Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid constraint expression

The following code example doesn't compile with Clang 15 or Clang trunk, in contrast to GCC 12.2 and MSVC 19.33. Is the contraint expression in the nested required clause invalid?

struct t {
    constexpr auto b() const noexcept
    { return true; }
};

template<typename T>
concept c = requires(T t) {
    requires t.b();
};

static_assert(c<t>);

The error message produced by Clang:

<source>:11:1: error: static assertion failed
static_assert(c<t>);
^             ~~~~
<source>:11:15: note: because 't' does not satisfy 'c'
static_assert(c<t>);
              ^
<source>:8:14: note: because 't.b()' would be invalid: constraint variable 't'
cannot be used in an evaluated context
    requires t.b();
             ^

Interestingly, the fault also becomes apparent with GCC when wrapping the evaluation of t.b() in a std::bool_constant. When changing the constraint expression as such:

template<typename T>
concept c = requires(T t) {
    requires std::bool_constant<t.b()>::value;
};

GCC will actually produce the following error, while MSVC is still fine with it:

<source>:15:38: error: template argument 1 is invalid
   15 |     requires std::bool_constant<t.b()>::value;
like image 536
303 Avatar asked Apr 03 '26 04:04

303


1 Answers

[expr.prim.req.general] (emphasis mine)

4 A requires-expression may introduce local parameters using a parameter-declaration-clause ([dcl.fct]). A local parameter of a requires-expression shall not have a default argument. Each name introduced by a local parameter is in scope from the point of its declaration until the closing brace of the requirement-body. These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining requirements. [...]

You are trying to use a non-existent object in (constant-)evaluation of an expression, it's not meant to work. Think of the parameters of compound requires expression as shorthand declval. You can use them in unevaluated contexts, examine the types and such, but not evaluate with them.

To be explicit

[expr.prim.req.nested]

2 A local parameter shall only appear as an unevaluated operand within the constraint-expression. [Example 2:

template<typename T> concept C = requires (T a) {
  requires sizeof(a) == 4;      // OK
  requires a == 0;              // error: evaluation of a constraint > variable
};

— end

So Clang is the only correct compiler out of the bunch.

like image 148
StoryTeller - Unslander Monica Avatar answered Apr 08 '26 06:04

StoryTeller - Unslander Monica