On Fri, 4 Apr 2025, Patrick Palka wrote: > On Thu, 3 Apr 2025, Jason Merrill wrote: > > > On 4/2/25 2:28 PM, Patrick Palka wrote: > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look > > > OK for trunk/14? > > > > OK for 14. > > > > For 15, what happens if we remove that error entirely? Do we still give > > other > > errors in that case? That seems to be the expectation of > > https://eel.is/c++draft/basic.scope.param#note-1 and I'd expect that in a > > constant-evaluated (and therefore evaluated) context we would complain about > > it not being constant. > > Indeed, it seems we do reliably error elsewhere if we remove that error, > e.g. for parse/parameter-declaration-2.C we instead emit give: > > error: size of array ‘p’ is not an integral constant-expression > > But regtesting revealed that error path is also used to disambiguate > vexing parses -- removing it causes us to now reject parse/ambig7.C: > > parse/ambig7.C:16:36: error: no matching function for call to > ‘Helper::Helper(int, <unresolved overloaded function type>)’ > > So I guess we can't remove it outright just yet.
Forgot to mention, removing the error is also unfortunately not sufficient to fix the related PR104255. For e.g. template<int> struct A; struct empty { }; constexpr int f(empty) { return 0; } auto g(empty e) -> A<f(e)>*; template<class T> auto h(T t) -> A<f(t)>*; int main() { g(empty{}); // now OK h(empty{}); // now ICE instead of error } the call to the (non-template) g is now accepted, but for the call to (template) h we now hit the cp_unevaluated_operand assert from the PARM_DECL case of tsubst_expr. > > > > > I think the current rule that corresponds to that error is > > https://eel.is/c++draft/basic.def.odr#10 -- odr-using a variable that isn't > > odr-usable. process_outer_var_ref/mark_use make that distinction for > > variables from an enclosing function, but I think for references outside of > > any function constant-evaluation should handle it. > > > > > -- >8 -- > > > > > > Here we wrongly reject the requires-expression requirement at parse time > > > due to the use of the constraint variable 't' within a template argument > > > (an evaluated context). Fix this simply by refining the "use of parameter > > > outside function body" code path to exclude constraint variables. > > > > > > PR c++/104255 tracks the same issue for function parameters, but fixing > > > that would be more involved, requiring changes to the PARM_DECL case of > > > tsubst_expr. > > > > > > PR c++/117849 > > > > > > gcc/cp/ChangeLog: > > > > > > * semantics.cc (finish_id_expression_1): Allow use of constraint > > > variable outside in an evaluated context. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/cpp2a/concepts-requires41.C: New test. > > > --- > > > gcc/cp/semantics.cc | 1 + > > > .../g++.dg/cpp2a/concepts-requires41.C | 23 +++++++++++++++++++ > > > 2 files changed, 24 insertions(+) > > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires41.C > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > index 7d8beb8833d..a10ef34383c 100644 > > > --- a/gcc/cp/semantics.cc > > > +++ b/gcc/cp/semantics.cc > > > @@ -4755,6 +4755,7 @@ finish_id_expression_1 (tree id_expression, > > > body, except inside an unevaluated context (i.e. decltype). */ > > > if (TREE_CODE (decl) == PARM_DECL > > > && DECL_CONTEXT (decl) == NULL_TREE > > > + && !CONSTRAINT_VAR_P (decl) > > > && !cp_unevaluated_operand > > > && !processing_contract_condition > > > && !processing_omp_trait_property_expr) > > > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires41.C > > > b/gcc/testsuite/g++.dg/cpp2a/concepts-requires41.C > > > new file mode 100644 > > > index 00000000000..840ed86c4ac > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires41.C > > > @@ -0,0 +1,23 @@ > > > +// PR c++/117849 > > > +// { dg-do compile { target c++20 } } > > > + > > > +template<int N> struct array { > > > + constexpr int size() const { return N; } > > > +}; > > > + > > > +struct vector { > > > + int _size = 3; > > > + constexpr int size() const { return _size; } > > > +}; > > > + > > > +template<int N> struct integral_constant { > > > + constexpr operator int() const { return N; } > > > +}; > > > + > > > +template<class T> > > > +concept StaticSize = requires (T& t) { > > > + typename integral_constant<t.size()>; > > > +}; > > > + > > > +static_assert(StaticSize<array<5>>); > > > +static_assert(!StaticSize<vector>); > > > >