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>);
> > 
> > 

Reply via email to