Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang] Instantiation of concept makes invalid expression valid. #132592

Open
SainoNamkho opened this issue Mar 23, 2025 · 3 comments
Open

[clang] Instantiation of concept makes invalid expression valid. #132592

SainoNamkho opened this issue Mar 23, 2025 · 3 comments
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts

Comments

@SainoNamkho
Copy link

SainoNamkho commented Mar 23, 2025

Clang accepts or rejects the code depending on whether a related concept is instantiated before.

Godbolt link

#include <concepts>

struct Var {};

template<class T>
constexpr Var var;

struct A {};

template<class T> requires std::same_as<A, T>
constexpr auto var<T> = 1;

template<class T> requires std::same_as<T*, A*>
constexpr auto var<T> = 2;

template<class T>
concept C1 = var<T> == 1;

template<class T>
concept C2 = var<T> == 2;

template<class T>
concept C = C1<T> || C2<T>;

#ifdef __clang__
// static_assert(var<A> == 1 || var<A> == 2);               // clang reports error here
auto magic = C1<A>;
static_assert(var<A> == 1 && var<A> == 2 && var<A> == 42);  // clang doesn't report error here
#endif

#ifdef _MSC_VER
    static_assert(var<A> == 1);                 // msvc selects the first specializatioin
    static_assert(C1<A> && !C2<A> && C<A>);
#else
    static_assert(!C1<A> && !C2<A> && !C<A>);   // concept-ids of unsatisfied constraints are false
#endif

template<class T>
struct B;

template<C1 T>
struct B<T> : std::true_type {};

template<std::same_as<A> T>
struct B<T> : std::false_type {};

static_assert(!B<A>::value);    // msvc doesn't treat unsatisfication of C1 as sfinae

Minimal example:

template<class>
constexpr auto x = false;

template<class T> requires true
constexpr auto x<T> = true;

template<class T> requires true && true
constexpr auto x<T> = true;

template<class T>
concept X = x<T>;
// static_assert(x<void>);     //error
static_assert(!X<void>);
static_assert(x<void> && !x<void> && **x<void>()[]);
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Mar 23, 2025
@SainoNamkho
Copy link
Author

SainoNamkho commented Mar 23, 2025

To make it look weirder:

template<class>
constexpr auto x = false;

template<class T> requires true
constexpr auto x<T> = true;

template<class T> requires true && true
constexpr auto x<T> = true;

template<class T>
concept X = x<T>;
static_assert(x<void> && !X<void>);     // error
static_assert(!X<void> && x<void>);     // compiles

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts and removed clang Clang issues not falling into any other category labels Mar 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 23, 2025

@llvm/issue-subscribers-clang-frontend

Author: None (SainoNamkho)

Clang accepts or rejects the code depending on whether a related concept is instantiated before.

Godbolt link

#include &lt;concepts&gt;

struct Var {};

template&lt;class T&gt;
constexpr Var var;

struct A {};

template&lt;class T&gt; requires std::same_as&lt;A, T&gt;
constexpr auto var&lt;T&gt; = 1;

template&lt;class T&gt; requires std::same_as&lt;T*, A*&gt;
constexpr auto var&lt;T&gt; = 2;

template&lt;class T&gt;
concept C1 = var&lt;T&gt; == 1;

template&lt;class T&gt;
concept C2 = var&lt;T&gt; == 2;

template&lt;class T&gt;
concept C = C1&lt;T&gt; || C2&lt;T&gt;;

#ifdef __clang__
// static_assert(var&lt;A&gt; == 1 || var&lt;A&gt; == 2);               // clang reports error here
auto magic = C1&lt;A&gt;;
static_assert(var&lt;A&gt; == 1 &amp;&amp; var&lt;A&gt; == 2 &amp;&amp; var&lt;A&gt; == 42);  // clang doesn't report error here
#endif

#ifdef _MSC_VER
    static_assert(var&lt;A&gt; == 1);                 // msvc selects the first specializatioin
    static_assert(C1&lt;A&gt; &amp;&amp; !C2&lt;A&gt; &amp;&amp; C&lt;A&gt;);
#else
    static_assert(!C1&lt;A&gt; &amp;&amp; !C2&lt;A&gt; &amp;&amp; !C&lt;A&gt;);   // concept-ids of unsatisfied constraints are false
#endif

template&lt;class T&gt;
struct B;

template&lt;C1 T&gt;
struct B&lt;T&gt; : std::true_type {};

template&lt;std::same_as&lt;A&gt; T&gt;
struct B&lt;T&gt; : std::false_type {};

static_assert(!B&lt;A&gt;::value);    // msvc doesn't treat unsatisfication of C1 as sfinae

Minimal example:

template&lt;class&gt;
constexpr auto x = false;

template&lt;class T&gt; requires true
constexpr auto x&lt;T&gt; = true;

template&lt;class T&gt; requires true &amp;&amp; true
constexpr auto x&lt;T&gt; = true;

template&lt;class T&gt;
concept X = x&lt;T&gt;;
// static_assert(x&lt;void&gt;);     //error
static_assert(!X&lt;void&gt;);
static_assert(x&lt;void&gt; &amp;&amp; !x&lt;void&gt; &amp;&amp; **x&lt;void&gt;()[]);

@shafik
Copy link
Collaborator

shafik commented Mar 25, 2025

clang is the only one that accepts the second one from the simplified example: https://godbolt.org/z/KGvrq3oxo and I don't think it should.

CC @cor3ntin how does this fare w/ your latest PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts
Projects
None yet
Development

No branches or pull requests

4 participants