Re: [PATCH] c++: optimize tsubst_template_decl for function templates

2023-09-18 Thread Patrick Palka via Gcc-patches
On Mon, Sep 18, 2023 at 9:36 AM Jason Merrill  wrote:
>
> On 9/18/23 08:58, Patrick Palka wrote:
> > On Sun, 17 Sep 2023, Jason Merrill wrote:
> >
> >> On 9/17/23 15:13, Patrick Palka wrote:
> >>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> >>> trunk?
> >>>
> >>> -- >8 --
> >>>
> >>> r14-2655-g92d1425ca78040 made instantiate_template avoid redundantly
> >>> performing a specialization lookup when instantiating a function or
> >>> alias template.  This patch applies the same optimization to
> >>> tsubst_template_decl when (partially) instantiating a function template,
> >>> which allows us to remove a check from register_specialization since
> >>> tsubst_function_decl no longer calls register_specialization for
> >>> a function template partial instantiation.
> >>>
> >>> gcc/cp/ChangeLog:
> >>>
> >>> * pt.cc (register_specialization): Remove now-unnecessary
> >>> early exit for FUNCTION_DECL partial instantiation.
> >>> (tsubst_template_decl): Pass use_spec_table=false to
> >>> tsubst_function_decl.  Set DECL_TI_ARGS of a non-lambda
> >>> FUNCTION_DECL specialization to the full set of arguments.
> >>> Simplify register_specialization call accordingly.
> >>>
> >>> gcc/testsuite/ChangeLog:
> >>>
> >>> * g++.dg/template/nontype12.C: Expect two instead of three
> >>> duplicate diagnostics for A::bar() specialization.
> >>> ---
> >>>gcc/cp/pt.cc  | 29 +++
> >>>gcc/testsuite/g++.dg/template/nontype12.C |  1 -
> >>>2 files changed, 9 insertions(+), 21 deletions(-)
> >>>
> >>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> >>> index c311a6b88f5..a0296a1ea16 100644
> >>> --- a/gcc/cp/pt.cc
> >>> +++ b/gcc/cp/pt.cc
> >>> @@ -1507,21 +1507,6 @@ register_specialization (tree spec, tree tmpl, tree
> >>> args, bool is_friend,
> >>>   || (TREE_CODE (tmpl) == FIELD_DECL
> >>>   && TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
> >>>-  if (TREE_CODE (spec) == FUNCTION_DECL
> >>> -  && uses_template_parms (DECL_TI_ARGS (spec)))
> >>> -/* This is the FUNCTION_DECL for a partial instantiation.  Don't
> >>> -   register it; we want the corresponding TEMPLATE_DECL instead.
> >>> -   We use `uses_template_parms (DECL_TI_ARGS (spec))' rather than
> >>> -   the more obvious `uses_template_parms (spec)' to avoid problems
> >>> -   with default function arguments.  In particular, given
> >>> -   something like this:
> >>> -
> >>> - template  void f(T t1, T t = T())
> >>> -
> >>> -   the default argument expression is not substituted for in an
> >>> -   instantiation unless and until it is actually needed.  */
> >>> -return spec;
> >>> -
> >>>  spec_entry elt;
> >>>  elt.tmpl = tmpl;
> >>>  elt.args = args;
> >>> @@ -14663,7 +14648,7 @@ tsubst_template_decl (tree t, tree args,
> >>> tsubst_flags_t complain,
> >>>  tree in_decl = t;
> >>>  tree spec;
> >>>  tree tmpl_args;
> >>> -  tree full_args;
> >>> +  tree full_args = NULL_TREE;
> >>>  tree r;
> >>>  hashval_t hash = 0;
> >>>@@ -14754,7 +14739,8 @@ tsubst_template_decl (tree t, tree args,
> >>> tsubst_flags_t complain,
> >>>  tree inner = decl;
> >>>  ++processing_template_decl;
> >>>  if (TREE_CODE (inner) == FUNCTION_DECL)
> >>> -inner = tsubst_function_decl (inner, args, complain, lambda_fntype);
> >>> +inner = tsubst_function_decl (inner, args, complain, lambda_fntype,
> >>> + /*use_spec_table=*/false);
> >>>  else
> >>>{
> >>>  if (TREE_CODE (inner) == TYPE_DECL && !TYPE_DECL_ALIAS_P (inner))
> >>> @@ -14792,6 +14778,11 @@ tsubst_template_decl (tree t, tree args,
> >>> tsubst_flags_t complain,
> >>>}
> >>>  else
> >>>{
> >>> +  if (TREE_CODE (inner) == FUNCTION_DECL)
> >>> +   /* Set DECL_TI_ARGS to the full set of template arguments, which
> >>> +  tsubst_function_decl didn't do due to use_spec_table=false.  */
> >>> +   DECL_TI_ARGS (inner) = full_args;
> >>> +
> >>>  DECL_TI_TEMPLATE (inner) = r;
> >>>  DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
> >>>}
> >>> @@ -14822,9 +14813,7 @@ tsubst_template_decl (tree t, tree args,
> >>> tsubst_flags_t complain,
> >>>if (TREE_CODE (decl) == FUNCTION_DECL && !lambda_fntype)
> >>>/* Record this non-type partial instantiation.  */
> >>> -register_specialization (r, t,
> >>> -DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
> >>> -false, hash);
> >>> +register_specialization (r, t, full_args, false, hash);
> >>>return r;
> >>>}
> >>> diff --git a/gcc/testsuite/g++.dg/template/nontype12.C
> >>> b/gcc/testsuite/g++.dg/template/nontype12.C
> >>> index 9a9c3ac1e66..e36a9f16f94 100644
> >>> --- a/gcc/testsuite/g++.dg/template/nontype12.C
> >>> +++ b/gcc/testsuite/g++.dg/template/nontype12.C
> >>> @@ -5,7 +5,6 @@ template struct A
> 

Re: [PATCH v2 2/2] c++: convert_to_void and volatile references

2023-09-18 Thread Patrick Palka via Gcc-patches
On Mon, 18 Sep 2023, Patrick Palka wrote:

> Jason pointed out that even implicit loads of volatile references need
> to undergo lvalue-to-rvalue conversion, but we currently emit a warning
> in this case and discard the load.  This patch changes this behavior so
> that we don't issue a warning, and preserve the load.
> 
> gcc/cp/ChangeLog:
> 
>   * cvt.cc (convert_to_void) : Remove warning
>   for an implicit load of a volatile reference.  Simplify as if
>   is_reference is false.  Check REFERENCE_REF_P in the test
>   guarding the -Wunused-value diagnostic.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/expr/discarded1a.C: No longer expect warning for
>   implicit load of a volatile reference.
>   * g++.old-deja/g++.bugs/900428_01.C: Likewise.
>   * g++.dg/expr/volatile2.C: New test.
> ---
>  gcc/cp/cvt.cc | 56 ++-
>  gcc/testsuite/g++.dg/expr/discarded1a.C   |  1 -
>  gcc/testsuite/g++.dg/expr/volatile2.C | 12 
>  .../g++.old-deja/g++.bugs/900428_01.C | 26 -
>  4 files changed, 30 insertions(+), 65 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/expr/volatile2.C
> 
> diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
> index 4424670356c..1cb6c1222c2 100644
> --- a/gcc/cp/cvt.cc
> +++ b/gcc/cp/cvt.cc
> @@ -1251,12 +1251,9 @@ convert_to_void (tree expr, impl_conv_void implicit, 
> tsubst_flags_t complain)
>{
>   tree type = TREE_TYPE (expr);
>   int is_volatile = TYPE_VOLATILE (type);
> - if (is_volatile)
> -   complete_type (type);
> - int is_complete = COMPLETE_TYPE_P (type);
>  
>   /* Can't load the value if we don't know the type.  */
> - if (is_volatile && !is_complete)
> + if (is_volatile && !COMPLETE_TYPE_P (complete_type (type)))
>{
>  if (complain & tf_warning)
> switch (implicit)
> @@ -1298,50 +1295,7 @@ convert_to_void (tree expr, impl_conv_void implicit, 
> tsubst_flags_t complain)
>   gcc_unreachable ();
>   }
>}
> - /* Don't load the value if this is an implicit dereference, or if
> -the type needs to be handled by ctors/dtors.  */
> - else if (is_volatile && is_reference)
> -  {
> -if (complain & tf_warning)
> -   switch (implicit)
> - {
> -   case ICV_CAST:
> - warning_at (loc, 0, "conversion to void will not access "
> - "object of type %qT", type);
> - break;
> -   case ICV_SECOND_OF_COND:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in second operand of "
> - "conditional expression", type);
> - break;
> -   case ICV_THIRD_OF_COND:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in third operand of "
> - "conditional expression", type);
> - break;
> -   case ICV_RIGHT_OF_COMMA:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in right operand of "
> - "comma operator", type);
> - break;
> -   case ICV_LEFT_OF_COMMA:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in left operand of comma "
> - "operator", type);
> - break;
> -   case ICV_STATEMENT:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in statement",  type);
> -  break;
> -   case ICV_THIRD_IN_FOR:
> - warning_at (loc, 0, "implicit dereference will not access "
> - "object of type %qT in for increment 
> expression",
> - type);
> - break;
> -   default:
> - gcc_unreachable ();
> - }
> -  }
> + /* Don't load the value if the type needs to be handled by cdtors.  */
>   else if (is_volatile && TREE_ADDRESSABLE (type))
> {
>   if (complain & tf_warning)
> @@ -1386,7 +1340,7 @@ convert_to_void (tree expr, impl_conv_void implicit, 
> tsubst_flags_t complain)
>   gcc_unreachable ();
>   }
> }
> - if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE 
> (type))
> + if (!is_volatile || !COMPLETE_TYPE_P (type))

... and the TREE_ADDRESSABLE test should not have been removed, consider
that fixed.  (The original patch doesn't have this mistake, I just
messed up splitting the patch into two.)

>

Re: [PATCH v2 1/2] c++: overeager type completion in convert_to_void [PR111419]

2023-09-18 Thread Patrick Palka via Gcc-patches
On Mon, 18 Sep 2023, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> -- >8 --
> 
> Here convert_to_void always completes the type of an indirection or
> id-expression, but according to [expr.context] an lvalue-to-rvalue
> conversion is applied to a discarded-value expression only if "the
> expression is a glvalue of volatile-qualified type".  This patch
> restricts convert_to_void's type completion to match.
> 
>   PR c++/111419
> 
> gcc/cp/ChangeLog:
> 
>   * cvt.cc (convert_to_void) : Only call
>   complete_type if the type is volatile.
>   : Only call complete_type if the type is volatile.
>   Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-requires36.C: New test.
>   * g++.dg/expr/discarded1.C: New test.
>   * g++.dg/expr/discarded1a.C: New test.
> ---
>  gcc/cp/cvt.cc   | 10 ++
>  .../g++.dg/cpp2a/concepts-requires36.C  | 16 
>  gcc/testsuite/g++.dg/expr/discarded1.C  | 15 +++
>  gcc/testsuite/g++.dg/expr/discarded1a.C | 17 +
>  4 files changed, 54 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
>  create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C
>  create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C
> 
> diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
> index c6b52f07050..4424670356c 100644
> --- a/gcc/cp/cvt.cc
> +++ b/gcc/cp/cvt.cc
> @@ -1250,9 +1250,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
> tsubst_flags_t complain)
>  case INDIRECT_REF:
>{
>   tree type = TREE_TYPE (expr);
> - int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));

Oops, this removal of is_reference should happen in the follow-up patch
instead, consider that fixed.

>   int is_volatile = TYPE_VOLATILE (type);
> - int is_complete = COMPLETE_TYPE_P (complete_type (type));
> + if (is_volatile)
> +   complete_type (type);
> + int is_complete = COMPLETE_TYPE_P (type);
>  
>   /* Can't load the value if we don't know the type.  */
>   if (is_volatile && !is_complete)
> @@ -1412,9 +1413,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
> tsubst_flags_t complain)
>{
>   /* External variables might be incomplete.  */
>   tree type = TREE_TYPE (expr);
> - int is_complete = COMPLETE_TYPE_P (complete_type (type));
>  
> - if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
> + if (TYPE_VOLATILE (type)
> + && !COMPLETE_TYPE_P (complete_type (type))
> + && (complain & tf_warning))
> switch (implicit)
>   {
> case ICV_CAST:
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
> new file mode 100644
> index 000..8d3a4fcd2aa
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
> @@ -0,0 +1,16 @@
> +// PR c++/111419
> +// { dg-do compile { target c++20 } }
> +
> +template
> +concept invocable = requires(F& f) { f(); };
> +
> +template
> +concept deref_invocable = requires(F& f) { *f(); };
> +
> +struct Incomplete;
> +
> +template
> +struct Holder { T t; };
> +
> +static_assert(invocable& ()>);
> +static_assert(deref_invocable* ()>);
> diff --git a/gcc/testsuite/g++.dg/expr/discarded1.C 
> b/gcc/testsuite/g++.dg/expr/discarded1.C
> new file mode 100644
> index 000..c0c22e9e95b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/expr/discarded1.C
> @@ -0,0 +1,15 @@
> +// PR c++/111419
> +
> +struct Incomplete;
> +
> +template struct Holder { T t; }; // { dg-bogus "incomplete" }
> +
> +extern Holder a;
> +extern Holder& b;
> +extern Holder* c;
> +
> +int main() {
> +  a;
> +  b;
> +  *c;
> +}
> diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C 
> b/gcc/testsuite/g++.dg/expr/discarded1a.C
> new file mode 100644
> index 000..1c4dff4553e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
> @@ -0,0 +1,17 @@
> +// A version of discarded1.C using volatile types.
> +// PR c++/111419
> +
> +struct Incomplete;
> +
> +template struct Holder { T t; }; // { dg-error "incomplete" }
> +
> +extern volatile Holder a;
> +extern volatile Holder& b;
> +extern volatile Holder* c;
> +
> +int main() {
> +  a; // { dg-message "required from here" }
> +  b; // { dg-message "required from here" }
> +  // { dg-warning "implicit dereference will not access object" "" { target 
> *-*-* } .-1 }
> +  *c; // { dg-message "required from here" }
> +}
> -- 
> 2.42.0.216.gbda494f404
> 
> 



[PATCH v2 2/2] c++: convert_to_void and volatile references

2023-09-18 Thread Patrick Palka via Gcc-patches
Jason pointed out that even implicit loads of volatile references need
to undergo lvalue-to-rvalue conversion, but we currently emit a warning
in this case and discard the load.  This patch changes this behavior so
that we don't issue a warning, and preserve the load.

gcc/cp/ChangeLog:

* cvt.cc (convert_to_void) : Remove warning
for an implicit load of a volatile reference.  Simplify as if
is_reference is false.  Check REFERENCE_REF_P in the test
guarding the -Wunused-value diagnostic.

gcc/testsuite/ChangeLog:

* g++.dg/expr/discarded1a.C: No longer expect warning for
implicit load of a volatile reference.
* g++.old-deja/g++.bugs/900428_01.C: Likewise.
* g++.dg/expr/volatile2.C: New test.
---
 gcc/cp/cvt.cc | 56 ++-
 gcc/testsuite/g++.dg/expr/discarded1a.C   |  1 -
 gcc/testsuite/g++.dg/expr/volatile2.C | 12 
 .../g++.old-deja/g++.bugs/900428_01.C | 26 -
 4 files changed, 30 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/expr/volatile2.C

diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index 4424670356c..1cb6c1222c2 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1251,12 +1251,9 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
   {
tree type = TREE_TYPE (expr);
int is_volatile = TYPE_VOLATILE (type);
-   if (is_volatile)
- complete_type (type);
-   int is_complete = COMPLETE_TYPE_P (type);
 
/* Can't load the value if we don't know the type.  */
-   if (is_volatile && !is_complete)
+   if (is_volatile && !COMPLETE_TYPE_P (complete_type (type)))
   {
 if (complain & tf_warning)
  switch (implicit)
@@ -1298,50 +1295,7 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
gcc_unreachable ();
}
   }
-   /* Don't load the value if this is an implicit dereference, or if
-  the type needs to be handled by ctors/dtors.  */
-   else if (is_volatile && is_reference)
-  {
-if (complain & tf_warning)
- switch (implicit)
-   {
- case ICV_CAST:
-   warning_at (loc, 0, "conversion to void will not access "
-   "object of type %qT", type);
-   break;
- case ICV_SECOND_OF_COND:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in second operand of "
-   "conditional expression", type);
-   break;
- case ICV_THIRD_OF_COND:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in third operand of "
-   "conditional expression", type);
-   break;
- case ICV_RIGHT_OF_COMMA:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in right operand of "
-   "comma operator", type);
-   break;
- case ICV_LEFT_OF_COMMA:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in left operand of comma "
-   "operator", type);
-   break;
- case ICV_STATEMENT:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in statement",  type);
-break;
- case ICV_THIRD_IN_FOR:
-   warning_at (loc, 0, "implicit dereference will not access "
-   "object of type %qT in for increment 
expression",
-   type);
-   break;
- default:
-   gcc_unreachable ();
-   }
-  }
+   /* Don't load the value if the type needs to be handled by cdtors.  */
else if (is_volatile && TREE_ADDRESSABLE (type))
  {
if (complain & tf_warning)
@@ -1386,7 +1340,7 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
gcc_unreachable ();
}
  }
-   if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE 
(type))
+   if (!is_volatile || !COMPLETE_TYPE_P (type))
   {
 /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
operation is stripped off. Note that we don't warn about
@@ -1397,8 +1351,8 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
 if (warn_unused_value
 

Re: [PATCH] c++: overeager type completion in convert_to_void [PR111419]

2023-09-18 Thread Patrick Palka via Gcc-patches
On Mon, 18 Sep 2023, Patrick Palka wrote:

> On Sun, 17 Sep 2023, Jason Merrill wrote:
> 
> > On 9/16/23 17:41, Patrick Palka wrote:
> > > On Sat, 16 Sep 2023, Jason Merrill wrote:
> > > 
> > > > On 9/15/23 12:03, Patrick Palka wrote:
> > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK 
> > > > > for
> > > > > trunk?
> > > > > 
> > > > > -- >8 --
> > > > > 
> > > > > Here convert_to_void always completes the type of an INDIRECT_REF or
> > > > > VAR_DECL expression, but according to [expr.context] an 
> > > > > lvalue-to-rvalue
> > > > > conversion is applied to a discarded-value expression only if "the
> > > > > expression is a glvalue of volatile-qualified type".  This patch
> > > > > restricts
> > > > > convert_to_void's type completion accordingly.
> > > > > 
> > > > >   PR c++/111419
> > > > > 
> > > > > gcc/cp/ChangeLog:
> > > > > 
> > > > >   * cvt.cc (convert_to_void) : Only call
> > > > >   complete_type if the type is volatile and the INDIRECT_REF
> > > > >   isn't an implicit one.
> > > > 
> > > > Hmm, what does implicit have to do with it?  The expression forms listed
> > > > in
> > > > https://eel.is/c++draft/expr.context#2 include "id-expression"...
> > > 
> > > When there's an implicit INDIRECT_REF, I reckoned the type of the
> > > id-expression is really a reference type, which can't be cv-qualified?
> > 
> > A name can have reference type, but its use as an expression doesn't:
> > https://eel.is/c++draft/expr.type#1.sentence-1
> 
> Ah, makes sense..
> 
> > 
> > > > > diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > > b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > > new file mode 100644
> > > > > index 000..5516ff46fe9
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > > @@ -0,0 +1,16 @@
> > > > > +// PR c++/111419
> > > > > +
> > > > > +struct Incomplete;
> > > > > +
> > > > > +template struct Holder { T t; }; // { dg-error
> > > > > "incomplete" }
> > > > > +
> > > > > +extern volatile Holder a;
> > > > > +extern volatile Holder& b;
> > > > > +extern volatile Holder* c;
> > > > > +
> > > > > +int main() {
> > > > > +  a; // { dg-message "required from here" }
> > > > > +  b; // { dg-warning "implicit dereference will not access object" }
> > > > > + // { dg-bogus "required from here" "" { target *-*-* } .-1 }
> > > > 
> > > > ...so it seems to me this line should get the lvalue-rvalue conversion
> > > > (and
> > > > not the warning about no access).
> 
> Sounds good, like so?  I also added a test to verify such loads don't
> get discarded in the generated code.

On second thought, it seems better to split this into two patches, one
that correctly restricts type completion, and the next that makes us
correctly handle warning/code generation of volatile references.
Patch series incoming...

> 
> -- >8 --
> 
> Subject: [PATCH] c++: overeager type completion in convert_to_void [PR111419]
> 
> Here convert_to_void always completes the type of an indirection or
> id-expression, but according to [expr.context] an lvalue-to-rvalue
> conversion is applied to a discarded-value expression only if "the
> expression is a glvalue of volatile-qualified type".  This patch
> restricts convert_to_void's type completion accordingly.
> 
> Jason pointed out that implicit loads of volatile references also need
> to undergo lvalue-to-rvalue conversion, but we currently emit a warning
> in this case and discard the load.  This patch also changes this behavior
> so that we preserve the load and don't issue a warning.
> 
>   PR c++/111419
> 
> gcc/cp/ChangeLog:
> 
>   * cvt.cc (convert_to_void) : Only call
>   complete_type if the type is volatile.  Remove warning for
>   implicit indirection of a volatile reference.  Simplify as if
>   is_reference=false.  Check REFERENCE_REF_P in the -Wunused-value
>   branch.
>   : Only call complete_type if the type is volatile.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-requires36.C: New test.
>   * g++.dg/expr/discarded1.C: New test.
>   * g++.dg/expr/discarded1a.C: New test.
>   * g++.dg/expr/volatile2.C: New test.
>   * g++.old-deja/g++.bugs/900428_01.C: No longer expect
>   warnings for implicit loads of volatile references.
> ---
>  gcc/cp/cvt.cc | 60 +++
>  .../g++.dg/cpp2a/concepts-requires36.C| 16 +
>  gcc/testsuite/g++.dg/expr/discarded1.C| 15 +
>  gcc/testsuite/g++.dg/expr/discarded1a.C   | 16 +
>  gcc/testsuite/g++.dg/expr/volatile2.C | 11 
>  .../g++.old-deja/g++.bugs/900428_01.C | 26 
>  6 files changed, 79 insertions(+), 65 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
>  create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C
>  create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C
>  create mode 100644 

[PATCH v2 1/2] c++: overeager type completion in convert_to_void [PR111419]

2023-09-18 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here convert_to_void always completes the type of an indirection or
id-expression, but according to [expr.context] an lvalue-to-rvalue
conversion is applied to a discarded-value expression only if "the
expression is a glvalue of volatile-qualified type".  This patch
restricts convert_to_void's type completion to match.

PR c++/111419

gcc/cp/ChangeLog:

* cvt.cc (convert_to_void) : Only call
complete_type if the type is volatile.
: Only call complete_type if the type is volatile.
Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires36.C: New test.
* g++.dg/expr/discarded1.C: New test.
* g++.dg/expr/discarded1a.C: New test.
---
 gcc/cp/cvt.cc   | 10 ++
 .../g++.dg/cpp2a/concepts-requires36.C  | 16 
 gcc/testsuite/g++.dg/expr/discarded1.C  | 15 +++
 gcc/testsuite/g++.dg/expr/discarded1a.C | 17 +
 4 files changed, 54 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C

diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index c6b52f07050..4424670356c 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1250,9 +1250,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
 case INDIRECT_REF:
   {
tree type = TREE_TYPE (expr);
-   int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
int is_volatile = TYPE_VOLATILE (type);
-   int is_complete = COMPLETE_TYPE_P (complete_type (type));
+   if (is_volatile)
+ complete_type (type);
+   int is_complete = COMPLETE_TYPE_P (type);
 
/* Can't load the value if we don't know the type.  */
if (is_volatile && !is_complete)
@@ -1412,9 +1413,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
   {
/* External variables might be incomplete.  */
tree type = TREE_TYPE (expr);
-   int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
-   if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
+   if (TYPE_VOLATILE (type)
+   && !COMPLETE_TYPE_P (complete_type (type))
+   && (complain & tf_warning))
  switch (implicit)
{
  case ICV_CAST:
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
new file mode 100644
index 000..8d3a4fcd2aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
@@ -0,0 +1,16 @@
+// PR c++/111419
+// { dg-do compile { target c++20 } }
+
+template
+concept invocable = requires(F& f) { f(); };
+
+template
+concept deref_invocable = requires(F& f) { *f(); };
+
+struct Incomplete;
+
+template
+struct Holder { T t; };
+
+static_assert(invocable& ()>);
+static_assert(deref_invocable* ()>);
diff --git a/gcc/testsuite/g++.dg/expr/discarded1.C 
b/gcc/testsuite/g++.dg/expr/discarded1.C
new file mode 100644
index 000..c0c22e9e95b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/discarded1.C
@@ -0,0 +1,15 @@
+// PR c++/111419
+
+struct Incomplete;
+
+template struct Holder { T t; }; // { dg-bogus "incomplete" }
+
+extern Holder a;
+extern Holder& b;
+extern Holder* c;
+
+int main() {
+  a;
+  b;
+  *c;
+}
diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C 
b/gcc/testsuite/g++.dg/expr/discarded1a.C
new file mode 100644
index 000..1c4dff4553e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
@@ -0,0 +1,17 @@
+// A version of discarded1.C using volatile types.
+// PR c++/111419
+
+struct Incomplete;
+
+template struct Holder { T t; }; // { dg-error "incomplete" }
+
+extern volatile Holder a;
+extern volatile Holder& b;
+extern volatile Holder* c;
+
+int main() {
+  a; // { dg-message "required from here" }
+  b; // { dg-message "required from here" }
+  // { dg-warning "implicit dereference will not access object" "" { target 
*-*-* } .-1 }
+  *c; // { dg-message "required from here" }
+}
-- 
2.42.0.216.gbda494f404



Re: [PATCH] c++: overeager type completion in convert_to_void [PR111419]

2023-09-18 Thread Patrick Palka via Gcc-patches
On Sun, 17 Sep 2023, Jason Merrill wrote:

> On 9/16/23 17:41, Patrick Palka wrote:
> > On Sat, 16 Sep 2023, Jason Merrill wrote:
> > 
> > > On 9/15/23 12:03, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > > trunk?
> > > > 
> > > > -- >8 --
> > > > 
> > > > Here convert_to_void always completes the type of an INDIRECT_REF or
> > > > VAR_DECL expression, but according to [expr.context] an lvalue-to-rvalue
> > > > conversion is applied to a discarded-value expression only if "the
> > > > expression is a glvalue of volatile-qualified type".  This patch
> > > > restricts
> > > > convert_to_void's type completion accordingly.
> > > > 
> > > > PR c++/111419
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * cvt.cc (convert_to_void) : Only call
> > > > complete_type if the type is volatile and the INDIRECT_REF
> > > > isn't an implicit one.
> > > 
> > > Hmm, what does implicit have to do with it?  The expression forms listed
> > > in
> > > https://eel.is/c++draft/expr.context#2 include "id-expression"...
> > 
> > When there's an implicit INDIRECT_REF, I reckoned the type of the
> > id-expression is really a reference type, which can't be cv-qualified?
> 
> A name can have reference type, but its use as an expression doesn't:
> https://eel.is/c++draft/expr.type#1.sentence-1

Ah, makes sense..

> 
> > > > diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > new file mode 100644
> > > > index 000..5516ff46fe9
> > > > --- /dev/null
> > > > +++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > > > @@ -0,0 +1,16 @@
> > > > +// PR c++/111419
> > > > +
> > > > +struct Incomplete;
> > > > +
> > > > +template struct Holder { T t; }; // { dg-error
> > > > "incomplete" }
> > > > +
> > > > +extern volatile Holder a;
> > > > +extern volatile Holder& b;
> > > > +extern volatile Holder* c;
> > > > +
> > > > +int main() {
> > > > +  a; // { dg-message "required from here" }
> > > > +  b; // { dg-warning "implicit dereference will not access object" }
> > > > + // { dg-bogus "required from here" "" { target *-*-* } .-1 }
> > > 
> > > ...so it seems to me this line should get the lvalue-rvalue conversion
> > > (and
> > > not the warning about no access).

Sounds good, like so?  I also added a test to verify such loads don't
get discarded in the generated code.

-- >8 --

Subject: [PATCH] c++: overeager type completion in convert_to_void [PR111419]

Here convert_to_void always completes the type of an indirection or
id-expression, but according to [expr.context] an lvalue-to-rvalue
conversion is applied to a discarded-value expression only if "the
expression is a glvalue of volatile-qualified type".  This patch
restricts convert_to_void's type completion accordingly.

Jason pointed out that implicit loads of volatile references also need
to undergo lvalue-to-rvalue conversion, but we currently emit a warning
in this case and discard the load.  This patch also changes this behavior
so that we preserve the load and don't issue a warning.

PR c++/111419

gcc/cp/ChangeLog:

* cvt.cc (convert_to_void) : Only call
complete_type if the type is volatile.  Remove warning for
implicit indirection of a volatile reference.  Simplify as if
is_reference=false.  Check REFERENCE_REF_P in the -Wunused-value
branch.
: Only call complete_type if the type is volatile.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires36.C: New test.
* g++.dg/expr/discarded1.C: New test.
* g++.dg/expr/discarded1a.C: New test.
* g++.dg/expr/volatile2.C: New test.
* g++.old-deja/g++.bugs/900428_01.C: No longer expect
warnings for implicit loads of volatile references.
---
 gcc/cp/cvt.cc | 60 +++
 .../g++.dg/cpp2a/concepts-requires36.C| 16 +
 gcc/testsuite/g++.dg/expr/discarded1.C| 15 +
 gcc/testsuite/g++.dg/expr/discarded1a.C   | 16 +
 gcc/testsuite/g++.dg/expr/volatile2.C | 11 
 .../g++.old-deja/g++.bugs/900428_01.C | 26 
 6 files changed, 79 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C
 create mode 100644 gcc/testsuite/g++.dg/expr/volatile2.C

diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index c6b52f07050..7e413f87334 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1250,12 +1250,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
 case INDIRECT_REF:
   {
tree type = TREE_TYPE (expr);
-   int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
int is_volatile = TYPE_VOLATILE (type);
-   int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
  

Re: [PATCH] c++: non-dependent assignment checking [PR63198, PR18474]

2023-09-18 Thread Patrick Palka via Gcc-patches
On Sun, 17 Sep 2023, Jason Merrill wrote:

> On 9/17/23 14:51, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  Patch generatde with -w to avoid noisy whitespace changes.
> > 
> > -- >8 --
> > 
> > This patch makes us recognize and check non-dependent simple assigments
> > ahead of time, like we already do for compound assignments.  This means
> > the templated representation of such assignments will now usually have
> > an implicit INDIRECT_REF (due to the reference return type), which the
> > -Wparentheses code needs to handle.  As a drive-by improvement, this
> > patch also makes maybe_convert_cond issue -Wparentheses warnings ahead
> > of time.
> > 
> > This revealed some libstdc++ tests were attempting to modify a data
> > member from a uninstantiated const member function; naively fixed by
> > making the data member mutable.
> > 
> > PR c++/63198
> > PR c++/18474
> > 
> > gcc/cp/ChangeLog:
> > 
> > * semantics.cc (maybe_convert_cond): Look through implicit
> > INDIRECT_REF when deciding whether to issue a -Wparentheses
> > warning, and consider templated assignment expressions as well.
> > (finish_parenthesized_expr): Look through implicit INDIRECT_REF
> > when suppressing -Wparentheses warning.
> > * typeck.cc (build_x_modify_expr): Check simple assignments
> > ahead time too, not just compound assignments.  Give the second
> > operand of MODOP_EXPR a non-null type so that it's not considered
> > always instantiation-dependent.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp0x/static_assert15.C: Expect diagnostic for
> > non-constant static_assert condition.
> > * g++.dg/expr/unary2.C: Remove xfails.
> > * g++.dg/template/init7.C: Make initializer type-dependent to
> > preserve intent of test.
> > * g++.dg/template/recurse3.C: Likewise for the erroneous
> > statement.
> > * g++.dg/template/non-dependent26.C: New test.
> > * g++.dg/warn/Wparentheses-32.C: New test.
> > 
> > libstdc++/ChangeLog:
> > 
> > * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc:
> > Make seed_seq::called member mutable.
> > *
> > testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc:
> > Likewise.
> > *
> > testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc
> > Likewise.
> > *
> > testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc:
> > Likewise.
> > * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc:
> > Likewise.
> > *
> > testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc:
> > Likewise.
> > *
> > testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc
> > Likewise.
> > ---
> >   gcc/cp/semantics.cc   | 17 +++
> >   gcc/cp/typeck.cc  | 23 +++
> >   gcc/testsuite/g++.dg/cpp0x/static_assert15.C  |  2 +-
> >   gcc/testsuite/g++.dg/expr/unary2.C|  8 ++
> >   gcc/testsuite/g++.dg/template/init7.C |  2 +-
> >   .../g++.dg/template/non-dependent26.C | 25 +
> >   gcc/testsuite/g++.dg/template/recurse3.C  |  8 +++---
> >   gcc/testsuite/g++.dg/warn/Wparentheses-32.C   | 28 +++
> >   .../discard_block_engine/cons/seed_seq2.cc|  2 +-
> >   .../independent_bits_engine/cons/seed_seq2.cc |  2 +-
> >   .../cons/seed_seq2.cc |  2 +-
> >   .../mersenne_twister_engine/cons/seed_seq2.cc |  2 +-
> >   .../shuffle_order_engine/cons/seed_seq2.cc|  2 +-
> >   .../cons/seed_seq2.cc |  2 +-
> >   .../cons/seed_seq2.cc |  2 +-
> >   15 files changed, 91 insertions(+), 36 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C
> >   create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C
> > 
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 0f7f4e87ae4..b57c1ac868b 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> > index 459739d5866..74f5fced060 100644
> > --- a/gcc/cp/typeck.cc
> > +++ b/gcc/cp/typeck.cc
> > @@ -9739,15 +9739,15 @@ build_x_modify_expr (location_t loc, tree lhs, enum
> > tree_code modifycode,
> > rhs = build_non_dependent_expr (rhs);
> >   }
> >   -  if (modifycode != NOP_EXPR)
> > -{
> > -  tree op = build_nt (modifycode, NULL_TREE, NULL_TREE);
> > -  tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
> > +  tree rval;
> > +  if (modifycode == NOP_EXPR)
> > +rval = cp_build_modify_expr (loc, lhs, modifycode, rhs, complain);
> > +  else
> > +rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
> >  lhs, rhs, op, lookups, , complain);
> > -  if (rval)
> > -   {
> > if (rval == 

Re: [PATCH] c++: optimize tsubst_template_decl for function templates

2023-09-18 Thread Patrick Palka via Gcc-patches
On Sun, 17 Sep 2023, Jason Merrill wrote:

> On 9/17/23 15:13, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > r14-2655-g92d1425ca78040 made instantiate_template avoid redundantly
> > performing a specialization lookup when instantiating a function or
> > alias template.  This patch applies the same optimization to
> > tsubst_template_decl when (partially) instantiating a function template,
> > which allows us to remove a check from register_specialization since
> > tsubst_function_decl no longer calls register_specialization for
> > a function template partial instantiation.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (register_specialization): Remove now-unnecessary
> > early exit for FUNCTION_DECL partial instantiation.
> > (tsubst_template_decl): Pass use_spec_table=false to
> > tsubst_function_decl.  Set DECL_TI_ARGS of a non-lambda
> > FUNCTION_DECL specialization to the full set of arguments.
> > Simplify register_specialization call accordingly.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/nontype12.C: Expect two instead of three
> > duplicate diagnostics for A::bar() specialization.
> > ---
> >   gcc/cp/pt.cc  | 29 +++
> >   gcc/testsuite/g++.dg/template/nontype12.C |  1 -
> >   2 files changed, 9 insertions(+), 21 deletions(-)
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index c311a6b88f5..a0296a1ea16 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -1507,21 +1507,6 @@ register_specialization (tree spec, tree tmpl, tree
> > args, bool is_friend,
> >   || (TREE_CODE (tmpl) == FIELD_DECL
> >   && TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
> >   -  if (TREE_CODE (spec) == FUNCTION_DECL
> > -  && uses_template_parms (DECL_TI_ARGS (spec)))
> > -/* This is the FUNCTION_DECL for a partial instantiation.  Don't
> > -   register it; we want the corresponding TEMPLATE_DECL instead.
> > -   We use `uses_template_parms (DECL_TI_ARGS (spec))' rather than
> > -   the more obvious `uses_template_parms (spec)' to avoid problems
> > -   with default function arguments.  In particular, given
> > -   something like this:
> > -
> > - template  void f(T t1, T t = T())
> > -
> > -   the default argument expression is not substituted for in an
> > -   instantiation unless and until it is actually needed.  */
> > -return spec;
> > -
> > spec_entry elt;
> > elt.tmpl = tmpl;
> > elt.args = args;
> > @@ -14663,7 +14648,7 @@ tsubst_template_decl (tree t, tree args,
> > tsubst_flags_t complain,
> > tree in_decl = t;
> > tree spec;
> > tree tmpl_args;
> > -  tree full_args;
> > +  tree full_args = NULL_TREE;
> > tree r;
> > hashval_t hash = 0;
> >   @@ -14754,7 +14739,8 @@ tsubst_template_decl (tree t, tree args,
> > tsubst_flags_t complain,
> > tree inner = decl;
> > ++processing_template_decl;
> > if (TREE_CODE (inner) == FUNCTION_DECL)
> > -inner = tsubst_function_decl (inner, args, complain, lambda_fntype);
> > +inner = tsubst_function_decl (inner, args, complain, lambda_fntype,
> > + /*use_spec_table=*/false);
> > else
> >   {
> > if (TREE_CODE (inner) == TYPE_DECL && !TYPE_DECL_ALIAS_P (inner))
> > @@ -14792,6 +14778,11 @@ tsubst_template_decl (tree t, tree args,
> > tsubst_flags_t complain,
> >   }
> > else
> >   {
> > +  if (TREE_CODE (inner) == FUNCTION_DECL)
> > +   /* Set DECL_TI_ARGS to the full set of template arguments, which
> > +  tsubst_function_decl didn't do due to use_spec_table=false.  */
> > +   DECL_TI_ARGS (inner) = full_args;
> > +
> > DECL_TI_TEMPLATE (inner) = r;
> > DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
> >   }
> > @@ -14822,9 +14813,7 @@ tsubst_template_decl (tree t, tree args,
> > tsubst_flags_t complain,
> >   if (TREE_CODE (decl) == FUNCTION_DECL && !lambda_fntype)
> >   /* Record this non-type partial instantiation.  */
> > -register_specialization (r, t,
> > -DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
> > -false, hash);
> > +register_specialization (r, t, full_args, false, hash);
> >   return r;
> >   }
> > diff --git a/gcc/testsuite/g++.dg/template/nontype12.C
> > b/gcc/testsuite/g++.dg/template/nontype12.C
> > index 9a9c3ac1e66..e36a9f16f94 100644
> > --- a/gcc/testsuite/g++.dg/template/nontype12.C
> > +++ b/gcc/testsuite/g++.dg/template/nontype12.C
> > @@ -5,7 +5,6 @@ template struct A
> >   {
> > template int foo();// { dg-error "double" ""
> > { target c++17_down } }
> > template class> int bar();// { dg-bogus
> > {double[^\n]*\n[^\n]*C:7:[^\n]*double} "" { xfail c++17_down } }
> > -  // { dg-error "double" "" { target c++17_down } .-1 }
> 
> Hmm, I thought this line was to check 

[PATCH] c++: optimize tsubst_template_decl for function templates

2023-09-17 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

r14-2655-g92d1425ca78040 made instantiate_template avoid redundantly
performing a specialization lookup when instantiating a function or
alias template.  This patch applies the same optimization to
tsubst_template_decl when (partially) instantiating a function template,
which allows us to remove a check from register_specialization since
tsubst_function_decl no longer calls register_specialization for
a function template partial instantiation.

gcc/cp/ChangeLog:

* pt.cc (register_specialization): Remove now-unnecessary
early exit for FUNCTION_DECL partial instantiation.
(tsubst_template_decl): Pass use_spec_table=false to
tsubst_function_decl.  Set DECL_TI_ARGS of a non-lambda
FUNCTION_DECL specialization to the full set of arguments.
Simplify register_specialization call accordingly.

gcc/testsuite/ChangeLog:

* g++.dg/template/nontype12.C: Expect two instead of three
duplicate diagnostics for A::bar() specialization.
---
 gcc/cp/pt.cc  | 29 +++
 gcc/testsuite/g++.dg/template/nontype12.C |  1 -
 2 files changed, 9 insertions(+), 21 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c311a6b88f5..a0296a1ea16 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1507,21 +1507,6 @@ register_specialization (tree spec, tree tmpl, tree 
args, bool is_friend,
  || (TREE_CODE (tmpl) == FIELD_DECL
  && TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
 
-  if (TREE_CODE (spec) == FUNCTION_DECL
-  && uses_template_parms (DECL_TI_ARGS (spec)))
-/* This is the FUNCTION_DECL for a partial instantiation.  Don't
-   register it; we want the corresponding TEMPLATE_DECL instead.
-   We use `uses_template_parms (DECL_TI_ARGS (spec))' rather than
-   the more obvious `uses_template_parms (spec)' to avoid problems
-   with default function arguments.  In particular, given
-   something like this:
-
- template  void f(T t1, T t = T())
-
-   the default argument expression is not substituted for in an
-   instantiation unless and until it is actually needed.  */
-return spec;
-
   spec_entry elt;
   elt.tmpl = tmpl;
   elt.args = args;
@@ -14663,7 +14648,7 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t 
complain,
   tree in_decl = t;
   tree spec;
   tree tmpl_args;
-  tree full_args;
+  tree full_args = NULL_TREE;
   tree r;
   hashval_t hash = 0;
 
@@ -14754,7 +14739,8 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t 
complain,
   tree inner = decl;
   ++processing_template_decl;
   if (TREE_CODE (inner) == FUNCTION_DECL)
-inner = tsubst_function_decl (inner, args, complain, lambda_fntype);
+inner = tsubst_function_decl (inner, args, complain, lambda_fntype,
+ /*use_spec_table=*/false);
   else
 {
   if (TREE_CODE (inner) == TYPE_DECL && !TYPE_DECL_ALIAS_P (inner))
@@ -14792,6 +14778,11 @@ tsubst_template_decl (tree t, tree args, 
tsubst_flags_t complain,
 }
   else
 {
+  if (TREE_CODE (inner) == FUNCTION_DECL)
+   /* Set DECL_TI_ARGS to the full set of template arguments, which
+  tsubst_function_decl didn't do due to use_spec_table=false.  */
+   DECL_TI_ARGS (inner) = full_args;
+
   DECL_TI_TEMPLATE (inner) = r;
   DECL_TI_ARGS (r) = DECL_TI_ARGS (inner);
 }
@@ -14822,9 +14813,7 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t 
complain,
 
   if (TREE_CODE (decl) == FUNCTION_DECL && !lambda_fntype)
 /* Record this non-type partial instantiation.  */
-register_specialization (r, t,
-DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
-false, hash);
+register_specialization (r, t, full_args, false, hash);
 
   return r;
 }
diff --git a/gcc/testsuite/g++.dg/template/nontype12.C 
b/gcc/testsuite/g++.dg/template/nontype12.C
index 9a9c3ac1e66..e36a9f16f94 100644
--- a/gcc/testsuite/g++.dg/template/nontype12.C
+++ b/gcc/testsuite/g++.dg/template/nontype12.C
@@ -5,7 +5,6 @@ template struct A
 {
   template int foo();// { dg-error "double" "" { 
target c++17_down } }
   template class> int bar();// { dg-bogus 
{double[^\n]*\n[^\n]*C:7:[^\n]*double} "" { xfail c++17_down } }
-  // { dg-error "double" "" { target c++17_down } .-1 }
   template struct X; // { dg-error "double" "" { 
target c++17_down } }
 };
 
-- 
2.42.0.216.gbda494f404



[PATCH] c++: non-dependent assignment checking [PR63198, PR18474]

2023-09-17 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Patch generatde with -w to avoid noisy whitespace changes.

-- >8 --

This patch makes us recognize and check non-dependent simple assigments
ahead of time, like we already do for compound assignments.  This means
the templated representation of such assignments will now usually have
an implicit INDIRECT_REF (due to the reference return type), which the
-Wparentheses code needs to handle.  As a drive-by improvement, this
patch also makes maybe_convert_cond issue -Wparentheses warnings ahead
of time.

This revealed some libstdc++ tests were attempting to modify a data
member from a uninstantiated const member function; naively fixed by
making the data member mutable.

PR c++/63198
PR c++/18474

gcc/cp/ChangeLog:

* semantics.cc (maybe_convert_cond): Look through implicit
INDIRECT_REF when deciding whether to issue a -Wparentheses
warning, and consider templated assignment expressions as well.
(finish_parenthesized_expr): Look through implicit INDIRECT_REF
when suppressing -Wparentheses warning.
* typeck.cc (build_x_modify_expr): Check simple assignments
ahead time too, not just compound assignments.  Give the second
operand of MODOP_EXPR a non-null type so that it's not considered
always instantiation-dependent.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/static_assert15.C: Expect diagnostic for
non-constant static_assert condition.
* g++.dg/expr/unary2.C: Remove xfails.
* g++.dg/template/init7.C: Make initializer type-dependent to
preserve intent of test.
* g++.dg/template/recurse3.C: Likewise for the erroneous
statement.
* g++.dg/template/non-dependent26.C: New test.
* g++.dg/warn/Wparentheses-32.C: New test.

libstdc++/ChangeLog:

* testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc:
Make seed_seq::called member mutable.
* 
testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc:
Likewise.
* 
testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc
Likewise.
* 
testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc:
Likewise.
* testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc:
Likewise.
* 
testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc:
Likewise.
* 
testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc
Likewise.
---
 gcc/cp/semantics.cc   | 17 +++
 gcc/cp/typeck.cc  | 23 +++
 gcc/testsuite/g++.dg/cpp0x/static_assert15.C  |  2 +-
 gcc/testsuite/g++.dg/expr/unary2.C|  8 ++
 gcc/testsuite/g++.dg/template/init7.C |  2 +-
 .../g++.dg/template/non-dependent26.C | 25 +
 gcc/testsuite/g++.dg/template/recurse3.C  |  8 +++---
 gcc/testsuite/g++.dg/warn/Wparentheses-32.C   | 28 +++
 .../discard_block_engine/cons/seed_seq2.cc|  2 +-
 .../independent_bits_engine/cons/seed_seq2.cc |  2 +-
 .../cons/seed_seq2.cc |  2 +-
 .../mersenne_twister_engine/cons/seed_seq2.cc |  2 +-
 .../shuffle_order_engine/cons/seed_seq2.cc|  2 +-
 .../cons/seed_seq2.cc |  2 +-
 .../cons/seed_seq2.cc |  2 +-
 15 files changed, 91 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/non-dependent26.C
 create mode 100644 gcc/testsuite/g++.dg/warn/Wparentheses-32.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..b57c1ac868b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -881,13 +881,17 @@ maybe_convert_cond (tree cond)
   /* Do the conversion.  */
   cond = convert_from_reference (cond);
 
-  if ((TREE_CODE (cond) == MODIFY_EXPR || is_assignment_op_expr_p (cond))
+  tree inner = REFERENCE_REF_P (cond) ? TREE_OPERAND (cond, 0) : cond;
+  if ((TREE_CODE (inner) == MODIFY_EXPR
+   || (TREE_CODE (inner) == MODOP_EXPR
+  && TREE_CODE (TREE_OPERAND (inner, 1)) == NOP_EXPR)
+   || is_assignment_op_expr_p (inner))
   && warn_parentheses
-  && !warning_suppressed_p (cond, OPT_Wparentheses)
-  && warning_at (cp_expr_loc_or_input_loc (cond),
+  && !warning_suppressed_p (inner, OPT_Wparentheses)
+  && warning_at (cp_expr_loc_or_input_loc (inner),
 OPT_Wparentheses, "suggest parentheses around "
   "assignment used as truth value"))
-suppress_warning (cond, OPT_Wparentheses);
+suppress_warning (inner, OPT_Wparentheses);
 
   return condition_conversion (cond);
 }
@@ -2155,8 +2159,11 @@ cp_expr
 finish_parenthesized_expr (cp_expr expr)
 {
   if (EXPR_P (expr))
+{
+  tree inner = REFERENCE_REF_P 

Re: [PATCH] c++: constness of decltype of NTTP object [PR98820]

2023-09-16 Thread Patrick Palka via Gcc-patches
On Sat, 16 Sep 2023, Jason Merrill wrote:

> On 9/15/23 13:55, Patrick Palka wrote:
> > This corrects decltype of a (class) NTTP object as per
> > [dcl.type.decltype]/1.2 and [temp.param]/6 in the type-dependent case.
> > In the non-dependent case (nontype-class8.C) we resolve the decltype
> > ahead of time, and finish_decltype_type already made sure to drop the
> > const VIEW_CONVERT_EXPR wrapper around the TEMPLATE_PARM_INDEX.
> 
> Hmm, seems like dropping the VIEW_CONVERT_EXPR is wrong in this case? I'm not
> sure why I added that.

Ah sorry, my commit message was a bit sloppy.

In the non-dependent case we resolve the decltype ahead of time, in
which case finish_decltype_type drops the const VIEW_CONVERT_EXPR
wrapper around the TEMPLATE_PARM_INDEX, and the latter has the
desired non-const type.

In the type-dependent case, tsubst drops the VIEW_CONVERT_EXPR
because the substituted class NTTP is the already const object
created by get_template_parm_object.  So finish_decltype_type
at instantiation time sees the bare const object, which this patch
now adds special handling for.

So we need to continue dropping the VIEW_CONVERT_EXPR to handle the
non-dependent case.

> 
> Jason
> 
> 



Re: [PATCH] c++: overeager type completion in convert_to_void [PR111419]

2023-09-16 Thread Patrick Palka via Gcc-patches
On Sat, 16 Sep 2023, Jason Merrill wrote:

> On 9/15/23 12:03, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > Here convert_to_void always completes the type of an INDIRECT_REF or
> > VAR_DECL expression, but according to [expr.context] an lvalue-to-rvalue
> > conversion is applied to a discarded-value expression only if "the
> > expression is a glvalue of volatile-qualified type".  This patch restricts
> > convert_to_void's type completion accordingly.
> > 
> > PR c++/111419
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cvt.cc (convert_to_void) : Only call
> > complete_type if the type is volatile and the INDIRECT_REF
> > isn't an implicit one.
> 
> Hmm, what does implicit have to do with it?  The expression forms listed in
> https://eel.is/c++draft/expr.context#2 include "id-expression"...

When there's an implicit INDIRECT_REF, I reckoned the type of the
id-expression is really a reference type, which can't be cv-qualified?

> 
> > diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C
> > b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > new file mode 100644
> > index 000..5516ff46fe9
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
> > @@ -0,0 +1,16 @@
> > +// PR c++/111419
> > +
> > +struct Incomplete;
> > +
> > +template struct Holder { T t; }; // { dg-error "incomplete" }
> > +
> > +extern volatile Holder a;
> > +extern volatile Holder& b;
> > +extern volatile Holder* c;
> > +
> > +int main() {
> > +  a; // { dg-message "required from here" }
> > +  b; // { dg-warning "implicit dereference will not access object" }
> > + // { dg-bogus "required from here" "" { target *-*-* } .-1 }
> 
> ...so it seems to me this line should get the lvalue-rvalue conversion (and
> not the warning about no access).
> 
> > +  *c; // { dg-message "required from here" }
> > +}
> 
> 



[PATCH] c++: constness of decltype of NTTP object [PR98820]

2023-09-15 Thread Patrick Palka via Gcc-patches
bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

This corrects decltype of a (class) NTTP object as per
[dcl.type.decltype]/1.2 and [temp.param]/6 in the type-dependent case.
In the non-dependent case (nontype-class8.C) we resolve the decltype
ahead of time, and finish_decltype_type already made sure to drop the
const VIEW_CONVERT_EXPR wrapper around the TEMPLATE_PARM_INDEX.

PR c++/98820

gcc/cp/ChangeLog:

* semantics.cc (finish_decltype_type): Drop cv-quals from
the type of an NTTP object.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class60.C: New test.
---
 gcc/cp/semantics.cc  |  8 
 gcc/testsuite/g++.dg/cpp2a/nontype-class60.C | 20 
 2 files changed, 28 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class60.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..a7ae5e78a6c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11599,6 +11599,14 @@ finish_decltype_type (tree expr, bool 
id_expression_or_member_access_p,
 case TEMPLATE_PARM_INDEX:
  expr = mark_type_use (expr);
   type = TREE_TYPE (expr);
+ if (VAR_P (expr) && DECL_NTTP_OBJECT_P (expr))
+   {
+ /* decltype of an NTTP object is the type of the template
+parameter, which never has cv-quals.  */
+ int quals = cp_type_quals (type);
+ gcc_checking_assert (quals & TYPE_QUAL_CONST);
+ type = cv_unqualified (type);
+   }
   break;
 
 case ERROR_MARK:
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class60.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-class60.C
new file mode 100644
index 000..fb3a61cfe10
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class60.C
@@ -0,0 +1,20 @@
+// PR c++/98820
+// { dg-do compile { target c++20 } }
+
+struct A { };
+
+template
+void f() {
+  static_assert(__is_same(decltype(V), A));
+}
+
+template
+void g() {
+  static_assert(__is_same(decltype(V), A));
+}
+
+int main() {
+  constexpr A a;
+  f();
+  g();
+}
-- 
2.42.0.216.gbda494f404



[PATCH] c++: visibility wrt template and ptrmem targs [PR70413]

2023-09-15 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

When constraining the visibility of an instantiation, we weren't
properly considering the visibility of PTRMEM_CST and TEMPLATE_DECL
template arguments.

PR c++/70413

gcc/cp/ChangeLog:

* decl2.cc (min_vis_expr_r): Handle PTRMEM_CST and TEMPLATE_DECL.

gcc/testsuite/ChangeLog:

* g++.dg/abi/no-linkage-expr2.C: New test.
* g++.dg/abi/no-linkage-expr3.C: New test.
---
 gcc/cp/decl2.cc | 18 ++
 gcc/testsuite/g++.dg/abi/no-linkage-expr2.C | 15 +++
 gcc/testsuite/g++.dg/abi/no-linkage-expr3.C | 17 +
 3 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/abi/no-linkage-expr2.C
 create mode 100644 gcc/testsuite/g++.dg/abi/no-linkage-expr3.C

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index b402befba6d..5006372a646 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2582,7 +2582,10 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void 
*data)
   int *vis_p = (int *)data;
   int tpvis = VISIBILITY_DEFAULT;
 
-  switch (TREE_CODE (*tp))
+  tree t = *tp;
+  if (TREE_CODE (t) == PTRMEM_CST)
+t = PTRMEM_CST_MEMBER (t);
+  switch (TREE_CODE (t))
 {
 case CAST_EXPR:
 case IMPLICIT_CONV_EXPR:
@@ -2593,15 +2596,22 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void 
*data)
 case NEW_EXPR:
 case CONSTRUCTOR:
 case LAMBDA_EXPR:
-  tpvis = type_visibility (TREE_TYPE (*tp));
+  tpvis = type_visibility (TREE_TYPE (t));
   break;
 
+case TEMPLATE_DECL:
+  t = DECL_TEMPLATE_RESULT (t);
+  /* Fall through.  */
 case VAR_DECL:
 case FUNCTION_DECL:
-  if (! TREE_PUBLIC (*tp))
+  if (! TREE_PUBLIC (t))
tpvis = VISIBILITY_ANON;
   else
-   tpvis = DECL_VISIBILITY (*tp);
+   tpvis = DECL_VISIBILITY (t);
+  break;
+
+case FIELD_DECL:
+  tpvis = type_visibility (DECL_CONTEXT (t));
   break;
 
 default:
diff --git a/gcc/testsuite/g++.dg/abi/no-linkage-expr2.C 
b/gcc/testsuite/g++.dg/abi/no-linkage-expr2.C
new file mode 100644
index 000..db23570bb08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/no-linkage-expr2.C
@@ -0,0 +1,15 @@
+// PR c++/70413
+// { dg-do compile { target c++11 } }
+// { dg-final { scan-assembler-not "weak.*_Z" } }
+
+namespace {
+  template struct A;
+  template using B = int;
+}
+
+template class Q> void f() { }
+
+int main() {
+  f();
+  f();
+}
diff --git a/gcc/testsuite/g++.dg/abi/no-linkage-expr3.C 
b/gcc/testsuite/g++.dg/abi/no-linkage-expr3.C
new file mode 100644
index 000..a2db1a45c74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/no-linkage-expr3.C
@@ -0,0 +1,17 @@
+// PR c++/70413
+// { dg-final { scan-assembler-not "weak.*_Z" } }
+
+namespace {
+  struct A {
+void f();
+int m;
+  };
+}
+
+template void g() { }
+template void h() { }
+
+int main() {
+  g<::f>();
+  h<::m>();
+}
-- 
2.42.0.158.g94e83dcf5b



[PATCH] c++: overeager type completion in convert_to_void [PR111419]

2023-09-15 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here convert_to_void always completes the type of an INDIRECT_REF or
VAR_DECL expression, but according to [expr.context] an lvalue-to-rvalue
conversion is applied to a discarded-value expression only if "the
expression is a glvalue of volatile-qualified type".  This patch restricts
convert_to_void's type completion accordingly.

PR c++/111419

gcc/cp/ChangeLog:

* cvt.cc (convert_to_void) : Only call
complete_type if the type is volatile and the INDIRECT_REF
isn't an implicit one.
: Only call complete_type if the type is
volatile.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires36.C: New test.
* g++.dg/expr/discarded1.C: New test.
* g++.dg/expr/discarded1a.C: New test.
---
 gcc/cp/cvt.cc| 11 +++
 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C | 16 
 gcc/testsuite/g++.dg/expr/discarded1.C   | 15 +++
 gcc/testsuite/g++.dg/expr/discarded1a.C  | 16 
 4 files changed, 54 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C
 create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C

diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index c6b52f07050..5e2c01476e3 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1252,10 +1252,12 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
tree type = TREE_TYPE (expr);
int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
int is_volatile = TYPE_VOLATILE (type);
-   int is_complete = COMPLETE_TYPE_P (complete_type (type));
+   if (is_volatile && !is_reference)
+ complete_type (type);
+   int is_complete = COMPLETE_TYPE_P (type);
 
/* Can't load the value if we don't know the type.  */
-   if (is_volatile && !is_complete)
+   if (is_volatile && !is_reference && !is_complete)
   {
 if (complain & tf_warning)
  switch (implicit)
@@ -1412,9 +1414,10 @@ convert_to_void (tree expr, impl_conv_void implicit, 
tsubst_flags_t complain)
   {
/* External variables might be incomplete.  */
tree type = TREE_TYPE (expr);
-   int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
-   if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
+   if (TYPE_VOLATILE (type)
+   && !COMPLETE_TYPE_P (complete_type (type))
+   && (complain & tf_warning))
  switch (implicit)
{
  case ICV_CAST:
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
new file mode 100644
index 000..8d3a4fcd2aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C
@@ -0,0 +1,16 @@
+// PR c++/111419
+// { dg-do compile { target c++20 } }
+
+template
+concept invocable = requires(F& f) { f(); };
+
+template
+concept deref_invocable = requires(F& f) { *f(); };
+
+struct Incomplete;
+
+template
+struct Holder { T t; };
+
+static_assert(invocable& ()>);
+static_assert(deref_invocable* ()>);
diff --git a/gcc/testsuite/g++.dg/expr/discarded1.C 
b/gcc/testsuite/g++.dg/expr/discarded1.C
new file mode 100644
index 000..c0c22e9e95b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/discarded1.C
@@ -0,0 +1,15 @@
+// PR c++/111419
+
+struct Incomplete;
+
+template struct Holder { T t; }; // { dg-bogus "incomplete" }
+
+extern Holder a;
+extern Holder& b;
+extern Holder* c;
+
+int main() {
+  a;
+  b;
+  *c;
+}
diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C 
b/gcc/testsuite/g++.dg/expr/discarded1a.C
new file mode 100644
index 000..5516ff46fe9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
@@ -0,0 +1,16 @@
+// PR c++/111419
+
+struct Incomplete;
+
+template struct Holder { T t; }; // { dg-error "incomplete" }
+
+extern volatile Holder a;
+extern volatile Holder& b;
+extern volatile Holder* c;
+
+int main() {
+  a; // { dg-message "required from here" }
+  b; // { dg-warning "implicit dereference will not access object" }
+ // { dg-bogus "required from here" "" { target *-*-* } .-1 }
+  *c; // { dg-message "required from here" }
+}
-- 
2.42.0.158.g94e83dcf5b



Re: [PATCH] libstdc++: Use C++20 constraints in

2023-09-14 Thread Patrick Palka via Gcc-patches
On Thu, 14 Sep 2023, Jonathan Wakely wrote:

> On Thu, 14 Sept 2023 at 15:13, Patrick Palka via Libstdc++
>  wrote:
> >
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> >
> > -- >8 --
> >
> > By now it's probably safe to assume supported compilers have full
> > concepts support in C++20 mode.
> 
> Clang 14.0.0 is good enough for these uses. It doesn't handle our
>  properly, or conditionally trivial special member functions,
> but that's not a problem here.

Makes sense.

> 
> >  And using a requires-clase instead
> > enable_if_t inside the return type greatly reduces the sizes of the
> > corresponding symbol names.
> 
> Will that change when we start to mangle constraints? :-)

In this specific case it should still be very worthwhile, since the
mangling of _If_is_unsigned_integer<_Tp> is around 200 characters due to
alias template transparency.  IIUC the mangling for the new constraint
__unsigned_integer<_Tp> should be around the same size as written since
we won't normalize concept-ids when mangling them like we do alias
template-ids.

> 
> OK for trunk.

Thanks!

> 
> 
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/std/bit: Include .
> > (byteswap): Use a requires-clause instead of enable_if_t
> > inside the return type.
> > (_If_is_unsigned_integer): Replace with ...
> > (__unsigned_integer): ... this.
> > (rotl): Use a requires-clause instead of enable_if_t
> > inside the return type.
> > (countl_zero): Likewise.
> > (countl_one): Likewise.
> > (countr_zero): Likewise.
> > (countr_one): Likewise.
> > (popcount): Likewise.
> > (has_single_bit): Likewise.
> > (bit_ceil): Likewise.
> > (bit_floor): Likewise.
> > (bit_width): Likewise.
> > ---
> >  libstdc++-v3/include/std/bit | 54 ++--
> >  1 file changed, 27 insertions(+), 27 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
> > index 987b6cdbb35..dce61b440c5 100644
> > --- a/libstdc++-v3/include/std/bit
> > +++ b/libstdc++-v3/include/std/bit
> > @@ -33,6 +33,7 @@
> >
> >  #if __cplusplus >= 201402L
> >
> > +#include  // for std::integral
> >  #include 
> >
> >  #if _GLIBCXX_HOSTED || __has_include()
> > @@ -103,9 +104,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > * @return An object of the same type, with the bytes reversed.
> > * @since C++23
> > */
> > -  template
> > +  template
> >  [[nodiscard]]
> > -constexpr enable_if_t::value, _Tp>
> > +constexpr _Tp
> >  byteswap(_Tp __value) noexcept
> >  {
> >if constexpr (sizeof(_Tp) == 1)
> > @@ -378,54 +379,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >  #ifdef __cpp_lib_bitops // C++ >= 20
> >
> >/// @cond undocumented
> > -  template
> > -using _If_is_unsigned_integer
> > -  = enable_if_t<__is_unsigned_integer<_Tp>::value, _Up>;
> > +  template
> > +concept __unsigned_integer = __is_unsigned_integer<_Tp>::value;
> >/// @endcond
> >
> >// [bit.rot], rotating
> >
> >/// Rotate `x` to the left by `s` bits.
> > -  template
> > -[[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
> > +  template<__unsigned_integer _Tp>
> > +[[nodiscard]] constexpr _Tp
> >  rotl(_Tp __x, int __s) noexcept
> >  { return std::__rotl(__x, __s); }
> >
> >/// Rotate `x` to the right by `s` bits.
> > -  template
> > -[[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
> > +  template<__unsigned_integer _Tp>
> > +[[nodiscard]] constexpr _Tp
> >  rotr(_Tp __x, int __s) noexcept
> >  { return std::__rotr(__x, __s); }
> >
> >// [bit.count], counting
> >
> >/// The number of contiguous zero bits, starting from the highest bit.
> > -  template
> > -constexpr _If_is_unsigned_integer<_Tp, int>
> > +  template<__unsigned_integer _Tp>
> > +constexpr int
> >  countl_zero(_Tp __x) noexcept
> >  { return std::__countl_zero(__x); }
> >
> >/// The number of contiguous one bits, starting from the highest bit.
> > -  template
> > -constexpr _If_is_unsigned_integer<_Tp, int>
> > +  template<__unsigned_integer _Tp>
> > +constexpr int
> >  countl_one(_Tp __x) noexcept
> >  { return std::__countl_one(__x); }
> >
> >/// The number of contiguous zero bits, starting from the lowest bit.
> > -  template
> > -constexpr _If_is_unsigned_integer<_Tp, int>
> > +  template<__unsigned_integer _Tp>
> > +constexpr int
> >  countr_zero(_Tp __x) noexcept
> >  { return std::__countr_zero(__x); }
> >
> >/// The number of contiguous one bits, starting from the lowest bit.
> > -  template
> > -constexpr _If_is_unsigned_integer<_Tp, int>
> > +  template<__unsigned_integer _Tp>
> > +constexpr int
> >  countr_one(_Tp __x) noexcept
> >  { return std::__countr_one(__x); }
> >
> >/// The number of bits set in `x`.
> > -  template
> > -constexpr 

[PATCH] libstdc++: Use C++20 constraints in

2023-09-14 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

By now it's probably safe to assume supported compilers have full
concepts support in C++20 mode.  And using a requires-clase instead
enable_if_t inside the return type greatly reduces the sizes of the
corresponding symbol names.

libstdc++-v3/ChangeLog:

* include/std/bit: Include .
(byteswap): Use a requires-clause instead of enable_if_t
inside the return type.
(_If_is_unsigned_integer): Replace with ...
(__unsigned_integer): ... this.
(rotl): Use a requires-clause instead of enable_if_t
inside the return type.
(countl_zero): Likewise.
(countl_one): Likewise.
(countr_zero): Likewise.
(countr_one): Likewise.
(popcount): Likewise.
(has_single_bit): Likewise.
(bit_ceil): Likewise.
(bit_floor): Likewise.
(bit_width): Likewise.
---
 libstdc++-v3/include/std/bit | 54 ++--
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index 987b6cdbb35..dce61b440c5 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -33,6 +33,7 @@
 
 #if __cplusplus >= 201402L
 
+#include  // for std::integral
 #include 
 
 #if _GLIBCXX_HOSTED || __has_include()
@@ -103,9 +104,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @return An object of the same type, with the bytes reversed.
* @since C++23
*/
-  template
+  template
 [[nodiscard]]
-constexpr enable_if_t::value, _Tp>
+constexpr _Tp
 byteswap(_Tp __value) noexcept
 {
   if constexpr (sizeof(_Tp) == 1)
@@ -378,54 +379,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef __cpp_lib_bitops // C++ >= 20
 
   /// @cond undocumented
-  template
-using _If_is_unsigned_integer
-  = enable_if_t<__is_unsigned_integer<_Tp>::value, _Up>;
+  template
+concept __unsigned_integer = __is_unsigned_integer<_Tp>::value;
   /// @endcond
 
   // [bit.rot], rotating
 
   /// Rotate `x` to the left by `s` bits.
-  template
-[[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
+  template<__unsigned_integer _Tp>
+[[nodiscard]] constexpr _Tp
 rotl(_Tp __x, int __s) noexcept
 { return std::__rotl(__x, __s); }
 
   /// Rotate `x` to the right by `s` bits.
-  template
-[[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
+  template<__unsigned_integer _Tp>
+[[nodiscard]] constexpr _Tp
 rotr(_Tp __x, int __s) noexcept
 { return std::__rotr(__x, __s); }
 
   // [bit.count], counting
 
   /// The number of contiguous zero bits, starting from the highest bit.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  template<__unsigned_integer _Tp>
+constexpr int
 countl_zero(_Tp __x) noexcept
 { return std::__countl_zero(__x); }
 
   /// The number of contiguous one bits, starting from the highest bit.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  template<__unsigned_integer _Tp>
+constexpr int
 countl_one(_Tp __x) noexcept
 { return std::__countl_one(__x); }
 
   /// The number of contiguous zero bits, starting from the lowest bit.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  template<__unsigned_integer _Tp>
+constexpr int
 countr_zero(_Tp __x) noexcept
 { return std::__countr_zero(__x); }
 
   /// The number of contiguous one bits, starting from the lowest bit.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  template<__unsigned_integer _Tp>
+constexpr int
 countr_one(_Tp __x) noexcept
 { return std::__countr_one(__x); }
 
   /// The number of bits set in `x`.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  template<__unsigned_integer _Tp>
+constexpr int
 popcount(_Tp __x) noexcept
 { return std::__popcount(__x); }
 #endif // __cpp_lib_bitops
@@ -434,28 +434,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // [bit.pow.two], integral powers of 2
 
   /// True if `x` is a power of two, false otherwise.
-  template
-constexpr _If_is_unsigned_integer<_Tp, bool>
+  template<__unsigned_integer _Tp>
+constexpr bool
 has_single_bit(_Tp __x) noexcept
 { return std::__has_single_bit(__x); }
 
   /// The smallest power-of-two not less than `x`.
-  template
-constexpr _If_is_unsigned_integer<_Tp>
+  template<__unsigned_integer _Tp>
+constexpr _Tp
 bit_ceil(_Tp __x) noexcept
 { return std::__bit_ceil(__x); }
 
   /// The largest power-of-two not greater than `x`.
-  template
-constexpr _If_is_unsigned_integer<_Tp>
+  template<__unsigned_integer _Tp>
+constexpr _Tp
 bit_floor(_Tp __x) noexcept
 { return std::__bit_floor(__x); }
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 3656. Inconsistent bit operations returning a count
   /// The smallest integer greater than the base-2 logarithm of `x`.
-  template
-constexpr _If_is_unsigned_integer<_Tp, int>
+  

[PATCH] libstdc++: Reduce integer std::to/from_chars symbol sizes

2023-09-13 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

For std::to_chars:

The constrained alias __integer_to_chars_result_type seems unnecessary
ever since r10-3080-g28f0075742ed58 got rid of the only public overload
which used it.  Now only non-public overloads are constrained by it
(through their return type) and these non-public overloads aren't used
in a SFINAE context, so the constraints have no observable effect.  So
this patch gets rid of this alias, which greatly reduces the symbol
sizes of the affected functions (since the expanded alias is quite
large).

For std::from_chars:

We can't get rid of the corresponding alias because it's constrains
the public integer std::from_chars overload.  But we can avoid having
the constraint bloat the mangled name by instead encoding it as a
defaulted template parameter.  We use the non-type parameter form

  enable_if_t<..., int> = 0

instead of the type parameter form

  typename = enable_if_t<...>

because the type form can be circumvented by providing an explicit template
argument to type parameter, e.g. 'std::from_chars(...)', so the
non-type form seems like the more robust choice.

In passing, use __is_standard_integer in the constraint.

libstdc++-v3/ChangeLog:

* include/std/charconv (__detail::__integer_to_chars_result_type):
Remove.
(__detail::__to_chars_16): Use to_chars_result as return type.
(__detail::__to_chars_10): Likewise.
(__detail::__to_chars_8): Likewise.
(__detail::__to_chars_2): Likewise.
(__detail::__to_chars_i): Likewise.
(__detail::__integer_from_chars_result_type): Pull out enable_if_t
condition into and replace with ...
(__detail::__integer_from_chars_enabled): ... this.  Use
__is_standard_integer instead of __is_signed_integer and
__is_unsigned_integer.
(from_chars): Encode constraint as a defaulted non-type template
parameter instead of within the return type.
---
 libstdc++-v3/include/std/charconv | 33 ++-
 1 file changed, 10 insertions(+), 23 deletions(-)

diff --git a/libstdc++-v3/include/std/charconv 
b/libstdc++-v3/include/std/charconv
index 01711d38576..ec25ae139ba 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -79,17 +79,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 namespace __detail
 {
-  template
-using __integer_to_chars_result_type
-  = enable_if_t<__or_<__is_signed_integer<_Tp>,
- __is_unsigned_integer<_Tp>,
-#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
- is_same<_Tp, signed __int128>,
- is_same<_Tp, unsigned __int128>,
-#endif
- is_same>>::value,
-   to_chars_result>;
-
   // Pick an unsigned type of suitable size. This is used to reduce the
   // number of specializations of __to_chars_len, __to_chars etc. that
   // get instantiated. For example, to_chars and to_chars
@@ -162,7 +151,7 @@ namespace __detail
 }
 
   template
-constexpr __integer_to_chars_result_type<_Tp>
+constexpr to_chars_result
 __to_chars_16(char* __first, char* __last, _Tp __val) noexcept
 {
   static_assert(__integer_to_chars_is_unsigned<_Tp>, "implementation bug");
@@ -208,7 +197,7 @@ namespace __detail
 }
 
   template
-constexpr __integer_to_chars_result_type<_Tp>
+constexpr to_chars_result
 __to_chars_10(char* __first, char* __last, _Tp __val) noexcept
 {
   static_assert(__integer_to_chars_is_unsigned<_Tp>, "implementation bug");
@@ -231,7 +220,7 @@ namespace __detail
 }
 
   template
-constexpr __integer_to_chars_result_type<_Tp>
+constexpr to_chars_result
 __to_chars_8(char* __first, char* __last, _Tp __val) noexcept
 {
   static_assert(__integer_to_chars_is_unsigned<_Tp>, "implementation bug");
@@ -284,7 +273,7 @@ namespace __detail
 }
 
   template
-constexpr __integer_to_chars_result_type<_Tp>
+constexpr to_chars_result
 __to_chars_2(char* __first, char* __last, _Tp __val) noexcept
 {
   static_assert(__integer_to_chars_is_unsigned<_Tp>, "implementation bug");
@@ -320,7 +309,7 @@ namespace __detail
 } // namespace __detail
 
   template
-constexpr __detail::__integer_to_chars_result_type<_Tp>
+constexpr to_chars_result
 __to_chars_i(char* __first, char* __last, _Tp __value, int __base = 10)
 {
   __glibcxx_assert(2 <= __base && __base <= 36);
@@ -548,17 +537,15 @@ namespace __detail
 }
 
   template
-using __integer_from_chars_result_type
-  = enable_if_t<__or_<__is_signed_integer<_Tp>,
- __is_unsigned_integer<_Tp>,
- is_same>>::value,
-   from_chars_result>;
+constexpr bool __integer_from_chars_enabled
+  = __or_<__is_standard_integer<_Tp>, is_same>>::value;
 
 } // namespace __detail
 
   /// std::from_chars for 

[PATCH] c++: optimize unification of class specializations [PR89231]

2023-09-13 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Since the LHS of a qualified-id is a non-deduced context, it effectively
means we can't deduce from outer template arguments of a class template
specialization.  And checking for equality between the TI_TEMPLATE of a
class specialization parm/arg already implies that the outer template
arguments are the same.  Hence recursing into outer template arguments
during unification of class specializations is redundant, so this patch
makes unify recurse only into innermost arguments.

This incidentally fixes the testcase from PR89231 because there
more_specialized_partial_inst considers the two partial specializations
to be unordered ultimately because unify for identical
parm=arg=A::Collect gets confused when it recurses into
parm=arg={Ps...} since the level of Ps doesn't match the innermost level
of tparms that we're actually deducing.

PR c++/89231

gcc/cp/ChangeLog:

* pt.cc (try_class_unification): Strengthen TI_TEMPLATE equality
test by not calling most_general_template.  Only unify the
innermost levels of template arguments.
(unify) : Only unify the innermost levels of
template arguments.  Don't unify template arguments if the
template is not primary.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/variadic-partial3.C: New test.
---
 gcc/cp/pt.cc  | 17 +++--
 .../g++.dg/cpp0x/variadic-partial3.C  | 19 +++
 2 files changed, 30 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 838179d5fe3..c88e9cd0fa6 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23999,8 +23999,7 @@ try_class_unification (tree tparms, tree targs, tree 
parm, tree arg,
 return NULL_TREE;
   else if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 /* Matches anything.  */;
-  else if (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
-  != most_general_template (CLASSTYPE_TI_TEMPLATE (parm)))
+  else if (CLASSTYPE_TI_TEMPLATE (arg) != CLASSTYPE_TI_TEMPLATE (parm))
 return NULL_TREE;
 
   /* We need to make a new template argument vector for the call to
@@ -24041,8 +24040,10 @@ try_class_unification (tree tparms, tree targs, tree 
parm, tree arg,
   if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 err = unify_bound_ttp_args (tparms, targs, parm, arg, explain_p);
   else
-err = unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p);
+err = unify (tparms, targs,
+INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)),
+INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (arg)),
+UNIFY_ALLOW_NONE, explain_p);
 
   return err ? NULL_TREE : arg;
 }
@@ -25167,11 +25168,15 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
/* There's no chance of unification succeeding.  */
return unify_type_mismatch (explain_p, parm, arg);
 
- return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-   CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p);
+ if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
+   return unify (tparms, targs,
+ INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)),
+ INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (t)),
+ UNIFY_ALLOW_NONE, explain_p);
}
   else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
return unify_type_mismatch (explain_p, parm, arg);
+
   return unify_success (explain_p);
 
 case METHOD_TYPE:
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C 
b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C
new file mode 100644
index 000..5af60711320
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C
@@ -0,0 +1,19 @@
+// PR c++/89231
+// { dg-do compile { target c++11 } }
+
+template
+struct A {
+  template
+  struct Collect { };
+
+  template>
+  struct Seq;
+
+  template
+  struct Seq> : Seq> { };
+
+  template
+  struct Seq<0, I, Collect> : Collect { };
+};
+
+A::Seq<4> test;
-- 
2.42.0.158.g94e83dcf5b



[PATCH] c++: unifying identical tmpls from current inst [PR108347]

2023-09-13 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

Here more_specialized_partial_spec considers the two partial
specializations to be unordered ultimately because unify for identical
parm=arg=A::C returns failure due to C being dependent.

This patch fixes this by relaxing unify's early-exit identity test to
also accept dependent decls; we can't deduce anything further from them
anyway.  In passing this patch removes the CONST_DECL case of unify:
we should never see the CONST_DECL version of a template parameter here,
and for other CONST_DECLs (such as enumerators) it seems we can rely on
them already having been folded to their DECL_INITIAL.

PR c++/108347

gcc/cp/ChangeLog:

* pt.cc (unify): Return unify_success for identical dependent
DECL_P 'arg' and 'parm'.
: Remove handling.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp41.C: New test.
---
 gcc/cp/pt.cc  | 10 ++
 gcc/testsuite/g++.dg/template/ttp41.C | 17 +
 2 files changed, 19 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp41.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 838179d5fe3..c311a6b88f5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24568,7 +24568,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
  even if ARG == PARM, since we won't record unifications for the
  template parameters.  We might need them if we're trying to
  figure out which of two things is more specialized.  */
-  if (arg == parm && !uses_template_parms (parm))
+  if (arg == parm
+  && (DECL_P (parm) || !uses_template_parms (parm)))
 return unify_success (explain_p);
 
   /* Handle init lists early, so the rest of the function can assume
@@ -25286,13 +25287,6 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
   return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
strict, explain_p);
 
-case CONST_DECL:
-  if (DECL_TEMPLATE_PARM_P (parm))
-   return unify (tparms, targs, DECL_INITIAL (parm), arg, strict, 
explain_p);
-  if (arg != scalar_constant_value (parm))
-   return unify_template_argument_mismatch (explain_p, parm, arg);
-  return unify_success (explain_p);
-
 case FIELD_DECL:
 case TEMPLATE_DECL:
   /* Matched cases are handled by the ARG == PARM test above.  */
diff --git a/gcc/testsuite/g++.dg/template/ttp41.C 
b/gcc/testsuite/g++.dg/template/ttp41.C
new file mode 100644
index 000..c81e5dd2405
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp41.C
@@ -0,0 +1,17 @@
+// PR c++/108347
+
+template
+struct A {
+  template struct C { };
+
+  template class TT, class U>
+  struct B;
+
+  template
+  struct B;
+
+  template
+  struct B { };
+};
+
+A::B::C, const int*> b;
-- 
2.42.0.158.g94e83dcf5b



[PATCH] c++: always check arity before deduction

2023-09-12 Thread Patrick Palka via Gcc-patches
Bootstrpaped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

This simple patch extends the r12-3271-gf1e73199569287 optimization
to apply to deduction without explicit template arguments as well.
The motivation for this is to accept testcases such as conv20.C and
ttp40.C below, which don't use explicit template arguments but for which
unnecessary template instantiation during deduction could be avoided if
we pruned overloads according to arity early in this case as well.  This
incidentally causes us to accept one reduced testcase from PR c++/84075,
but the underlying issue there still remains unfixed.

As an added bonus, this change ends up causing the "candidate expects
N argument(s)" note during overload resolution failure to point to the
template candidate instead of the call site, which seems like an
improvement similar to r14-309-g14e881eb030509.

gcc/cp/ChangeLog:

* call.cc (add_template_candidate_real): Check arity even
when there are no explicit template arguments.  Combine the
two adjacent '!obj' tests into one.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/vt-57397-1.C: Expect "candidate expects ... N
argument(s)" at the declaration site instead of the call site.
* g++.dg/cpp0x/vt-57397-2.C: Likewise.
* g++.dg/overload/template5.C: Likewise.
* g++.dg/template/local6.C: Likewise.
* g++.dg/template/conv20.C: New test.
* g++.dg/template/ttp40.C: New test.
---
 gcc/cp/call.cc| 14 ++---
 gcc/testsuite/g++.dg/cpp0x/vt-57397-1.C   |  6 +++---
 gcc/testsuite/g++.dg/cpp0x/vt-57397-2.C   |  6 +++---
 gcc/testsuite/g++.dg/overload/template5.C |  4 ++--
 gcc/testsuite/g++.dg/template/conv20.C| 17 +++
 gcc/testsuite/g++.dg/template/local6.C|  4 ++--
 gcc/testsuite/g++.dg/template/ttp40.C | 25 +++
 7 files changed, 58 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/conv20.C
 create mode 100644 gcc/testsuite/g++.dg/template/ttp40.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 399345307ea..2bbaeee039d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -3535,13 +3535,13 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
 }
   gcc_assert (ia == nargs_without_in_chrg);
 
-  if (!obj && explicit_targs)
+  if (!obj)
 {
   /* Check that there's no obvious arity mismatch before proceeding with
 deduction.  This avoids substituting explicit template arguments
-into the template (which could result in an error outside the
-immediate context) when the resulting candidate would be unviable
-anyway.  */
+into the template or e.g. derived-to-base parm/arg unification
+(which could result in an error outside the immediate context) when
+the resulting candidate would be unviable anyway.  */
   int min_arity = 0, max_arity = 0;
   tree parms = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
   parms = skip_artificial_parms_for (tmpl, parms);
@@ -3571,11 +3571,7 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
  reason = arity_rejection (NULL_TREE, max_arity, ia);
  goto fail;
}
-}
 
-  errs = errorcount+sorrycount;
-  if (!obj)
-{
   convs = alloc_conversions (nargs);
 
   if (shortcut_bad_convs
@@ -3602,6 +3598,8 @@ add_template_candidate_real (struct z_candidate 
**candidates, tree tmpl,
}
}
 }
+
+  errs = errorcount+sorrycount;
   fn = fn_type_unification (tmpl, explicit_targs, targs,
args_without_in_chrg,
nargs_without_in_chrg,
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-57397-1.C 
b/gcc/testsuite/g++.dg/cpp0x/vt-57397-1.C
index 440bea5b2f7..bac3b64ad7e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/vt-57397-1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/vt-57397-1.C
@@ -3,20 +3,20 @@
 
 template
 void foo(T1, Tn...);
+// { dg-message "candidate expects at least 1 argument, 0 provided" "" { 
target *-*-* } .-1 }
 
 template
 void bar(T1, T2, Tn...);
+// { dg-message "candidate expects at least 2 arguments, 0 provided" "" { 
target *-*-* } .-1 }
+// { dg-message "candidate expects at least 2 arguments, 1 provided" "" { 
target *-*-* } .-2 }
 
 int main()
 {
   foo();   // { dg-error "no matching" }
-  // { dg-message "candidate expects at least 1 argument, 0 provided" "" { 
target *-*-* } .-1 }
   foo(1);
   foo(1, 2);
   bar();   // { dg-error "no matching" }
-  // { dg-message "candidate expects at least 2 arguments, 0 provided" "" { 
target *-*-* } .-1 }
   bar(1);  // { dg-error "no matching" }
-  // { dg-message "candidate expects at least 2 arguments, 1 provided" "" { 
target *-*-* } .-1 }
   bar(1, 2);
   bar(1, 2, 3);
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-57397-2.C 
b/gcc/testsuite/g++.dg/cpp0x/vt-57397-2.C
index 1a99e22c5cb..22b19ef6c1a 100644
--- 

Re: [PATCH 1/3] libstdc++: Remove std::bind_front specialization for no bound args

2023-09-12 Thread Patrick Palka via Gcc-patches
On Mon, 11 Sep 2023, Patrick Palka wrote:

> This specialization for the case of no bound args, added by
> r13-4214-gcbd05ca5ab1231, seems to be mostly obsoleted by
> r13-5033-ge2eab3c4edb6aa which added [[no_unique_address]] to the
> main template's data members.  And the compile time advantage of
> avoiding an empty tuple and index_sequence seems minimal.  Removing this
> specialization also means we don't have to fix the PR111327 bug in
> another place.

FWIW I don't feel strongly about removing this specialization.  If we
keep it We'd at least be able to reuse it for std::bind_back, and it
wouldn't be hard to fix the PR111327 bug in its implementation.

> 
>   PR libstdc++/111327
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/functional (_Bind_front0): Remove.
>   (_Bind_front_t): Adjust.
> ---
>  libstdc++-v3/include/std/functional | 63 +
>  1 file changed, 1 insertion(+), 62 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/functional 
> b/libstdc++-v3/include/std/functional
> index 60d4d1f3dd2..7d1b890bb4e 100644
> --- a/libstdc++-v3/include/std/functional
> +++ b/libstdc++-v3/include/std/functional
> @@ -996,69 +996,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>[[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args;
>  };
>  
> -  // Avoid the overhead of an empty tuple<> if there are no bound args.
> -  template
> -struct _Bind_front0
> -{
> -  static_assert(is_move_constructible_v<_Fd>);
> -
> -  // First parameter is to ensure this constructor is never used
> -  // instead of the copy/move constructor.
> -  template
> - explicit constexpr
> - _Bind_front0(int, _Fn&& __fn)
> - noexcept(is_nothrow_constructible_v<_Fd, _Fn>)
> - : _M_fd(std::forward<_Fn>(__fn))
> - { }
> -
> -  _Bind_front0(const _Bind_front0&) = default;
> -  _Bind_front0(_Bind_front0&&) = default;
> -  _Bind_front0& operator=(const _Bind_front0&) = default;
> -  _Bind_front0& operator=(_Bind_front0&&) = default;
> -  ~_Bind_front0() = default;
> -
> -  template
> - constexpr
> - invoke_result_t<_Fd&, _CallArgs...>
> - operator()(_CallArgs&&... __call_args) &
> - noexcept(is_nothrow_invocable_v<_Fd&, _CallArgs...>)
> - { return std::invoke(_M_fd, std::forward<_CallArgs>(__call_args)...); }
> -
> -  template
> - constexpr
> - invoke_result_t
> - operator()(_CallArgs&&... __call_args) const &
> - noexcept(is_nothrow_invocable_v)
> - { return std::invoke(_M_fd, std::forward<_CallArgs>(__call_args)...); }
> -
> -  template
> - constexpr
> - invoke_result_t<_Fd, _CallArgs...>
> - operator()(_CallArgs&&... __call_args) &&
> - noexcept(is_nothrow_invocable_v<_Fd, _CallArgs...>)
> - {
> -   return std::invoke(std::move(_M_fd),
> -  std::forward<_CallArgs>(__call_args)...);
> - }
> -
> -  template
> - constexpr
> - invoke_result_t
> - operator()(_CallArgs&&... __call_args) const &&
> - noexcept(is_nothrow_invocable_v)
> - {
> -   return std::invoke(std::move(_M_fd),
> -  std::forward<_CallArgs>(__call_args)...);
> - }
> -
> -private:
> -  [[no_unique_address]] _Fd _M_fd;
> -};
> -
>template
> -using _Bind_front_t
> -  = __conditional_t>,
> - _Bind_front, decay_t<_Args>...>>;
> +using _Bind_front_t = _Bind_front, decay_t<_Args>...>;
>  
>/** Create call wrapper by partial application of arguments to function.
> *
> -- 
> 2.42.0.158.g94e83dcf5b
> 
> 



[PATCH 3/3] libstdc++: Fix std::not_fn perfect forwarding [PR111327]

2023-09-11 Thread Patrick Palka via Gcc-patches
The previous patch fixed perfect forwarding for std::bind_front.
This patch fixes the same issue for std::not_fn.

Tested on x86_64-pc-linux-gnu, does this look OK for trunk and
perhaps 13?

PR libstdc++/111327

libstdc++-v3/ChangeLog:

* include/std/functional (_GLIBCXX_NOT_FN_CALL_OP): Also define
a deleted fallback operator() overload.  Constrain both the
main and deleted overloads accordingly.
* testsuite/20_util/function_objects/not_fn/111327.cc: New test.
---
 libstdc++-v3/include/std/functional   | 10 +--
 .../20_util/function_objects/not_fn/111327.cc | 29 +++
 2 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index c50b9e4d365..9551e38dfdb 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1061,7 +1061,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // forwarding _M_fn and the function arguments with the same qualifiers,
   // and deducing the return type and exception-specification.
 #define _GLIBCXX_NOT_FN_CALL_OP( _QUALS )  \
-  template  \
+  template::value>> \
_GLIBCXX20_CONSTEXPR\
decltype(_S_not<__inv_res_t<_Fn _QUALS, _Args...>>())   \
operator()(_Args&&... __args) _QUALS\
@@ -1070,7 +1071,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{   \
  return !std::__invoke(std::forward< _Fn _QUALS >(_M_fn),  \
std::forward<_Args>(__args)...);\
-   }
+   }   \
+   \
+  template::value>> \
+   void operator()(_Args&&... __args) _QUALS = delete;
+
   _GLIBCXX_NOT_FN_CALL_OP( & )
   _GLIBCXX_NOT_FN_CALL_OP( const & )
   _GLIBCXX_NOT_FN_CALL_OP( && )
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc
new file mode 100644
index 000..93e00ee8057
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc
@@ -0,0 +1,29 @@
+// PR libstdc++/111327 - std::bind_front (and std::not_fn) doesn't perfectly
+// forward according to value category of the call wrapper object
+// { dg-do compile { target c++17 } }
+
+#include 
+#include 
+
+struct F {
+  void operator()(...) & = delete;
+  bool operator()(...) const &;
+};
+
+struct G {
+  void operator()(...) && = delete;
+  bool operator()(...) const &&;
+};
+
+int main() {
+  auto f = std::not_fn(F{});
+  f(); // { dg-error "deleted" }
+  std::move(f)();
+  std::as_const(f)();
+  std::move(std::as_const(f))();
+
+  auto g = std::not_fn(G{});
+  g(); // { dg-error "deleted" }
+  std::move(g)(); // { dg-error "deleted" }
+  std::move(std::as_const(g))();
+}
-- 
2.42.0.158.g94e83dcf5b



[PATCH 2/3] libstdc++: Fix std::bind_front perfect forwarding [PR111327]

2023-09-11 Thread Patrick Palka via Gcc-patches
In order to properly implement a perfect forwarding call wrapper
(before 'deducing this' at least) we need a total of 8 operator()
overloads, 4 main ones and 4 deleted ones for each const/ref qual pair,
as described in section 5.5 of P0847R6.  Otherwise the wrapper may
not perfectly forward according to the value category and constness
of the wrapped object.  This patch fixes this bug in std::bind_front.

PR libstdc++/111327

libstdc++-v3/ChangeLog:

* include/std/functional (_Bind_front::operator()): Add deleted
fallback overloads for each const/ref qualifier pair.  Give the
main overloads dummy constraints to make them more specialized
than the deleted overloads.
* testsuite/20_util/function_objects/bind_front/111327.cc: New test.
---
 libstdc++-v3/include/std/functional   | 16 
 .../function_objects/bind_front/111327.cc | 41 +++
 2 files changed, 57 insertions(+)
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 7d1b890bb4e..c50b9e4d365 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -938,6 +938,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   ~_Bind_front() = default;
 
   template
+   requires true
constexpr
invoke_result_t<_Fd&, _BoundArgs&..., _CallArgs...>
operator()(_CallArgs&&... __call_args) &
@@ -948,6 +949,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
 
   template
+   requires true
constexpr
invoke_result_t
operator()(_CallArgs&&... __call_args) const &
@@ -959,6 +961,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
 
   template
+   requires true
constexpr
invoke_result_t<_Fd, _BoundArgs..., _CallArgs...>
operator()(_CallArgs&&... __call_args) &&
@@ -969,6 +972,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
 
   template
+   requires true
constexpr
invoke_result_t
operator()(_CallArgs&&... __call_args) const &&
@@ -979,6 +983,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  std::forward<_CallArgs>(__call_args)...);
}
 
+  template
+   void operator()(_CallArgs&&...) & = delete;
+
+  template
+   void operator()(_CallArgs&&...) const & = delete;
+
+  template
+   void operator()(_CallArgs&&...) && = delete;
+
+  template
+   void operator()(_CallArgs&&...) const && = delete;
+
 private:
   using _BoundIndices = index_sequence_for<_BoundArgs...>;
 
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
new file mode 100644
index 000..6eb51994476
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
@@ -0,0 +1,41 @@
+// PR libstdc++/111327 - std::bind_front doesn't perfectly forward according
+// to value category of the call wrapper object
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include 
+#include 
+
+struct F {
+  void operator()(...) & = delete;
+  void operator()(...) const &;
+};
+
+struct G {
+  void operator()(...) && = delete;
+  void operator()(...) const &&;
+};
+
+int main() {
+  auto f0 = std::bind_front(F{});
+  f0(); // { dg-error "deleted" }
+  std::move(f0)();
+  std::as_const(f0)();
+  std::move(std::as_const(f0))();
+
+  auto g0 = std::bind_front(G{});
+  g0(); // { dg-error "deleted" }
+  std::move(g0)(); // { dg-error "deleted" }
+  std::move(std::as_const(g0))();
+
+  auto f1 = std::bind_front(F{}, 42);
+  f1(); // { dg-error "deleted" }
+  std::move(f1)();
+  std::as_const(f1)();
+  std::move(std::as_const(f1))();
+
+  auto g1 = std::bind_front(G{}, 42);
+  g1(); // { dg-error "deleted" }
+  std::move(g1)(); // { dg-error "deleted" }
+  std::move(std::as_const(g1))();
+}
-- 
2.42.0.158.g94e83dcf5b



[PATCH 1/3] libstdc++: Remove std::bind_front specialization for no bound args

2023-09-11 Thread Patrick Palka via Gcc-patches
This specialization for the case of no bound args, added by
r13-4214-gcbd05ca5ab1231, seems to be mostly obsoleted by
r13-5033-ge2eab3c4edb6aa which added [[no_unique_address]] to the
main template's data members.  And the compile time advantage of
avoiding an empty tuple and index_sequence seems minimal.  Removing this
specialization also means we don't have to fix the PR111327 bug in
another place.

PR libstdc++/111327

libstdc++-v3/ChangeLog:

* include/std/functional (_Bind_front0): Remove.
(_Bind_front_t): Adjust.
---
 libstdc++-v3/include/std/functional | 63 +
 1 file changed, 1 insertion(+), 62 deletions(-)

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 60d4d1f3dd2..7d1b890bb4e 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -996,69 +996,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args;
 };
 
-  // Avoid the overhead of an empty tuple<> if there are no bound args.
-  template
-struct _Bind_front0
-{
-  static_assert(is_move_constructible_v<_Fd>);
-
-  // First parameter is to ensure this constructor is never used
-  // instead of the copy/move constructor.
-  template
-   explicit constexpr
-   _Bind_front0(int, _Fn&& __fn)
-   noexcept(is_nothrow_constructible_v<_Fd, _Fn>)
-   : _M_fd(std::forward<_Fn>(__fn))
-   { }
-
-  _Bind_front0(const _Bind_front0&) = default;
-  _Bind_front0(_Bind_front0&&) = default;
-  _Bind_front0& operator=(const _Bind_front0&) = default;
-  _Bind_front0& operator=(_Bind_front0&&) = default;
-  ~_Bind_front0() = default;
-
-  template
-   constexpr
-   invoke_result_t<_Fd&, _CallArgs...>
-   operator()(_CallArgs&&... __call_args) &
-   noexcept(is_nothrow_invocable_v<_Fd&, _CallArgs...>)
-   { return std::invoke(_M_fd, std::forward<_CallArgs>(__call_args)...); }
-
-  template
-   constexpr
-   invoke_result_t
-   operator()(_CallArgs&&... __call_args) const &
-   noexcept(is_nothrow_invocable_v)
-   { return std::invoke(_M_fd, std::forward<_CallArgs>(__call_args)...); }
-
-  template
-   constexpr
-   invoke_result_t<_Fd, _CallArgs...>
-   operator()(_CallArgs&&... __call_args) &&
-   noexcept(is_nothrow_invocable_v<_Fd, _CallArgs...>)
-   {
- return std::invoke(std::move(_M_fd),
-std::forward<_CallArgs>(__call_args)...);
-   }
-
-  template
-   constexpr
-   invoke_result_t
-   operator()(_CallArgs&&... __call_args) const &&
-   noexcept(is_nothrow_invocable_v)
-   {
- return std::invoke(std::move(_M_fd),
-std::forward<_CallArgs>(__call_args)...);
-   }
-
-private:
-  [[no_unique_address]] _Fd _M_fd;
-};
-
   template
-using _Bind_front_t
-  = __conditional_t>,
-   _Bind_front, decay_t<_Args>...>>;
+using _Bind_front_t = _Bind_front, decay_t<_Args>...>;
 
   /** Create call wrapper by partial application of arguments to function.
*
-- 
2.42.0.158.g94e83dcf5b



Re: [PATCH] libstdc++ Use _GLIBCXX_USE_BUILTIN_TRAIT

2023-09-11 Thread Patrick Palka via Gcc-patches
On Mon, 11 Sep 2023, Ken Matsui via Gcc-patches wrote:

> This patch uses _GLIBCXX_USE_BUILTIN_TRAIT macro instead of __has_builtin in
> the type_traits header for traits that have a corresponding fallback
> non-built-in implementation. This macro supports to toggle the use of built-in
> traits in the type_traits header through _GLIBCXX_DO_NOT_USE_BUILTIN_TRAITS
> macro, without needing to modify the source code.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits: Use _GLIBCXX_USE_BUILTIN_TRAIT.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 10 +-
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 677cd934b94..221c809dd6d 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -1430,7 +1430,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  : public __bool_constant<__is_base_of(_Base, _Derived)>
>  { };
>  
> -#if __has_builtin(__is_convertible)
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_convertible)
>template
>  struct is_convertible
>  : public __bool_constant<__is_convertible(_From, _To)>
> @@ -1480,7 +1480,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  
>  #ifdef __cpp_lib_is_nothrow_convertible // C++ >= 20
>  
> -#if __has_builtin(__is_nothrow_convertible)
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_convertible)
>/// is_nothrow_convertible_v
>template
>  inline constexpr bool is_nothrow_convertible_v
> @@ -1555,7 +1555,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { using type = _Tp; };
>  
>/// remove_cv
> -#if __has_builtin(__remove_cv)
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_cv)
>template
>  struct remove_cv
>  { using type = __remove_cv(_Tp); };
> @@ -1621,7 +1621,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Reference transformations.
>  
>/// remove_reference
> -#if __has_builtin(__remove_reference)
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_reference)
>template
>  struct remove_reference
>  { using type = __remove_reference(_Tp); };
> @@ -3427,7 +3427,7 @@ template
> * @{
> */
>  #ifdef __cpp_lib_remove_cvref // C++ >= 20
> -# if __has_builtin(__remove_cvref)
> +# if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_cvref)
>template
>  struct remove_cvref
>  { using type = __remove_cvref(_Tp); };
> -- 
> 2.42.0
> 
> 



Re: [PATCH 2/2] c++: partial ordering and dep alias tmpl specs [PR90679]

2023-09-11 Thread Patrick Palka via Gcc-patches
On Thu, 1 Jun 2023, Patrick Palka wrote:

> During partial ordering, we want to look through dependent alias
> template specializations within template arguments and otherwise
> treat them as opaque in other contexts (see e.g. r7-7116-g0c942f3edab108
> and r11-7011-g6e0a231a4aa240).  To that end template_args_equal was
> given a partial_order flag that controls this behavior.  This flag
> does the right thing when a dependent alias template specialization
> appears as template argument of the partial specialization, e.g. in
> 
>   template using first_t = T;
>   template struct traits;
>   template struct traits> { }; // #1
>   template struct traits> { }; // #2
> 
> we correctly consider #2 to be more specialized than #1.  But if
> the alias specialization appears as a template argument of another
> class template specialization, e.g. in
> 
>   template struct traits>> { }; // #1
>   template struct traits>> { }; // #2
> 
> then we incorrectly consider #1 and #2 to be unordered.  This is because
> 
>   1. we don't propagate the flag to recursive template_args_equal calls
>   2. we don't use structural equality for class template specializations
>  written in terms of dependent alias template specializations
> 
> This patch fixes the first issue by turning the partial_order flag into
> a global.  This patch fixes the second issue by making us propagate
> structural equality appropriately when building a class template
> specialization.  In passing this patch also improves hashing of
> specializations that use structural equality.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

Ping.

> 
>   PR c++/90679
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (comp_template_args): Remove partial_order
>   parameter.
>   (template_args_equal): Likewise.
>   * pt.cc (iterative_hash_template_arg) : Hash
>   the template and arguments for specializations that use
>   structural equality.
>   (comparing_for_partial_ordering): New flag.
>   (template_args_equal): Remove partial order parameter and
>   use comparing_for_partial_ordering instead.
>   (comp_template_args): Likewise.
>   (comp_template_args_porder): Set comparing_for_partial_ordering
>   instead.  Make static.
>   (any_template_arguments_need_structural_equality_p): Return true
>   for an argument that's a dependent alias template specialization
>   or a class template specialization that itself needs structural
>   equality.
>   * tree.cc (cp_tree_equal) : Adjust call to
>   comp_template_args.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/alias-decl-75a.C: New test.
>   * g++.dg/cpp0x/alias-decl-75b.C: New test.
> ---
>  gcc/cp/cp-tree.h|  4 +--
>  gcc/cp/pt.cc| 40 +
>  gcc/cp/tree.cc  |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C | 26 ++
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75b.C | 26 ++
>  5 files changed, 88 insertions(+), 10 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75a.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75b.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 5330d1e1f62..f08e5630a5c 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7381,8 +7381,8 @@ extern int template_class_depth (tree);
>  extern int is_specialization_of  (tree, tree);
>  extern bool is_specialization_of_friend  (tree, tree);
>  extern bool comp_template_args   (tree, tree, tree * = 
> NULL,
> -  tree * = NULL, bool = false);
> -extern int template_args_equal  (tree, tree, bool = false);
> +  tree * = NULL);
> +extern int template_args_equal  (tree, tree);
>  extern tree maybe_process_partial_specialization (tree);
>  extern tree most_specialized_instantiation   (tree);
>  extern tree most_specialized_partial_spec   (tree, tsubst_flags_t);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 1b28195e10d..1a32f10b22b 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -1913,6 +1913,11 @@ iterative_hash_template_arg (tree arg, hashval_t val)
>   default:
> if (tree canonical = TYPE_CANONICAL (arg))
>   val = iterative_hash_object (TYPE_HASH (canonical), val);
> +   else if (tree ti = TYPE_TEMPLATE_INFO (arg))
> + {
> +   val = iterative_hash_template_arg (TI_TEMPLATE (ti), val);
> +   val = iterative_hash_template_arg (TI_ARGS (ti), val);
> + }
> break;
>   }
>  
> @@ -9296,6 +9301,12 @@ coerce_template_parms (tree parms,
>return return_full_args ? new_args : new_inner_args;
>  }
>  
> +/* Whether we are comparing template arguments during partial ordering
> +   (and 

Re: [PATCH 1/2] c++: refine dependent_alias_template_spec_p [PR90679]

2023-09-11 Thread Patrick Palka via Gcc-patches
On Thu, 1 Jun 2023, Patrick Palka wrote:

> For a complex alias template-id, dependent_alias_template_spec_p returns
> true if any template argument of the template-id is dependent.  This
> predicate indicates that substitution into the template-id may behave
> differently with respect to SFINAE than substitution into the expanded
> alias, and so the alias is in a way non-transparent.  For example
> 'first_t' in
> 
>   template using first_t = T;
>   template first_t f();
> 
> is such an alias template-id since first_t doesn't use its second
> template parameter and so the substitution into the expanded alias would
> discard the SFINAE effects of the corresponding (dependent) argument 'T&'.
> 
> But this predicate is overly conservative since what really matters for
> sake of SFINAE equivalence is whether a template argument corresponding
> to an _unused_ template parameter is dependent.  So the predicate should
> return false for e.g. 'first_t' or 'first_t'.
> 
> This patch refines the predicate appropriately.  We need to be able to
> efficiently determine which template parameters of a complex alias
> template are unused, so to that end we add a new out parameter to
> complex_alias_template_p and cache its result in an on-the-side
> hash_map that replaces the existing TEMPLATE_DECL_COMPLEX_ALIAS_P
> flag.  And in doing so, we fix a latent bug that this flag wasn't
> being propagated during partial instantiation, and so we were treating
> all partially instantiated member alias templates as non-complex.
> 
>   PR c++/90679
> 
> gcc/cp/ChangeLog:
> 
>   * cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): Remove.
>   (most_general_template): Constify parameter.
>   * pt.cc (push_template_decl): Adjust after removing
>   TEMPLATE_DECL_COMPLEX_ALIAS_P.
>   (complex_alias_tmpl_info): New hash_map.
>   (uses_all_template_parms_data::seen): Change type to
>   tree* from bool*.
>   (complex_alias_template_r): Adjust accordingly.
>   (complex_alias_template_p): Add 'seen_out' out parameter.
>   Call most_general_template and check PRIMARY_TEMPLATE_P.
>   Use complex_alias_tmpl_info to cache the result and set
>   '*seen_out' accordigly.
>   (dependent_alias_template_spec_p): Add !processing_template_decl
>   early exit test.  Consider dependence of only template arguments
>   corresponding to seen template parameters as per
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/alias-decl-75.C: New test.

Ping.

> ---
>  gcc/cp/cp-tree.h   |   7 +-
>  gcc/cp/pt.cc   | 101 +++--
>  gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C |  24 +
>  3 files changed, 100 insertions(+), 32 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-75.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index a1b882f11fe..5330d1e1f62 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -543,7 +543,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> 2: DECL_THIS_EXTERN (in VAR_DECL, FUNCTION_DECL or PARM_DECL)
>DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
>DECL_CONSTRAINT_VAR_P (in a PARM_DECL)
> -  TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
>DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
>USING_DECL_UNRELATED_P (in USING_DECL)
> 3: DECL_IN_AGGR_P.
> @@ -3655,10 +3654,6 @@ struct GTY(()) lang_decl {
>  #define TYPE_DECL_ALIAS_P(NODE) \
>DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
>  
> -/* Nonzero for TEMPLATE_DECL means that it is a 'complex' alias template.  */
> -#define TEMPLATE_DECL_COMPLEX_ALIAS_P(NODE) \
> -  DECL_LANG_FLAG_2 (TEMPLATE_DECL_CHECK (NODE))
> -
>  /* Nonzero for a type which is an alias for another type; i.e, a type
> which declaration was written 'using name-of-type =
> another-type'.  */
> @@ -7403,7 +7398,7 @@ extern tree tsubst_argument_pack(tree, 
> tree, tsubst_flags_t, tree);
>  extern tree tsubst_template_args (tree, tree, tsubst_flags_t, 
> tree);
>  extern tree tsubst_template_arg  (tree, tree, 
> tsubst_flags_t, tree);
>  extern tree tsubst_function_parms(tree, tree, tsubst_flags_t, 
> tree);
> -extern tree most_general_template(tree);
> +extern tree most_general_template(const_tree);
>  extern tree get_mostly_instantiated_function_type (tree);
>  extern bool problematic_instantiation_changed(void);
>  extern void record_last_problematic_instantiation (void);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 7fb3e75bceb..1b28195e10d 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -211,7 +211,6 @@ static tree listify (tree);
>  static tree listify_autos (tree, tree);
>  static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
>  static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
> -static bool complex_alias_template_p (const_tree tmpl);
>  static tree 

Re: [PATCH] c++: cache conversion function lookup

2023-09-07 Thread Patrick Palka via Gcc-patches
On Thu, 7 Sep 2023, Jason Merrill wrote:

> On 9/6/23 18:07, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  This cache apparently has a 98% hit rate for TYPE_HAS_CONVERSION
> > types on some test files.
> 
> Does it make a measurable difference in compile time?

Admittedly this optimization was probably more justified with the older
version of the PR99599 patch that added another lookup_conversions call.
Compile time for this standalone patch in the noise according to my
experiments, but I did measure a ~1MB/0.2% decrease in memory usage for
range-v3's zip.cpp.  This is because lookup_conversions_r allocates a
new list each time it's called (on a TYPE_HAS_CONVERSION type) even in
the simple case of no inheritance etc.  Maybe lookup_conversions_r's
(relatively complicated) implementation could be improved in the
simple/common case...

> 
> > +/* A cache of the result of lookup_conversions.  */
> > +
> > +static GTY((cache)) type_tree_cache_map *lookup_conversions_cache;
> 
> This should probably be (deletable) rather than (cache)?

Ack.  Is that because of PCH concerns or because the cache is
purely an optimization and so has no semantic effect?

> 
> Jason
> 
> 



Re: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

2023-09-06 Thread Patrick Palka via Gcc-patches
On Mon, 28 Aug 2023, Jason Merrill wrote:

> On 8/24/23 09:31, Patrick Palka wrote:
> > On Wed, 23 Aug 2023, Jason Merrill wrote:
> > 
> > > On 8/21/23 21:51, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
> > > > a reasonable approach?  I didn't observe any compile time/memory impact
> > > > of this change.
> > > > 
> > > > -- >8 --
> > > > 
> > > > As described in detail in the PR, CWG 2369 has the surprising
> > > > consequence of introducing constraint recursion in seemingly valid and
> > > > innocent code.
> > > > 
> > > > This patch attempts to fix this surpising behavior for the majority
> > > > of problematic use cases.  Rather than checking satisfaction before
> > > > _all_ non-dependent conversions, as specified by the CWG issue,
> > > > this patch makes us first check "safe" non-dependent conversions,
> > > > then satisfaction, then followed by "unsafe" non-dependent conversions.
> > > > In this case, a conversion is "safe" if computing it is guaranteed
> > > > to not induce template instantiation.  This patch heuristically
> > > > determines "safety" by checking for a constructor template or conversion
> > > > function template in the (class) parm or arg types respectively.
> > > > If neither type has such a member, then computing the conversion
> > > > should not induce instantiation (modulo satisfaction checking of
> > > > non-template constructor and conversion functions I suppose).
> > > > 
> > > > + /* We're checking only non-instantiating conversions.
> > > > +A conversion may instantiate only if it's to/from a
> > > > +class type that has a constructor template/conversion
> > > > +function template.  */
> > > > + tree parm_nonref = non_reference (parm);
> > > > + tree type_nonref = non_reference (type);
> > > > +
> > > > + if (CLASS_TYPE_P (parm_nonref))
> > > > +   {
> > > > + if (!COMPLETE_TYPE_P (parm_nonref)
> > > > + && CLASSTYPE_TEMPLATE_INSTANTIATION (parm_nonref))
> > > > +   return unify_success (explain_p);
> > > > +
> > > > + tree ctors = get_class_binding (parm_nonref,
> > > > + complete_ctor_identifier);
> > > > + for (tree ctor : lkp_range (ctors))
> > > > +   if (TREE_CODE (ctor) == TEMPLATE_DECL)
> > > > + return unify_success (explain_p);
> > > 
> > > Today we discussed maybe checking CLASSTYPE_NON_AGGREGATE?
> > 
> > Done; all dups of this PR seem to use tag types that are aggregates, so this
> > seems like a good simplification.  I also made us punt if the arg type has a
> > constrained non-template conversion function.
> > 
> > > 
> > > Also, instantiation can also happen when checking for conversion to a
> > > pointer
> > > or reference to base class.
> > 
> > Oops, I suppose we just need to strip pointer types upfront as well.  The
> > !COMPLETE_TYPE_P && CLASSTYPE_TEMPLATE_INSTANTIATION tests will then make
> > sure we deem a potential derived-to-base conversion unsafe if appropriate
> > IIUC.
> > 
> > How does the following look?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs
> > [PR99599]
> > 
> > PR c++/99599
> > 
> > gcc/cp/ChangeLog:
> > 
> > * config-lang.in (gtfiles): Add search.cc.
> > * pt.cc (check_non_deducible_conversions): Add bool parameter
> > passed down to check_non_deducible_conversion.
> > (fn_type_unification): Call check_non_deducible_conversions
> > an extra time before satisfaction with noninst_only_p=true.
> > (check_non_deducible_conversion): Add bool parameter controlling
> > whether to compute only conversions that are guaranteed to
> > not induce template instantiation.
> > * search.cc (conversions_cache): Define.
> > (lookup_conversions): Use it to cache the lookup.  Improve cache
> > rate by considering TYPE_MAIN_VARIANT of the type.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-nondep4.C: New test.
> > ---
> >   gcc/cp/config-lang.in |  1 +
> >   gcc/cp/pt.cc  | 81 +--
> >   gcc/cp/search.cc  | 14 +++-
> >   gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C | 21 +
> >   4 files changed, 110 insertions(+), 7 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C
> > 
> > @@ -22921,6 +22933,65 @@ check_non_deducible_conversion (tree parm, tree
> > arg, unification_kind_t strict,
> >   {
> > bool ok = false;
> > tree conv_arg = TYPE_P (arg) ? NULL_TREE : arg;
> > +  if (conv_p && *conv_p)
> > +   {
> > + /* This conversion was already computed earlier (when
> > +computing only non-instantiating conversions).  */
> > + gcc_checking_assert (!noninst_only_p);
> > + return unify_success 

[PATCH] c++: cache conversion function lookup

2023-09-06 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  This cache apparently has a 98% hit rate for TYPE_HAS_CONVERSION
types on some test files.

-- >8 --

gcc/cp/ChangeLog:

* config-lang.in (gtfiles): Add search.cc.
* search.cc (lookup_conversions_cache): Define.
(lookup_conversions): Use it to cache he lookup.
Improve cache rate by considering TYPE_MAIN_VARIANT
of the type.
---
 gcc/cp/config-lang.in |  1 +
 gcc/cp/search.cc  | 11 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index a6c7883cc24..e34c392d208 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -52,6 +52,7 @@ gtfiles="\
 \$(srcdir)/cp/name-lookup.cc \
 \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \
 \$(srcdir)/cp/rtti.cc \
+\$(srcdir)/cp/search.cc \
 \$(srcdir)/cp/semantics.cc \
 \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \
 \$(srcdir)/cp/vtable-class-hierarchy.cc \
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index cd80f285ac9..d5a2c57f59c 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -2582,6 +2582,10 @@ lookup_conversions_r (tree binfo, int virtual_depth, int 
virtualness,
   return my_virtualness;
 }
 
+/* A cache of the result of lookup_conversions.  */
+
+static GTY((cache)) type_tree_cache_map *lookup_conversions_cache;
+
 /* Return a TREE_LIST containing all the non-hidden user-defined
conversion functions for TYPE (and its base-classes).  The
TREE_VALUE of each node is the FUNCTION_DECL of the conversion
@@ -2596,10 +2600,14 @@ lookup_conversions (tree type)
 {
   tree convs;
 
+  type = TYPE_MAIN_VARIANT (type);
   complete_type (type);
   if (!CLASS_TYPE_P (type) || !TYPE_BINFO (type))
 return NULL_TREE;
 
+  if (tree *c = hash_map_safe_get (lookup_conversions_cache, type))
+return *c;
+
   lookup_conversions_r (TYPE_BINFO (type), 0, 0, NULL_TREE, NULL_TREE, );
 
   tree list = NULL_TREE;
@@ -2618,6 +2626,7 @@ lookup_conversions (tree type)
}
 }
 
+  hash_map_safe_put (lookup_conversions_cache, type, list);
   return list;
 }
 
@@ -2798,3 +2807,5 @@ any_dependent_bases_p (tree type)
 
   return false;
 }
+
+#include "gt-cp-search.h"
-- 
2.42.0.122.g1fc548b2d6



Re: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

2023-09-06 Thread Patrick Palka via Gcc-patches



On Mon, 28 Aug 2023, Jason Merrill wrote:

> On 8/24/23 09:31, Patrick Palka wrote:
> > On Wed, 23 Aug 2023, Jason Merrill wrote:
> > 
> > > On 8/21/23 21:51, Patrick Palka wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
> > > > a reasonable approach?  I didn't observe any compile time/memory impact
> > > > of this change.
> > > > 
> > > > -- >8 --
> > > > 
> > > > As described in detail in the PR, CWG 2369 has the surprising
> > > > consequence of introducing constraint recursion in seemingly valid and
> > > > innocent code.
> > > > 
> > > > This patch attempts to fix this surpising behavior for the majority
> > > > of problematic use cases.  Rather than checking satisfaction before
> > > > _all_ non-dependent conversions, as specified by the CWG issue,
> > > > this patch makes us first check "safe" non-dependent conversions,
> > > > then satisfaction, then followed by "unsafe" non-dependent conversions.
> > > > In this case, a conversion is "safe" if computing it is guaranteed
> > > > to not induce template instantiation.  This patch heuristically
> > > > determines "safety" by checking for a constructor template or conversion
> > > > function template in the (class) parm or arg types respectively.
> > > > If neither type has such a member, then computing the conversion
> > > > should not induce instantiation (modulo satisfaction checking of
> > > > non-template constructor and conversion functions I suppose).
> > > > 
> > > > + /* We're checking only non-instantiating conversions.
> > > > +A conversion may instantiate only if it's to/from a
> > > > +class type that has a constructor template/conversion
> > > > +function template.  */
> > > > + tree parm_nonref = non_reference (parm);
> > > > + tree type_nonref = non_reference (type);
> > > > +
> > > > + if (CLASS_TYPE_P (parm_nonref))
> > > > +   {
> > > > + if (!COMPLETE_TYPE_P (parm_nonref)
> > > > + && CLASSTYPE_TEMPLATE_INSTANTIATION (parm_nonref))
> > > > +   return unify_success (explain_p);
> > > > +
> > > > + tree ctors = get_class_binding (parm_nonref,
> > > > + complete_ctor_identifier);
> > > > + for (tree ctor : lkp_range (ctors))
> > > > +   if (TREE_CODE (ctor) == TEMPLATE_DECL)
> > > > + return unify_success (explain_p);
> > > 
> > > Today we discussed maybe checking CLASSTYPE_NON_AGGREGATE?
> > 
> > Done; all dups of this PR seem to use tag types that are aggregates, so this
> > seems like a good simplification.  I also made us punt if the arg type has a
> > constrained non-template conversion function.
> > 
> > > 
> > > Also, instantiation can also happen when checking for conversion to a
> > > pointer
> > > or reference to base class.
> > 
> > Oops, I suppose we just need to strip pointer types upfront as well.  The
> > !COMPLETE_TYPE_P && CLASSTYPE_TEMPLATE_INSTANTIATION tests will then make
> > sure we deem a potential derived-to-base conversion unsafe if appropriate
> > IIUC.
> > 
> > How does the following look?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs
> > [PR99599]
> > 
> > PR c++/99599
> > 
> > gcc/cp/ChangeLog:
> > 
> > * config-lang.in (gtfiles): Add search.cc.
> > * pt.cc (check_non_deducible_conversions): Add bool parameter
> > passed down to check_non_deducible_conversion.
> > (fn_type_unification): Call check_non_deducible_conversions
> > an extra time before satisfaction with noninst_only_p=true.
> > (check_non_deducible_conversion): Add bool parameter controlling
> > whether to compute only conversions that are guaranteed to
> > not induce template instantiation.
> > * search.cc (conversions_cache): Define.
> > (lookup_conversions): Use it to cache the lookup.  Improve cache
> > rate by considering TYPE_MAIN_VARIANT of the type.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp2a/concepts-nondep4.C: New test.
> > ---
> >   gcc/cp/config-lang.in |  1 +
> >   gcc/cp/pt.cc  | 81 +--
> >   gcc/cp/search.cc  | 14 +++-
> >   gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C | 21 +
> >   4 files changed, 110 insertions(+), 7 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C
> > 
> > @@ -22921,6 +22933,65 @@ check_non_deducible_conversion (tree parm, tree
> > arg, unification_kind_t strict,
> >   {
> > bool ok = false;
> > tree conv_arg = TYPE_P (arg) ? NULL_TREE : arg;
> > +  if (conv_p && *conv_p)
> > +   {
> > + /* This conversion was already computed earlier (when
> > +computing only non-instantiating conversions).  */
> > + gcc_checking_assert (!noninst_only_p);
> > + return unify_success 

Re: [PATCH] c++: CWG 2359, wrong copy-init with designated init [PR91319]

2023-08-25 Thread Patrick Palka via Gcc-patches
On Fri, 25 Aug 2023, Marek Polacek via Gcc-patches wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

LGTM

> 
> -- >8 --
> 
> This CWG clarifies that designated initializer support direct-initialization.
> Just be careful what Note 2 in [dcl.init.aggr]/4.2 says: "If the
> initialization is by designated-initializer-clause, its form determines
> whether copy-initialization or direct-initialization is performed."  Hence
> this patch sets CONSTRUCTOR_IS_DIRECT_INIT only when we are dealing with
> ".x{}", but not ".x = {}".
> 
>   PR c++/91319
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_initializer_list): Set CONSTRUCTOR_IS_DIRECT_INIT
>   when the designated initializer is of the .x{} form.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/desig30.C: New test.
> ---
>  gcc/cp/parser.cc |  6 ++
>  gcc/testsuite/g++.dg/cpp2a/desig30.C | 22 ++
>  2 files changed, 28 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig30.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index eeb22e44fb4..b3d5c65b469 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -25718,6 +25718,7 @@ cp_parser_initializer_list (cp_parser* parser, bool* 
> non_constant_p,
>tree designator;
>tree initializer;
>bool clause_non_constant_p;
> +  bool direct_p = false;
>location_t loc = cp_lexer_peek_token (parser->lexer)->location;
>  
>/* Handle the C++20 syntax, '. id ='.  */
> @@ -25740,6 +25741,8 @@ cp_parser_initializer_list (cp_parser* parser, bool* 
> non_constant_p,
> if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
>   /* Consume the `='.  */
>   cp_lexer_consume_token (parser->lexer);
> +   else
> + direct_p = true;
>   }
>/* Also, if the next token is an identifier and the following one is a
>colon, we are looking at the GNU designated-initializer
> @@ -25817,6 +25820,9 @@ cp_parser_initializer_list (cp_parser* parser, bool* 
> non_constant_p,
>if (clause_non_constant_p && non_constant_p)
>   *non_constant_p = true;
>  
> +  if (TREE_CODE (initializer) == CONSTRUCTOR)
> + CONSTRUCTOR_IS_DIRECT_INIT (initializer) |= direct_p;
> +
>/* If we have an ellipsis, this is an initializer pack
>expansion.  */
>if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig30.C 
> b/gcc/testsuite/g++.dg/cpp2a/desig30.C
> new file mode 100644
> index 000..d9292df9de2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig30.C
> @@ -0,0 +1,22 @@
> +// PR c++/91319
> +// { dg-do compile { target c++20 } }
> +
> +struct X {
> +explicit X() { }
> +};
> +
> +struct Aggr {
> +X x;
> +};
> +
> +Aggr
> +f ()
> +{
> +  return Aggr{.x{}};
> +}
> +
> +Aggr
> +f2 ()
> +{
> +  return Aggr{.x = {}}; // { dg-error "explicit constructor" }
> +}
> 
> base-commit: 54cc21eaf5f3eb7f7a508919a086f6c8bf5c4c17
> -- 
> 2.41.0
> 
> 



[PATCH] c++: more dummy non_constant_p arg avoidance

2023-08-25 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?  This
reduces calls to is_rvalue_constant_expression from
cp_parser_constant_expression by 10% for stdc++.h.

-- >8 --

As a follow-up to Marek's r14-3088-ga263152643bbec, this patch makes
us avoid passing an effectively dummy non_constant_p argument in two
more spots in the parser.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_parenthesized_expression_list_elt): Pass
nullptr as non_constant_p to cp_parser_braced_list if our
non_constant_p is null.
(cp_parser_initializer_list): Likewise to
cp_parser_initializer_clause.
---
 gcc/cp/parser.cc | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 774706ac607..a8cc91059c1 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -8099,7 +8099,10 @@ cp_parser_parenthesized_expression_list_elt (cp_parser 
*parser, bool cast_p,
   /* A braced-init-list.  */
   cp_lexer_set_source_position (parser->lexer);
   maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
-  expr = cp_parser_braced_list (parser, _non_constant_p);
+  expr = cp_parser_braced_list (parser,
+   (non_constant_p != nullptr
+   ? _non_constant_p
+   : nullptr));
   if (non_constant_p && expr_non_constant_p)
*non_constant_p = true;
 }
@@ -25812,9 +25815,11 @@ cp_parser_initializer_list (cp_parser* parser, bool* 
non_constant_p,
 
   /* Parse the initializer.  */
   initializer = cp_parser_initializer_clause (parser,
- _non_constant_p);
+ (non_constant_p != nullptr
+  ? _non_constant_p
+  : nullptr));
   /* If any clause is non-constant, so is the entire initializer.  */
-  if (clause_non_constant_p && non_constant_p)
+  if (non_constant_p && clause_non_constant_p)
*non_constant_p = true;
 
   /* If we have an ellipsis, this is an initializer pack
-- 
2.42.0.29.gcd9da15a85



[PATCH] c++: use conversion_obstack_sentinel throughout

2023-08-25 Thread Patrick Palka via Gcc-patches
Boostrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

This replaces manual memory management via conversion_obstack_alloc(0)
and obstack_free with the recently added conversion_obstack_sentinel,
and also uses the latter in build_user_type_conversion and
build_operator_new_call.

gcc/cp/ChangeLog:

* call.cc (build_user_type_conversion): Free allocated
conversions.
(build_converted_constant_expr_internal): Use
conversion_obstack_sentinel instead.
(perform_dguide_overload_resolution): Likewise.
(build_new_function_call): Likewise.
(build_operator_new_call): Free allocated conversions.
(build_op_call): Use conversion_obstack_sentinel instead.
(build_conditional_expr): Use conversion_obstack_sentinel
instead, and hoist it out to the outermost scope.
(build_new_op): Use conversion_obstack_sentinel instead
and set it up before the first goto.  Remove second unneeded goto.
(build_op_subscript): Use conversion_obstack_sentinel instead.
(ref_conv_binds_to_temporary): Likewise.
(build_new_method_call): Likewise.
(can_convert_arg): Likewise.
(can_convert_arg_bad): Likewise.
(perform_implicit_conversion_flags): Likewise.
(perform_direct_initialization_if_possible): Likewise.
(initialize_reference): Likewise.
---
 gcc/cp/call.cc | 107 ++---
 1 file changed, 22 insertions(+), 85 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 673ec91d60e..432ac99b4bb 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -4646,6 +4646,9 @@ build_user_type_conversion (tree totype, tree expr, int 
flags,
   tree ret;
 
   auto_cond_timevar tv (TV_OVERLOAD);
+
+  conversion_obstack_sentinel cos;
+
   cand = build_user_type_conversion_1 (totype, expr, flags, complain);
 
   if (cand)
@@ -4698,15 +4701,13 @@ build_converted_constant_expr_internal (tree type, tree 
expr,
int flags, tsubst_flags_t complain)
 {
   conversion *conv;
-  void *p;
   tree t;
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
   if (error_operand_p (expr))
 return error_mark_node;
 
-  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
-  p = conversion_obstack_alloc (0);
+  conversion_obstack_sentinel cos;
 
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
  /*c_cast_p=*/false, flags, complain);
@@ -4815,9 +4816,6 @@ build_converted_constant_expr_internal (tree type, tree 
expr,
   expr = error_mark_node;
 }
 
-  /* Free all the conversions we allocated.  */
-  obstack_free (_obstack, p);
-
   return expr;
 }
 
@@ -4985,8 +4983,7 @@ perform_dguide_overload_resolution (tree dguides, const 
vec *args,
 
   gcc_assert (deduction_guide_p (OVL_FIRST (dguides)));
 
-  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
-  void *p = conversion_obstack_alloc (0);
+  conversion_obstack_sentinel cos;
 
   z_candidate *cand = perform_overload_resolution (dguides, args, ,
   _viable_p, complain);
@@ -4999,9 +4996,6 @@ perform_dguide_overload_resolution (tree dguides, const 
vec *args,
   else
 result = cand->fn;
 
-  /* Free all the conversions we allocated.  */
-  obstack_free (_obstack, p);
-
   return result;
 }
 
@@ -5015,7 +5009,6 @@ build_new_function_call (tree fn, vec **args,
 {
   struct z_candidate *candidates, *cand;
   bool any_viable_p;
-  void *p;
   tree result;
 
   if (args != NULL && *args != NULL)
@@ -5028,8 +5021,7 @@ build_new_function_call (tree fn, vec **args,
   if (flag_tm)
 tm_malloc_replacement (fn);
 
-  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
-  p = conversion_obstack_alloc (0);
+  conversion_obstack_sentinel cos;
 
   cand = perform_overload_resolution (fn, *args, , _viable_p,
  complain);
@@ -5061,9 +5053,6 @@ build_new_function_call (tree fn, vec **args,
  == BUILT_IN_NORMAL)
result = coro_validate_builtin_call (result);
 
-  /* Free all the conversions we allocated.  */
-  obstack_free (_obstack, p);
-
   return result;
 }
 
@@ -5108,6 +5097,8 @@ build_operator_new_call (tree fnname, vec 
**args,
   if (*args == NULL)
 return error_mark_node;
 
+  conversion_obstack_sentinel cos;
+
   /* Based on:
 
[expr.new]
@@ -5234,7 +5225,6 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
   tree fns, convs, first_mem_arg = NULL_TREE;
   bool any_viable_p;
   tree result = NULL_TREE;
-  void *p;
 
   auto_cond_timevar tv (TV_OVERLOAD);
 
@@ -5273,8 +5263,7 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
return error_mark_node;
 }
 
-  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
-  p = conversion_obstack_alloc (0);
+  conversion_obstack_sentinel cos;
 
   if (fns)
 {
@@ -5377,9 +5366,6 @@ 

Re: [RFC] -folding dumping for fold-const.cc

2023-08-25 Thread Patrick Palka via Gcc-patches
On Fri, 25 Aug 2023, Richard Biener via Gcc-patches wrote:

> 
> The following adds the capability to have fold-const.cc matched
> patterns visible in -folding dumps.  There's two choices,
> a portable one replacing return stmts like
> 
> -   return fold_build1 (tcode, ctype, fold_convert (ctype, t1));
> +   DRET (fold_build1 (tcode, ctype, fold_convert (ctype, t1)));
> 
> (carefully keeping total line length the same)
> 
> Or less portably by wrapping the return value:
> 
> -   return fold_build1 (tcode, ctype, fold_convert (ctype, t1));
> +   return DUMP_FOLD (fold_build1 (tcode, ctype, fold_convert (ctype, 
> t1)));
> 
> (requiring re-indenting)
> 
> +/* Similar to match.pd dumping support notes as part of -folding dumping
> +   by wrapping return values in DUMP_FOLD (...).  */
> +#if __GNUC__
> +#define DUMP_FOLD(X) (__extension__ ({ \
> +  auto x = (X); \
> +  if (x && dump_file && (dump_flags & TDF_FOLDING)) \
> +fprintf (dump_file, "Applying fold-const.c:%d\n", __LINE__); \
> +  x; \
> +}))  

Would using an ordinary function here work?

  static tree
  dump_fold (tree x, int line)
  {
if (...)
  fprintf (dump_file, "Applying fold-const.c:%d\n", line);
return x;
  }

  #define DUMP_FOLD(X) dump_fold ((X), __LINE__)

> +#else 
> +#define DUMP_FOLD(X) (X)  
> +#endif 
> 
> vs.
> 
> +/* Similar to match.pd dumping support notes as part of -folding dumping
> +   by changing return statements to DRET (...).  */
> +#define DRET(X) do { \
> +  auto x = (X); \
> +  if (x && dump_file && (dump_flags & TDF_FOLDING)) \
> +fprintf (dump_file, "Applying fold-const.c:%d\n", __LINE__); \
> +  return x; \
> +} while (0)
> 
> I personally prefer keeping 'return' visible and thus going the
> non-portable way.  Any C++ folks know how to avoid re-evaluating
> X portably in expression context?
> 
> Any other comments?
> 
> Thanks,
> Richard.
> 
> 



Re: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

2023-08-24 Thread Patrick Palka via Gcc-patches
On Wed, 23 Aug 2023, Jason Merrill wrote:

> On 8/21/23 21:51, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
> > a reasonable approach?  I didn't observe any compile time/memory impact
> > of this change.
> > 
> > -- >8 --
> > 
> > As described in detail in the PR, CWG 2369 has the surprising
> > consequence of introducing constraint recursion in seemingly valid and
> > innocent code.
> > 
> > This patch attempts to fix this surpising behavior for the majority
> > of problematic use cases.  Rather than checking satisfaction before
> > _all_ non-dependent conversions, as specified by the CWG issue,
> > this patch makes us first check "safe" non-dependent conversions,
> > then satisfaction, then followed by "unsafe" non-dependent conversions.
> > In this case, a conversion is "safe" if computing it is guaranteed
> > to not induce template instantiation.  This patch heuristically
> > determines "safety" by checking for a constructor template or conversion
> > function template in the (class) parm or arg types respectively.
> > If neither type has such a member, then computing the conversion
> > should not induce instantiation (modulo satisfaction checking of
> > non-template constructor and conversion functions I suppose).
> > 
> > + /* We're checking only non-instantiating conversions.
> > +A conversion may instantiate only if it's to/from a
> > +class type that has a constructor template/conversion
> > +function template.  */
> > + tree parm_nonref = non_reference (parm);
> > + tree type_nonref = non_reference (type);
> > +
> > + if (CLASS_TYPE_P (parm_nonref))
> > +   {
> > + if (!COMPLETE_TYPE_P (parm_nonref)
> > + && CLASSTYPE_TEMPLATE_INSTANTIATION (parm_nonref))
> > +   return unify_success (explain_p);
> > +
> > + tree ctors = get_class_binding (parm_nonref,
> > + complete_ctor_identifier);
> > + for (tree ctor : lkp_range (ctors))
> > +   if (TREE_CODE (ctor) == TEMPLATE_DECL)
> > + return unify_success (explain_p);
> 
> Today we discussed maybe checking CLASSTYPE_NON_AGGREGATE?

Done; all dups of this PR seem to use tag types that are aggregates, so this
seems like a good simplification.  I also made us punt if the arg type has a
constrained non-template conversion function.

> 
> Also, instantiation can also happen when checking for conversion to a pointer
> or reference to base class.

Oops, I suppose we just need to strip pointer types upfront as well.  The
!COMPLETE_TYPE_P && CLASSTYPE_TEMPLATE_INSTANTIATION tests will then make
sure we deem a potential derived-to-base conversion unsafe if appropriate
IIUC.

How does the following look?

-- >8 --

Subject: [PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

PR c++/99599

gcc/cp/ChangeLog:

* config-lang.in (gtfiles): Add search.cc.
* pt.cc (check_non_deducible_conversions): Add bool parameter
passed down to check_non_deducible_conversion.
(fn_type_unification): Call check_non_deducible_conversions
an extra time before satisfaction with noninst_only_p=true.
(check_non_deducible_conversion): Add bool parameter controlling
whether to compute only conversions that are guaranteed to
not induce template instantiation.
* search.cc (conversions_cache): Define.
(lookup_conversions): Use it to cache the lookup.  Improve cache
rate by considering TYPE_MAIN_VARIANT of the type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-nondep4.C: New test.
---
 gcc/cp/config-lang.in |  1 +
 gcc/cp/pt.cc  | 81 +--
 gcc/cp/search.cc  | 14 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C | 21 +
 4 files changed, 110 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C

diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index a6c7883cc24..e34c392d208 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -52,6 +52,7 @@ gtfiles="\
 \$(srcdir)/cp/name-lookup.cc \
 \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \
 \$(srcdir)/cp/rtti.cc \
+\$(srcdir)/cp/search.cc \
 \$(srcdir)/cp/semantics.cc \
 \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \
 \$(srcdir)/cp/vtable-class-hierarchy.cc \
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a4809f034dc..3c77d2466eb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -151,7 +151,7 @@ static tree get_partial_spec_bindings (tree, tree, tree);
 static void tsubst_enum(tree, tree, tree);
 static bool check_instantiated_args (tree, tree, tsubst_flags_t);
 static int check_non_deducible_conversion (tree, tree, unification_kind_t, int,
-  struct conversion **, bool);
+  struct 

Re: [PATCH v10 3/5] c++: Implement __is_function built-in trait

2023-08-22 Thread Patrick Palka via Gcc-patches
On Wed, 12 Jul 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_function.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_function.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
>   * g++.dg/ext/is_function.C: New test.

LGTM!

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 ++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 ++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
>  gcc/testsuite/g++.dg/ext/is_function.C   | 58 
>  5 files changed, 69 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index f6951ee2670..927605c6cb7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3754,6 +3754,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_UNION:
>inform (loc, "  %qT is not a union", t1);
>break;
> +case CPTK_IS_FUNCTION:
> +  inform (loc, "  %qT is not a function", t1);
> +  break;
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 1e3310cd682..3cd3babc242 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, 
> "__is_trivially_assignable", 2)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", 
> -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> +DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
> "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
> "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 2f37bc353a1..b976633645a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12072,6 +12072,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_ENUM:
>return type_code1 == ENUMERAL_TYPE;
>  
> +case CPTK_IS_FUNCTION:
> +  return type_code1 == FUNCTION_TYPE;
> +
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12293,6 +12296,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_UNION:
>  case CPTK_IS_SAME:
>  case CPTK_IS_REFERENCE:
> +case CPTK_IS_FUNCTION:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index b697673790c..90eb00ebf2d 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -149,3 +149,6 @@
>  #if !__has_builtin (__is_reference)
>  # error "__has_builtin (__is_reference) failed"
>  #endif
> +#if !__has_builtin (__is_function)
> +# error "__has_builtin (__is_function) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_function.C 
> b/gcc/testsuite/g++.dg/ext/is_function.C
> new file mode 100644
> index 000..2e1594b12ad
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_function.C
> @@ -0,0 +1,58 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +struct A
> +{ void fn(); };
> +
> +template
> +struct AHolder { };
> +
> +template
> +struct AHolder
> +{ using type = U; };
> +
> +// Positive tests.
> +SA(__is_function(int (int)));
> +SA(__is_function(ClassType (ClassType)));
> +SA(__is_function(float (int, float, int[], int&)));
> +SA(__is_function(int (int, ...)));
> +SA(__is_function(bool (ClassType) const));
> +SA(__is_function(AHolder::type));
> +
> +void fn();
> +SA(__is_function(decltype(fn)));
> +
> +// Negative tests.
> +SA_TEST_CATEGORY(__is_function, int, false);
> +SA_TEST_CATEGORY(__is_function, int*, false);
> +SA_TEST_CATEGORY(__is_function, int&, false);
> +SA_TEST_CATEGORY(__is_function, void, false);
> +SA_TEST_CATEGORY(__is_function, void*, false);
> +SA_TEST_CATEGORY(__is_function, void**, false);
> +SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
> +
> +SA_TEST_CATEGORY(__is_function, 

[PATCH] c++: refine CWG 2369 satisfaction vs non-dep convs [PR99599]

2023-08-21 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look like
a reasonable approach?  I didn't observe any compile time/memory impact
of this change.

-- >8 --

As described in detail in the PR, CWG 2369 has the surprising
consequence of introducing constraint recursion in seemingly valid and
innocent code.

This patch attempts to fix this surpising behavior for the majority
of problematic use cases.  Rather than checking satisfaction before
_all_ non-dependent conversions, as specified by the CWG issue,
this patch makes us first check "safe" non-dependent conversions,
then satisfaction, then followed by "unsafe" non-dependent conversions.
In this case, a conversion is "safe" if computing it is guaranteed
to not induce template instantiation.  This patch heuristically
determines "safety" by checking for a constructor template or conversion
function template in the (class) parm or arg types respectively.
If neither type has such a member, then computing the conversion
should not induce instantiation (modulo satisfaction checking of
non-template constructor and conversion functions I suppose).

PR c++/99599

gcc/cp/ChangeLog:

* config-lang.in (gtfiles): Add search.cc.
* pt.cc (check_non_deducible_conversions): Add bool parameter
passed down to check_non_deducible_conversion.
(fn_type_unification): Call check_non_deducible_conversions
an extra time before satisfaction with noninst_only_p=true.
(check_non_deducible_conversion): Add bool parameter controlling
whether to compute only conversions that are guaranteed to
not induce template instantiation.
* search.cc (conversions_cache): Define.
(lookup_conversions): Use it to cache the lookup.  Improve cache
rate by considering TYPE_MAIN_VARIANT of the type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-nondep4.C: New test.
* g++.dg/cpp2a/concepts-nondep4a.C: New test.
---
 gcc/cp/config-lang.in |  1 +
 gcc/cp/pt.cc  | 66 +--
 gcc/cp/search.cc  | 14 +++-
 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C | 21 ++
 .../g++.dg/cpp2a/concepts-nondep4a.C  | 30 +
 5 files changed, 125 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-nondep4a.C

diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index a6c7883cc24..e34c392d208 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -52,6 +52,7 @@ gtfiles="\
 \$(srcdir)/cp/name-lookup.cc \
 \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \
 \$(srcdir)/cp/rtti.cc \
+\$(srcdir)/cp/search.cc \
 \$(srcdir)/cp/semantics.cc \
 \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \
 \$(srcdir)/cp/vtable-class-hierarchy.cc \
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a4809f034dc..c761b73b771 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -151,7 +151,7 @@ static tree get_partial_spec_bindings (tree, tree, tree);
 static void tsubst_enum(tree, tree, tree);
 static bool check_instantiated_args (tree, tree, tsubst_flags_t);
 static int check_non_deducible_conversion (tree, tree, unification_kind_t, int,
-  struct conversion **, bool);
+  struct conversion **, bool, bool);
 static int maybe_adjust_types_for_deduction (tree, unification_kind_t,
 tree*, tree*, tree);
 static int type_unification_real (tree, tree, tree, const tree *,
@@ -22315,7 +22315,8 @@ pack_deducible_p (tree parm, tree fn)
 static int
 check_non_deducible_conversions (tree parms, const tree *args, unsigned nargs,
 tree fn, unification_kind_t strict, int flags,
-struct conversion **convs, bool explain_p)
+struct conversion **convs, bool explain_p,
+bool noninst_only_p)
 {
   /* Non-constructor methods need to leave a conversion for 'this', which
  isn't included in nargs here.  */
@@ -22351,7 +22352,7 @@ check_non_deducible_conversions (tree parms, const tree 
*args, unsigned nargs,
  int lflags = conv_flags (ia, nargs, fn, arg, flags);
 
  if (check_non_deducible_conversion (parm, arg, strict, lflags,
- conv_p, explain_p))
+ conv_p, explain_p, 
noninst_only_p))
return 1;
}
 
@@ -22651,6 +22652,16 @@ fn_type_unification (tree fn,
 
  deduced:
 
+  /* As a refinement of CWG2369, check first and foremost non-dependent
+ conversions that we know are not going to induce template instantiation
+ (PR99599).  */
+  if (strict == DEDUCE_CALL
+  && incomplete
+  && check_non_deducible_conversions (parms, args, nargs, fn, 

Re: [PATCH] libstdc++: Make __max_size_type and __max_diff_type structural

2023-08-16 Thread Patrick Palka via Gcc-patches
On Mon, Apr 24, 2023 at 12:23 PM Patrick Palka  wrote:
>
> This patch makes these integer-class type structural types by changing
> their private data members into public ones, which allows them to be
> used as NTTP types.  I'm not sure if this is required by the standard
> but it seems handy.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

Ping

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/max_size_type.h (__max_size_type::_M_val): Make
> public instead of private.
> (__max_size_type::_M_msb): Likewise.
> (__max_diff_type::_M_rep): Likewise.
> * testsuite/std/ranges/iota/max_size_type.cc: Verify
> __max_diff_type and __max_size_type are structural.
> ---
>  libstdc++-v3/include/bits/max_size_type.h   | 4 ++--
>  libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc | 7 +++
>  2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/max_size_type.h 
> b/libstdc++-v3/include/bits/max_size_type.h
> index 4796135d073..d6705bbe4c8 100644
> --- a/libstdc++-v3/include/bits/max_size_type.h
> +++ b/libstdc++-v3/include/bits/max_size_type.h
> @@ -423,10 +423,11 @@ namespace ranges
>using __rep = unsigned long long;
>  #endif
>static constexpr size_t _S_rep_bits = sizeof(__rep) * __CHAR_BIT__;
> -private:
> +
>__rep _M_val = 0;
>unsigned _M_msb:1 = 0;
>
> +private:
>constexpr explicit
>__max_size_type(__rep __val, int __msb) noexcept
> : _M_val(__val), _M_msb(__msb)
> @@ -750,7 +751,6 @@ namespace ranges
>{ return !(__l < __r); }
>  #endif
>
> -private:
>__max_size_type _M_rep = 0;
>
>friend class __max_size_type;
> diff --git a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc 
> b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> index 985acd5a803..9afd05d5acf 100644
> --- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
> @@ -400,6 +400,13 @@ static_assert(max_diff_t(max_size_t(1)
>  << (numeric_limits::digits-1))
>   == numeric_limits::min());
>
> +// Verify that the types are structural types and can therefore be used
> +// as NTTP types.
> +template struct Su { static_assert(V*V == V+132); };
> +template struct Ss { static_assert(V*V == V+132); };
> +template struct Su<12>;
> +template struct Ss<12>;
> +
>  int
>  main()
>  {
> --
> 2.40.0.374.g7580f92ffa
>



Re: [PATCH 1/2] libstdc++: Convert _RangeAdaptorClosure into a CRTP class [PR108827]

2023-08-16 Thread Patrick Palka via Gcc-patches
On Sun, Apr 16, 2023 at 11:24 PM Patrick Palka  wrote:
>
> On Fri, 14 Apr 2023, Patrick Palka wrote:
>
> > Using the CRTP idiom for this base class avoids bloating the size of a
> > pipeline when adding distinct empty range adaptor closure objects to it,
> > as detailed in section 4.1 of P2387R3.
> >
> > But it means we can no longer define its operator| overloads as hidden
> > friends, since each instantiation of _RangeAdaptorClosure would then
> > introduce its own logically different hidden friends.  So for example
> > during overload resolution for the outer pipe operator in
> >
> >  :x | (views::reverse | views::join)
> >
> > we'd have to consider 6 different hidden operator| friends:
> >
> >   2 from _RangeAdaptorClosure<_Reverse>
> >   2 from _RangeAdaptorClosure<_Join>
> >   2 from _RangeAdaptorClosure<_Pipe<_Reverse, _Join>>
> >
> > which is wasteful and can even cause hard errors in some cases.  So we
> > instead define the operator| overloads at namespace scope in an isolated
> > namespace.
>
> On second thought, since this doesn't fix a bug or add new functionality
> it seems more like GCC 14 material.  The size reduction is nice but it's
> probably not a big deal in practice since adaptor pipelines are usually
> very transient objects that don't get passed around as function
> arguments etc.

Ping, does this look OK for trunk?

>
> But perhaps the second patch implementing range_adaptor_closure would be
> desirable for GCC 13?  I'll post an updated standalone version of that
> patch for separate consideration.
>
> >
> >   PR libstdc++/108827
> >
> > libstdc++-v3/ChangeLog:
> >
> >   * include/std/ranges (__adaptor::_RangeAdaptorClosure): Move ...
> >   (__adaptor::__closure::_RangeAdaptorClosure): ... here and turn
> >   it into a CRTP class template.  Move hidden operator| friends
> >   into namespace scope and adjust their constraints.  Add a
> >   using-declaration for this at __adaptor::_RangeAdaptorClosure.
> >   (__closure::__is_range_adaptor_closure_fn): Define.
> >   (__closure::__is_range_adaptor_closure): Define.
> >   (__adaptor::_Partial): Adjust use of _RangeAdaptorClosure.
> >   (__adaptor::_Pipe): Likewise.
> >   (views::_All): Likewise.
> >   (views::_Join): Likewise.
> >   (views::_Common): Likewise.
> >   (views::_Reverse): Likewise.
> >   (views::_Elements): Likewise.
> >   (views::_Adjacent): Likewise.
> >   (views::_AsRvalue): Likewise.
> >   (views::_Enumerate): Likewise.
> >   (views::_AsConst): Likewise.
> >   * testsuite/std/ranges/adaptors/all.cc: Reintroduce
> >   static_assert expecting that adding empty range adaptor
> >   closure objects to a pipeline doesn't increase the size of a
> >   pipeline.
> > ---
> >  libstdc++-v3/include/std/ranges   | 69 +++
> >  .../testsuite/std/ranges/adaptors/all.cc  |  7 --
> >  2 files changed, 42 insertions(+), 34 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index 283d757faa4..531ec6f68b3 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -872,30 +872,45 @@ namespace views::__adaptor
> >template
> >  struct _Pipe;
> >
> > -  // The base class of every range adaptor closure.
> > -  //
> > -  // The derived class should define the optional static data member
> > -  // _S_has_simple_call_op to true if the behavior of this adaptor is
> > -  // independent of the constness/value category of the adaptor object.
> > -  struct _RangeAdaptorClosure
> > +  namespace __closure
> >{
> > +// The base class of every range adaptor closure.
> > +//
> > +// The derived class should define the optional static data member
> > +// _S_has_simple_call_op to true if the behavior of this adaptor is
> > +// independent of the constness/value category of the adaptor object.
> > +template
> > +  struct _RangeAdaptorClosure
> > +  { };
> > +
> > +template
> > +  requires (!same_as<_Tp, _RangeAdaptorClosure<_Up>>)
> > +  void __is_range_adaptor_closure_fn
> > + (const _Tp&, const _RangeAdaptorClosure<_Up>&); // not defined
> > +
> > +template
> > +  concept __is_range_adaptor_closure
> > + = requires (_Tp __t) { __closure::__is_range_adaptor_closure_fn(__t, 
> > __t); };
> > +
> >  // range | adaptor is equivalent to adaptor(range).
> >  template
> > -  requires derived_from, _RangeAdaptorClosure>
> > +  requires __is_range_adaptor_closure<_Self>
> >   && __adaptor_invocable<_Self, _Range>
> > -  friend constexpr auto
> > +  constexpr auto
> >operator|(_Range&& __r, _Self&& __self)
> >{ return std::forward<_Self>(__self)(std::forward<_Range>(__r)); }
> >
> >  // Compose the adaptors __lhs and __rhs into a pipeline, returning
> >  // another range adaptor closure object.
> >  template
> > -  

Re: [PATCH] libstdc++: Implement P2770R0 changes to join_view / join_with_view

2023-08-16 Thread Patrick Palka via Gcc-patches
On Mon, Apr 17, 2023 at 9:39 AM Patrick Palka  wrote:
>
> This C++23 paper fixes a bug in these views when adapting a certain kind
> of non-forward range, and we treat it as a DR against C++20.
>
> Tested on x86_64-pc-linux-gnu, does this look OK for GCC 13?  This
> is an ABI change for join_view so it'd be unsuitable for backporting
> later I think :(

Ping, does this look OK for trunk?

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/regex.h (regex_iterator::iterator_concept):
> Define for C++20 as per P2770R0.
> (regex_token_iterator::iterator_concept): Likewise.
> * include/std/ranges (__detail::__as_lvalue): Define.
> (join_view::_Iterator): Befriend join_view.
> (join_view::_Iterator::_M_satisfy): Use _M_get_outer
> instead of _M_outer.
> (join_view::_Iterator::_M_get_outer): Define.
> (join_view::_Iterator::_Iterator): Split constructor taking
> _Parent argument into two as per P2770R0.  Remove constraint on
> default constructor.
> (join_view::_Iterator::_M_outer): Make this data member present
> only when the underlying range is forward.
> (join_view::_Iterator::operator++): Use _M_get_outer instead of
> _M_outer.
> (join_view::_Iterator::operator--): Use __as_lvalue helper.
> (join_view::_Iterator::operator==): Adjust constraints as per
> P2770R0.
> (join_view::_Sentinel::__equal): Use _M_get_outer instead of
> _M_outer.
> (join_view::_M_outer): New data member when the underlying range
> is non-forward.
> (join_view::begin): Adjust definition as per P2770R0.
> (join_view::end): Likewise.
> (join_with_view::_M_outer_it): New data member when the
> underlying range is non-forward.
> (join_with_view::begin): Adjust definition as per P2770R0.
> (join_with_view::end): Likewise.
> (join_with_view::_Iterator::_M_outer_it): Make this data member
> present only when the underlying range is forward.
> (join_with_view::_Iterator::_M_get_outer): Define.
> (join_with_view::_Iterator::_Iterator): Split constructor
> taking _Parent argument into two as per P2770R0.  Remove
> constraint on default constructor.
> (join_with_view::_Iterator::_M_update_inner): Adjust definition
> as per P2770R0.
> (join_with_view::_Iterator::_M_get_inner): Likewise.
> (join_with_view::_Iterator::_M_satisfy): Adjust calls to
> _M_get_inner.  Use _M_get_outer instead of _M_outer_it.
> (join_with_view::_Iterator::operator==): Adjust constraints
> as per P2770R0.
> (join_with_view::_Sentinel::operator==): Use _M_get_outer
> instead of _M_outer_it.
> * testsuite/std/ranges/adaptors/p2770r0.cc: New test.
> ---
>  libstdc++-v3/include/bits/regex.h |   6 +
>  libstdc++-v3/include/std/ranges   | 190 +-
>  .../testsuite/std/ranges/adaptors/p2770r0.cc  | 110 ++
>  3 files changed, 257 insertions(+), 49 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc
>
> diff --git a/libstdc++-v3/include/bits/regex.h 
> b/libstdc++-v3/include/bits/regex.h
> index 26ac6a21c31..2d306868721 100644
> --- a/libstdc++-v3/include/bits/regex.h
> +++ b/libstdc++-v3/include/bits/regex.h
> @@ -2740,6 +2740,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>typedef const value_type*  pointer;
>typedef const value_type&  reference;
>typedef std::forward_iterator_tag  iterator_category;
> +#if __cplusplus > 201703L
> +  typedef std::input_iterator_tagiterator_concept;
> +#endif
>
>/**
> * @brief Provides a singular iterator, useful for indicating
> @@ -2869,6 +2872,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>typedef const value_type*pointer;
>typedef const value_type&reference;
>typedef std::forward_iterator_tagiterator_category;
> +#if __cplusplus > 201703L
> +  typedef std::input_iterator_tag  iterator_concept;
> +#endif
>
>  public:
>/**
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 283d757faa4..ddcf50cc93e 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -2705,6 +2705,14 @@ namespace views::__adaptor
>  inline constexpr _DropWhile drop_while;
>} // namespace views
>
> +  namespace __detail
> +  {
> +template
> +  constexpr _Tp&
> +  __as_lvalue(_Tp&& __t)
> +  { return static_cast<_Tp&>(__t); }
> +  } // namespace __detail
> +
>template
>  requires view<_Vp> && input_range>
>  class join_view : public view_interface>
> @@ -2767,6 +2775,8 @@ namespace views::__adaptor
>   using _Parent = __detail::__maybe_const_t<_Const, join_view>;
> 

[PATCH] tree-pretty-print: delimit TREE_VEC with braces

2023-08-11 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

This makes the generic pretty printer print braces around a TREE_VEC
like we do for CONSTRUCTOR.  This should improve readability of nested
TREE_VECs in particular.

gcc/ChangeLog:

* tree-pretty-print.cc (dump_generic_node) :
Delimit output with braces.
---
 gcc/tree-pretty-print.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 51a213529d1..579037b32c2 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1900,6 +1900,7 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
 case TREE_VEC:
   {
size_t i;
+   pp_left_brace (pp);
if (TREE_VEC_LENGTH (node) > 0)
  {
size_t len = TREE_VEC_LENGTH (node);
@@ -1913,6 +1914,7 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
dump_generic_node (pp, TREE_VEC_ELT (node, len - 1), spc,
   flags, false);
  }
+   pp_right_brace (pp);
   }
   break;
 
-- 
2.42.0.rc1



Re: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-11 Thread Patrick Palka via Gcc-patches
On Thu, 10 Aug 2023, Jason Merrill wrote:

> On 8/10/23 16:40, Patrick Palka wrote:
> > On Thu, 10 Aug 2023, Jason Merrill wrote:
> > 
> > > On 8/10/23 12:09, Patrick Palka wrote:
> > > > Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> > > > for
> > > > trunk and perhaps 13?
> > > > 
> > > > -- >8 --
> > > > 
> > > > We shouldn't issue a "declared static but never defined" warning
> > > > for a deduction guide (declared in an anonymous namespace).
> > > > 
> > > > PR c++/106604
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > > * decl.cc (wrapup_namespace_globals): Don't issue a
> > > > -Wunused-function warning for a deduction guide.
> > > 
> > > Maybe instead of special casing this here we could set DECL_INITIAL on
> > > deduction guides so they look defined?
> > 
> > That seems to work, but it requires some tweaks in duplicate_decls to keep
> > saying "declared" instead of "defined" when diagnosing a deduction guide
> > redeclaration.  I'm not sure which approach is preferable?
> 
> I'm not sure it matters which we say; the restriction that you can't repeat a
> deduction guide makes it more like a definition anyway (even if [basic.def]
> disagrees).  Is the diagnostic worse apart from that word?

Ah, makes sense.  So we can also remove the special case for them in the
redeclaration checking code after we give them a dummy DECL_INITIAL.
Like so?

Here's a before/after for the diagnostic with the below patch:

Before

src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:11:1: error: deduction guide 
‘S()-> S’ redeclared
   11 | S() -> S; // { dg-error "redefinition" }
  | ^
src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:10:1: note: ‘S()-> S’ 
previously declared here
   10 | S() -> S; // { dg-message "previously defined here|old 
declaration" }
  | ^

After

src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:11:1: error: redefinition of 
‘S()-> S’
   11 | S() -> S; // { dg-error "redefinition" }
  | ^
src/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C:10:1: note: ‘S()-> S’ 
previously defined here
   10 | S() -> S; // { dg-message "previously defined here|old 
declaration" }
  | ^

-- >8 --

Subject: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

Here we're unintentionally issuing a "declared static but never defined"
warning for a deduction guide declared in an anonymous namespace.
This patch fixes this by giving deduction guides a dummy DECL_INITIAL,
which suppresses the warning and also allows us to simplify redeclaration
checking for them.

Co-authored-by: Jason Merrill 

PR c++/106604

gcc/cp/ChangeLog:

* decl.cc (redeclaration_error_message): Remove special handling
for deduction guides.
(grokfndecl): Give deduction guides a dummy DECL_INITIAL.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction74.C: Expect "defined" instead
of "declared" in diagnostics for a repeated deduction guide.
* g++.dg/cpp1z/class-deduction116.C: New test.
---
 gcc/cp/decl.cc  | 14 ++
 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C |  8 
 gcc/testsuite/g++.dg/cpp1z/class-deduction74.C  | 14 +++---
 3 files changed, 21 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 792ab330dd0..3ada5516c58 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3297,10 +3297,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* [class.compare.default]: A definition of a comparison operator as
 defaulted that appears in a class shall be the first declaration of
 that function.  */
@@ -3355,10 +3351,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* Core issue #226 (C++11):
 
If a friend function template declaration specifies a
@@ -10352,6 +10344,12 @@ grokfndecl (tree ctype,
   DECL_CXX_DESTRUCTOR_P (decl) = 1;
   DECL_NAME (decl) = dtor_identifier;
   break;
+case sfk_deduction_guide:
+  /* Give deduction guides a definition even though they don't really
+have one: the restriction that you can't repeat a deduction guide
+makes them more like a definition anyway.  */
+  DECL_INITIAL (decl) = void_node;
+  break;
 default:
   break;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR 

Re: [PATCH] c++: improve debug_tree for templated types/decls

2023-08-10 Thread Patrick Palka via Gcc-patches
On Tue, 8 Aug 2023, Jason Merrill wrote:

> On 7/31/23 20:34, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> > 
> > -- >8 --
> > 
> > gcc/cp/ChangeLog:
> > 
> > * ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
> > TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
> > for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
> > Also print DECL_USE_TEMPLATE.
> > (cxx_print_type): Print TYPE_TEMPLATE_INFO.
> > : Don't print TYPE_TI_ARGS
> > anymore.
> > : Print TEMPLATE_TYPE_PARM_INDEX
> > instead of printing the index, level and original level
> > individually.
> > ---
> >   gcc/cp/ptree.cc | 32 +---
> >   1 file changed, 17 insertions(+), 15 deletions(-)
> > 
> > diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
> > index 33af7b81f58..13306fc8762 100644
> > --- a/gcc/cp/ptree.cc
> > +++ b/gcc/cp/ptree.cc
> > @@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > return;
> >   }
> >   -  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
> > -  || !DECL_LANG_SPECIFIC (node))
> > -return;
> > -
> > if (TREE_CODE (node) == FUNCTION_DECL)
> >   {
> > int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
> > @@ -106,7 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > need_indent = false;
> >   }
> >   -  if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
> > +  if (CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
> > +  && DECL_LANG_SPECIFIC (node)
> > +  && DECL_EXTERNAL (node)
> > +  && DECL_NOT_REALLY_EXTERN (node))
> >   {
> > if (need_indent)
> > indent_to (file, indent + 3);
> > @@ -115,6 +114,7 @@ cxx_print_decl (FILE *file, tree node, int indent)
> >   }
> >   if (TREE_CODE (node) == FUNCTION_DECL
> > +  && DECL_LANG_SPECIFIC (node)
> > && DECL_PENDING_INLINE_INFO (node))
> >   {
> > if (need_indent)
> > @@ -124,27 +124,29 @@ cxx_print_decl (FILE *file, tree node, int indent)
> > need_indent = false;
> >   }
> > -  if (VAR_OR_FUNCTION_DECL_P (node)
> > +  if (DECL_LANG_SPECIFIC (node)
> 
> Hmm, won't this crash on a non-COMMON decl?

Oops yes, I overlooked that DECL_LANG_SPECIFIC requires DECL_COMMON.  So
we should just move the early exit test down a bit.

> 
> > && DECL_TEMPLATE_INFO (node))

We also need to constrain the kinds of decls that we test
DECL_TEMPLATE_INFO on according to template_info_decl_check.

-- >8 --

Subject: [PATCH] c++: improve debug_tree for templated types/decls

gcc/cp/ChangeLog:

* ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
Also print DECL_USE_TEMPLATE.
(cxx_print_type): Print TYPE_TEMPLATE_INFO.
: Don't print TYPE_TI_ARGS
anymore.
: Print TEMPLATE_TYPE_PARM_INDEX
instead of printing the index, level and original level
individually.
---
 gcc/cp/ptree.cc | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
index 33af7b81f58..b4001486701 100644
--- a/gcc/cp/ptree.cc
+++ b/gcc/cp/ptree.cc
@@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
   return;
 }
 
-  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
-  || !DECL_LANG_SPECIFIC (node))
-return;
-
   if (TREE_CODE (node) == FUNCTION_DECL)
 {
   int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
@@ -106,6 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
 
+  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
+  || !DECL_LANG_SPECIFIC (node))
+return;
+
   if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
 {
   if (need_indent)
@@ -124,27 +124,33 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
   
-  if (VAR_OR_FUNCTION_DECL_P (node)
+  if ((VAR_OR_FUNCTION_DECL_P (node)
+   || TREE_CODE (node) == FIELD_DECL
+   || TREE_CODE (node) == TYPE_DECL
+   || TREE_CODE (node) == CONCEPT_DECL
+   || TREE_CODE (node) == TEMPLATE_DECL)
   && DECL_TEMPLATE_INFO (node))
-print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
-   indent + 4);
+{
+  print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
+ indent + 4);
+  indent_to (file, indent + 3);
+  fprintf (file, " use_template=%d", DECL_USE_TEMPLATE (node));
+}
 }
 
 void
 cxx_print_type (FILE *file, tree node, int indent)
 {
+  if (TYPE_LANG_SPECIFIC (node)
+  && TYPE_TEMPLATE_INFO (node))
+print_node (file, "template-info", TYPE_TEMPLATE_INFO (node), indent + 4);
+
   switch (TREE_CODE (node))
 {
 

Re: [PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-10 Thread Patrick Palka via Gcc-patches
On Thu, 10 Aug 2023, Jason Merrill wrote:

> On 8/10/23 12:09, Patrick Palka wrote:
> > Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk and perhaps 13?
> > 
> > -- >8 --
> > 
> > We shouldn't issue a "declared static but never defined" warning
> > for a deduction guide (declared in an anonymous namespace).
> > 
> > PR c++/106604
> > 
> > gcc/cp/ChangeLog:
> > 
> > * decl.cc (wrapup_namespace_globals): Don't issue a
> > -Wunused-function warning for a deduction guide.
> 
> Maybe instead of special casing this here we could set DECL_INITIAL on
> deduction guides so they look defined?

That seems to work, but it requires some tweaks in duplicate_decls to keep
saying "declared" instead of "defined" when diagnosing a deduction guide
redeclaration.  I'm not sure which approach is preferable?

-- >8 --

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): When diagnosing a redeclared
deduction guide, ensure we say "declared" instead of "defined".
(redeclaration_error_message): Move up deduction guide tests.
(grokfndecl): Set DECL_INITIAL to void_node for a deduction
guide.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction116.C: New test.
---
 gcc/cp/decl.cc| 23 +++
 .../g++.dg/cpp1z/class-deduction116.C |  5 
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 2b3fb313166..70dcff7aa8c 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2025,7 +2025,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
  error_at (newdecl_loc, errmsg, newdecl);
  if (DECL_NAME (olddecl) != NULL_TREE)
inform (olddecl_loc,
-   (DECL_INITIAL (olddecl) && namespace_bindings_p ())
+   (DECL_INITIAL (olddecl)
+&& !deduction_guide_p (olddecl)
+&& namespace_bindings_p ())
? G_("%q#D previously defined here")
: G_("%q#D previously declared here"), olddecl);
  return error_mark_node;
@@ -3271,6 +3273,10 @@ redeclaration_error_message (tree newdecl, tree olddecl)
   /* We'll complain about linkage mismatches in
 warn_extern_redeclared_static.  */
 
+  if (deduction_guide_p (olddecl)
+ && deduction_guide_p (newdecl))
+   return G_("deduction guide %q+D redeclared");
+
   /* Defining the same name twice is no good.  */
   if (decl_defined_p (olddecl)
  && decl_defined_p (newdecl))
@@ -3298,10 +3304,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* [class.compare.default]: A definition of a comparison operator as
 defaulted that appears in a class shall be the first declaration of
 that function.  */
@@ -3330,6 +3332,10 @@ redeclaration_error_message (tree newdecl, tree olddecl)
   if (DECL_TEMPLATE_RESULT (newdecl) == DECL_TEMPLATE_RESULT (olddecl))
return NULL;
 
+  if (deduction_guide_p (olddecl)
+ && deduction_guide_p (newdecl))
+   return G_("deduction guide %q+D redeclared");
+
   nt = DECL_TEMPLATE_RESULT (newdecl);
   if (DECL_TEMPLATE_INFO (nt))
nt = DECL_TEMPLATE_RESULT (template_for_substitution (nt));
@@ -3356,10 +3362,6 @@ redeclaration_error_message (tree newdecl, tree olddecl)
}
}
 
-  if (deduction_guide_p (olddecl)
- && deduction_guide_p (newdecl))
-   return G_("deduction guide %q+D redeclared");
-
   /* Core issue #226 (C++11):
 
If a friend function template declaration specifies a
@@ -10353,6 +10355,9 @@ grokfndecl (tree ctype,
   DECL_CXX_DESTRUCTOR_P (decl) = 1;
   DECL_NAME (decl) = dtor_identifier;
   break;
+case sfk_deduction_guide:
+  DECL_INITIAL (decl) = void_node;
+  break;
 default:
   break;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR c++/106604
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wunused-function" }
+
+namespace {
+  template struct A { A(...); };
+  A(bool) -> A; // { dg-bogus "never defined" }
+}
-- 
2.42.0.rc1


> 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/cpp1z/class-deduction116.C: New test.
> > ---
> >   gcc/cp/decl.cc  | 1 +
> >   gcc/testsuite/g++.dg/cpp1z/class-deduction116.C | 8 
> >   2 files changed, 9 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
> > 
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 

[PATCH] c++: bogus warning w/ deduction guide in anon ns [PR106604]

2023-08-10 Thread Patrick Palka via Gcc-patches
Booststrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk and perhaps 13?

-- >8 --

We shouldn't issue a "declared static but never defined" warning
for a deduction guide (declared in an anonymous namespace).

PR c++/106604

gcc/cp/ChangeLog:

* decl.cc (wrapup_namespace_globals): Don't issue a
-Wunused-function warning for a deduction guide.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction116.C: New test.
---
 gcc/cp/decl.cc  | 1 +
 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C | 8 
 2 files changed, 9 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction116.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 792ab330dd0..9fe3a0b98fd 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -856,6 +856,7 @@ wrapup_namespace_globals ()
  && !TREE_PUBLIC (decl)
  && !DECL_ARTIFICIAL (decl)
  && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)
+ && !deduction_guide_p (decl)
  && !warning_suppressed_p (decl, OPT_Wunused_function))
warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wunused_function,
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C 
b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
new file mode 100644
index 000..00f6d5fef41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C
@@ -0,0 +1,8 @@
+// PR c++/106604
+// { dg-do compile { target c++17 } }
+// { dg-additional-options "-Wunused-function" }
+
+namespace {
+  template struct A { A(...); };
+  A(bool) -> A; // { dg-bogus "never defined" }
+}
-- 
2.42.0.rc0.25.ga82fb66fed



[PATCH] c++: recognize in-class var tmpl partial spec [PR71954]

2023-08-10 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

-- >8 --

This makes us recognize variable template partial specializations
defined directly inside the class body.  It seems to suffice to call
check_explicit_specialization when we see a static TEMPLATE_ID_EXPR data
member, which sets SET_DECL_TEMPLATE_SPECIALIZATION and which we
otherwise don't call (for out-of-class partial specializations we call
it from from grokvardecl which is used only for out-of-class definitions).
We also need to make finish_member_template_decl return NULL_TREE for
such partial specializations (matching its behavior class template
partial specializations) so that its caller doesn't try to call
finish_member_declaration on it.

PR c++/71954

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Use 'dname' instead of
'unqualified_id' when building the VAR_DECL for a static data
member.  Call check_explicit_specialization for a
TEMPLATE_ID_EXPR such member.
* pt.cc (finish_member_template_decl): Return NULL_TREE
instead of 'decl' when DECL_TEMPLATE_SPECIALIZATION is not
set.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/var-templ84.C: New test.
* g++.dg/cpp1y/var-templ84a.C: New test.
---
 gcc/cp/decl.cc| 11 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/var-templ84.C  | 12 
 gcc/testsuite/g++.dg/cpp1y/var-templ84a.C | 19 +++
 4 files changed, 42 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ84.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ84a.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9fe3a0b98fd..2b3fb313166 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -14440,7 +14440,16 @@ grokdeclarator (const cp_declarator *declarator,
/* C++ allows static class members.  All other work
   for this is done by grokfield.  */
decl = build_lang_decl_loc (id_loc, VAR_DECL,
-   unqualified_id, type);
+   dname, type);
+   if (unqualified_id
+   && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
+ {
+   decl = check_explicit_specialization (unqualified_id, decl,
+ template_count,
+ concept_p * 8);
+   if (decl == error_mark_node)
+ return error_mark_node;
+ }
set_linkage_for_static_data_member (decl);
if (concept_p)
  error_at (declspecs->locations[ds_concept],
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2706fa619bf..a4809f034dc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -314,7 +314,7 @@ finish_member_template_decl (tree decl)
  return DECL_TI_TEMPLATE (decl);
}
   else
-   return decl;
+   return NULL_TREE;
 }
   else
 error_at (DECL_SOURCE_LOCATION (decl),
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C
new file mode 100644
index 000..39c2a0dc0cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C
@@ -0,0 +1,12 @@
+// PR c++/71954
+// { dg-do compile { target c++14 } }
+
+struct A {
+  template static const int var = 0;
+  template static const int var = 1;
+  template static const int var = 2;
+};
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 1, "");
+static_assert(A::var == 2, "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C
new file mode 100644
index 000..4aa3a2a7245
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C
@@ -0,0 +1,19 @@
+// PR c++/71954
+// A version of var-templ84.C where the partial specializations depend on
+// outer template parameters.
+// { dg-do compile { target c++14 } }
+
+template
+struct A {
+  template static const int var = 0;
+  template static const int var = 1;
+  template static const int var = 2;
+};
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 1, "");
+static_assert(A::var == 2, "");
+
+static_assert(A::var == 0, "");
+static_assert(A::var == 0, "");
+static_assert(A::var == 0, "");
-- 
2.42.0.rc0.25.ga82fb66fed



[PATCH] c++: dependently scoped template-id in type-req [PR110927]

2023-08-10 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk and perhaps 13?

-- >8 --

Here we're incorrectly rejecting the first type-requirement at parse
time with

  concepts-requires35.C:14:56: error: ‘typename A::B’ is not a template 
[-fpermissive]

We also incorrectly reject the second type-requirement at satisfaction time
with

  concepts-requires35.C:17:34: error: ‘typename A::B’ names 
‘template struct A::B’, which is not a type

and similarly for the third type-requirement.  This seems to happen only
within a type-requirement; if we instead use e.g. an alias template then
it works as expected.

The difference ultimately seems to be that during parsing of a
using-declaration, we pass check_dependency_p=true to
cp_parser_nested_name_specifier_opt whereas during parsing of a
type-requirement we pass check_dependency_p=false.  Passing =false causes
cp_parser_template_id for the dependently-scoped template-id B to
return a TYPE_DECL of TYPENAME_TYPE (sometimes with TYPENAME_IS_CLASS_P
unexpectedly set for the last two type-requirements) whereas passing
=true causes it to return a TEMPLATE_ID_EXPR.

The simplest fix therefore seems to be to pass check_dependency_p=true
from cp_parser_type_requirement, matching the behavior of
cp_parser_elaborated_type_specifier.

PR c++/110927

gcc/cp/ChangeLog:

* parser.cc (cp_parser_type_requirement): Pass
check_dependency_p=true instead of =false.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-requires35.C: New test.
---
 gcc/cp/parser.cc  |  4 +--
 .../g++.dg/cpp2a/concepts-requires35.C| 28 +++
 2 files changed, 30 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 589ac879c6d..2d27376d988 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -30977,7 +30977,7 @@ cp_parser_type_requirement (cp_parser *parser)
   cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
   cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
-   /*check_dependency_p=*/false,
+  /*check_dependency_p=*/true,
/*type_p=*/true,
/*is_declaration=*/false);
 
@@ -30987,7 +30987,7 @@ cp_parser_type_requirement (cp_parser *parser)
   cp_lexer_consume_token (parser->lexer);
   type = cp_parser_template_id (parser,
 /*template_keyword_p=*/true,
-/*check_dependency=*/false,
+   /*check_dependency_p=*/true,
 /*tag_type=*/none_type,
 /*is_declaration=*/false);
   type = make_typename_type (parser->scope, type, typename_type,
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C
new file mode 100644
index 000..1dad931c01a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C
@@ -0,0 +1,28 @@
+// PR c++/110927
+// { dg-do compile { target c++20 } }
+
+template
+struct A {
+  template struct B { using type = B; };
+
+  template using type = U;
+};
+
+template<> struct A { };
+
+template
+concept C1 = requires { typename A::template B::type; };
+
+template
+concept C2 = requires { typename A::template B; };
+
+template
+concept C3 = requires { typename A::template type; };
+
+static_assert(C1);
+static_assert(C2);
+static_assert(C3);
+
+static_assert(!C1);
+static_assert(!C2);
+static_assert(!C3);
-- 
2.42.0.rc0.25.ga82fb66fed



Re: [PATCH 04/14] c++: use _P() defines from tree.h

2023-08-02 Thread Patrick Palka via Gcc-patches
On Thu, Jun 1, 2023 at 2:11 PM Bernhard Reutner-Fischer
 wrote:
>
> Hi David, Patrick,
>
> On Thu, 1 Jun 2023 18:33:46 +0200
> Bernhard Reutner-Fischer  wrote:
>
> > On Thu, 1 Jun 2023 11:24:06 -0400
> > Patrick Palka  wrote:
> >
> > > On Sat, May 13, 2023 at 7:26 PM Bernhard Reutner-Fischer via
> > > Gcc-patches  wrote:
> >
> > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> > > > index 131b212ff73..19dfb3ed782 100644
> > > > --- a/gcc/cp/tree.cc
> > > > +++ b/gcc/cp/tree.cc
> > > > @@ -1173,7 +1173,7 @@ build_cplus_array_type (tree elt_type, tree 
> > > > index_type, int dependent)
> > > >  }
> > > >
> > > >/* Avoid spurious warnings with VLAs (c++/54583).  */
> > > > -  if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t)))
> > > > +  if (CAN_HAVE_LOCATION_P (TYPE_SIZE (t)))
> > >
> > > Hmm, this change seems undesirable...
> >
> > mhm, yes that is misleading. I'll prepare a patch to revert this.
> > Let me have a look if there were other such CAN_HAVE_LOCATION_P changes
> > that we'd want to revert.
>
> Sorry for that!
> I'd revert the hunk above and the one in gcc-rich-location.cc
> (maybe_range_label_for_tree_type_mismatch::get_text), please see
> attached. Bootstrap running, ok for trunk if it passes?

LGTM!

>
> thanks,



Re: [PATCH v3 2/2] libstdc++: Use _GLIBCXX_HAS_BUILTIN_TRAIT

2023-08-01 Thread Patrick Palka via Gcc-patches
On Thu, 27 Jul 2023, Ken Matsui via Gcc-patches wrote:

> This patch uses _GLIBCXX_HAS_BUILTIN_TRAIT macro instead of
> __has_builtin in the type_traits header. This macro supports to toggle
> the use of built-in traits in the type_traits header through
> _GLIBCXX_NO_BUILTIN_TRAITS macro, without needing to modify the
> source code.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (__has_builtin): Replace with ...
>   (_GLIBCXX_HAS_BUILTIN): ... this.
> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 26 +-
>  1 file changed, 13 insertions(+), 13 deletions(-)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 9f086992ebc..12423361b6e 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  : public __bool_constant<__is_base_of(_Base, _Derived)>
>  { };
>  
> -#if __has_builtin(__is_convertible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_convertible)
>template
>  struct is_convertible
>  : public __bool_constant<__is_convertible(_From, _To)>
> @@ -1462,7 +1462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  #if __cplusplus >= 202002L
>  #define __cpp_lib_is_nothrow_convertible 201806L
>  
> -#if __has_builtin(__is_nothrow_convertible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_nothrow_convertible)
>/// is_nothrow_convertible_v
>template
>  inline constexpr bool is_nothrow_convertible_v
> @@ -1537,7 +1537,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { using type = _Tp; };
>  
>/// remove_cv
> -#if __has_builtin(__remove_cv)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_cv)
>template
>  struct remove_cv
>  { using type = __remove_cv(_Tp); };
> @@ -1606,7 +1606,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Reference transformations.
>  
>/// remove_reference
> -#if __has_builtin(__remove_reference)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_reference)
>template
>  struct remove_reference
>  { using type = __remove_reference(_Tp); };
> @@ -2963,7 +2963,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template  bool _Nothrow = noexcept(_S_conv<_Tp>(_S_get())),
>  typename = decltype(_S_conv<_Tp>(_S_get())),
> -#if __has_builtin(__reference_converts_from_temporary)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__reference_converts_from_temporary)
>  bool _Dangle = __reference_converts_from_temporary(_Tp, _Res_t)
>  #else
>  bool _Dangle = false
> @@ -3420,7 +3420,7 @@ template
> */
>  #define __cpp_lib_remove_cvref 201711L
>  
> -#if __has_builtin(__remove_cvref)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__remove_cvref)
>template
>  struct remove_cvref
>  { using type = __remove_cvref(_Tp); };
> @@ -3515,7 +3515,7 @@ template
>  : public bool_constant>
>  { };
>  
> -#if __has_builtin(__is_layout_compatible)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_layout_compatible)

Hmm, I was thinking we'd use this macro only for traits that have a
fallback non-built-in implementation so that we could easily use/test
their fallback implementation.  For traits that don't have such a
fallback, using this macro would mean that trait would no longer get
defined at all, which doesn't seem as useful.  Perhaps let's initially
adjust only the traits that have a fallback implementation?

We could then verify that using the fallback implementation for all such
traits works as expected by running the testsuite with:

  make check RUNTESTFLAGS="conformance.exp 
--target_board=unix/-D_GLIBCXX_NO_BUILTIN_TRAITS"

>  
>/// @since C++20
>template
> @@ -3529,7 +3529,7 @@ template
>  constexpr bool is_layout_compatible_v
>= __is_layout_compatible(_Tp, _Up);
>  
> -#if __has_builtin(__builtin_is_corresponding_member)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__builtin_is_corresponding_member)
>  #define __cpp_lib_is_layout_compatible 201907L
>  
>/// @since C++20
> @@ -3540,7 +3540,7 @@ template
>  #endif
>  #endif
>  
> -#if __has_builtin(__is_pointer_interconvertible_base_of)
> +#if _GLIBCXX_HAS_BUILTIN_TRAIT(__is_pointer_interconvertible_base_of)
>/// True if `_Derived` is standard-layout and has a base class of type 
> `_Base`
>/// @since C++20
>template
> @@ -3554,7 +3554,7 @@ template
>  constexpr bool is_pointer_interconvertible_base_of_v
>= __is_pointer_interconvertible_base_of(_Base, _Derived);
>  
> -#if __has_builtin(__builtin_is_pointer_interconvertible_with_class)
> +#if 
> _GLIBCXX_HAS_BUILTIN_TRAIT(__builtin_is_pointer_interconvertible_with_class)
>  #define __cpp_lib_is_pointer_interconvertible 201907L
>  
>/// True if `__mp` points to the first member of a standard-layout type
> @@ -3590,8 +3590,8 @@ template
>template
>  inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
>  
> -#if __has_builtin(__reference_constructs_from_temporary) \
> -  

[PATCH] c++: improve debug_tree for templated types/decls

2023-07-31 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

gcc/cp/ChangeLog:

* ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and
TS_DECL_COMMON only when necessary.  Print DECL_TEMPLATE_INFO
for all decls that have it, not just VAR_DECL or FUNCTION_DECL.
Also print DECL_USE_TEMPLATE.
(cxx_print_type): Print TYPE_TEMPLATE_INFO.
: Don't print TYPE_TI_ARGS
anymore.
: Print TEMPLATE_TYPE_PARM_INDEX
instead of printing the index, level and original level
individually.
---
 gcc/cp/ptree.cc | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc
index 33af7b81f58..13306fc8762 100644
--- a/gcc/cp/ptree.cc
+++ b/gcc/cp/ptree.cc
@@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent)
   return;
 }
 
-  if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
-  || !DECL_LANG_SPECIFIC (node))
-return;
-
   if (TREE_CODE (node) == FUNCTION_DECL)
 {
   int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
@@ -106,7 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
 
-  if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node))
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON)
+  && DECL_LANG_SPECIFIC (node)
+  && DECL_EXTERNAL (node)
+  && DECL_NOT_REALLY_EXTERN (node))
 {
   if (need_indent)
indent_to (file, indent + 3);
@@ -115,6 +114,7 @@ cxx_print_decl (FILE *file, tree node, int indent)
 }
 
   if (TREE_CODE (node) == FUNCTION_DECL
+  && DECL_LANG_SPECIFIC (node)
   && DECL_PENDING_INLINE_INFO (node))
 {
   if (need_indent)
@@ -124,27 +124,29 @@ cxx_print_decl (FILE *file, tree node, int indent)
   need_indent = false;
 }
   
-  if (VAR_OR_FUNCTION_DECL_P (node)
+  if (DECL_LANG_SPECIFIC (node)
   && DECL_TEMPLATE_INFO (node))
-print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
-   indent + 4);
+{
+  print_node (file, "template-info", DECL_TEMPLATE_INFO (node),
+ indent + 4);
+  indent_to (file, indent + 3);
+  fprintf (file, " use_template=%d", DECL_USE_TEMPLATE (node));
+}
 }
 
 void
 cxx_print_type (FILE *file, tree node, int indent)
 {
+  if (TYPE_LANG_SPECIFIC (node)
+  && TYPE_TEMPLATE_INFO (node))
+print_node (file, "template-info", TYPE_TEMPLATE_INFO (node), indent + 4);
+
   switch (TREE_CODE (node))
 {
 case BOUND_TEMPLATE_TEMPLATE_PARM:
-  print_node (file, "args", TYPE_TI_ARGS (node), indent + 4);
-  gcc_fallthrough ();
-
 case TEMPLATE_TYPE_PARM:
 case TEMPLATE_TEMPLATE_PARM:
-  indent_to (file, indent + 3);
-  fprintf (file, "index %d level %d orig_level %d",
-  TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node),
-  TEMPLATE_TYPE_ORIG_LEVEL (node));
+  print_node (file, "tpi", TEMPLATE_TYPE_PARM_INDEX (node), indent + 4);
   return;
 
 case FUNCTION_TYPE:
-- 
2.41.0.478.gee48e70a82



[PATCH] tree-pretty-print: handle COMPONENT_REF with non-decl RHS

2023-07-31 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

In the C++ front end, a COMPONENT_REF's second operand isn't always a
decl (at least at template parse time).  This patch makes the generic
pretty printer not ICE when printing such a COMPONENT_REF.

gcc/ChangeLog:

* tree-pretty-print.cc (dump_generic_node) :
Don't call component_ref_field_offset if the RHS isn't a decl.
---
 gcc/tree-pretty-print.cc | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 25d191b10fd..da8dd002a3b 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -2482,14 +2482,16 @@ dump_generic_node (pretty_printer *pp, tree node, int 
spc, dump_flags_t flags,
   if (op_prio (op0) < op_prio (node))
pp_right_paren (pp);
   pp_string (pp, str);
-  dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false);
-  op0 = component_ref_field_offset (node);
-  if (op0 && TREE_CODE (op0) != INTEGER_CST)
-   {
- pp_string (pp, "{off: ");
- dump_generic_node (pp, op0, spc, flags, false);
+  op1 = TREE_OPERAND (node, 1);
+  dump_generic_node (pp, op1, spc, flags, false);
+  if (DECL_P (op1))
+   if (tree off = component_ref_field_offset (node))
+ if (TREE_CODE (off) != INTEGER_CST)
+   {
+ pp_string (pp, "{off: ");
+ dump_generic_node (pp, off, spc, flags, false);
  pp_right_brace (pp);
-   }
+   }
   break;
 
 case BIT_FIELD_REF:
-- 
2.41.0.478.gee48e70a82



[PATCH] c++: constexpr empty subobject confusion [PR110197]

2023-07-26 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13 (later)?

-- >8 --

Now that init_subob_ctx no longer sets new_ctx.ctor for a subobject of
empty type, it seems we need to ensure its callers cxx_eval_bare_aggregate
and cxx_eval_vec_init_1 consistently omit entries for such subobjects in
the parent ctx->ctor.  We also need to allow cxx_eval_array_reference
to synthesize an empty element object even if the array CONSTRUCTOR
has CONSTRUCTOR_NO_CLEARING set.

PR c++/110197

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_array_reference): Return a synthesized
empty subobject even if CONSTRUCTOR_NO_CLEARING is set.
(cxx_eval_bare_aggregate): Set 'no_slot' to true more generally
whenever new_ctx.ctor is empty, i.e. for any subobject of empty
type.
(cxx_eval_vec_init_1): Define 'no_slot' as above and use it
accordingly.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-empty18.C: New test.
* g++.dg/cpp0x/constexpr-empty19.C: New test.
---
 gcc/cp/constexpr.cc   | 23 +--
 .../g++.dg/cpp0x/constexpr-empty18.C  |  7 ++
 .../g++.dg/cpp0x/constexpr-empty19.C  | 12 ++
 3 files changed, 35 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f2fcb54626d..da2c3116810 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4297,6 +4297,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
 
   /* Not found.  */
 
+  if (is_really_empty_class (elem_type, /*ignore_vptr*/false))
+return build_constructor (elem_type, NULL);
+
   if (TREE_CODE (ary) == CONSTRUCTOR
   && CONSTRUCTOR_NO_CLEARING (ary))
 {
@@ -4314,9 +4317,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree 
t,
  directly for non-aggregates to avoid creating a garbage CONSTRUCTOR.  */
   tree val;
   constexpr_ctx new_ctx;
-  if (is_really_empty_class (elem_type, /*ignore_vptr*/false))
-return build_constructor (elem_type, NULL);
-  else if (CP_AGGREGATE_TYPE_P (elem_type))
+  if (CP_AGGREGATE_TYPE_P (elem_type))
 {
   tree empty_ctor = build_constructor (init_list_type_node, NULL);
   val = digest_init (elem_type, empty_ctor, tf_warning_or_error);
@@ -5095,9 +5096,9 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
   FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
 {
   tree orig_value = value;
-  /* Like in cxx_eval_store_expression, omit entries for empty fields.  */
-  bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index);
   init_subob_ctx (ctx, new_ctx, index, value);
+  /* Like in cxx_eval_store_expression, omit entries for empty fields.  */
+  bool no_slot = new_ctx.ctor == NULL_TREE;
   int pos_hint = -1;
   if (new_ctx.ctor != ctx->ctor && !no_slot)
{
@@ -5261,7 +5262,8 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree 
atype, tree init,
   bool reuse = false;
   constexpr_ctx new_ctx;
   init_subob_ctx (ctx, new_ctx, idx, pre_init ? init : elttype);
-  if (new_ctx.ctor != ctx->ctor)
+  bool no_slot = new_ctx.ctor == NULL_TREE;
+  if (new_ctx.ctor != ctx->ctor && !no_slot)
{
  if (zeroed_out)
CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = false;
@@ -5306,7 +5308,14 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree 
atype, tree init,
}
   if (*non_constant_p)
break;
-  if (new_ctx.ctor != ctx->ctor)
+  if (no_slot)
+   {
+ /* This is an initializer for an empty subobject; now that we've
+checked that it's constant, we can ignore it.  */
+ gcc_checking_assert (i == 0);
+ break;
+   }
+  else if (new_ctx.ctor != ctx->ctor)
{
  /* We appended this element above; update the value.  */
  gcc_assert ((*p)->last().index == idx);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
new file mode 100644
index 000..4bb9e3dcb64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty18.C
@@ -0,0 +1,7 @@
+// PR c++/110197
+// { dg-do compile { target c++11 } }
+
+struct A { constexpr A(int) { } };
+struct B { A a; };
+constexpr B f(int n) { return B{A{n}}; }
+constexpr B b = f(1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C
new file mode 100644
index 000..5ad67682c5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty19.C
@@ -0,0 +1,12 @@
+// PR c++/110197
+// { dg-do compile { target c++11 } }
+
+struct A {
+  constexpr A() : A(__builtin_is_constant_evaluated()) { }
+  constexpr A(int) { }
+};
+constexpr A a1[1] = {{}};
+constexpr A a2[2] = {{}, {}};
+constexpr A a3[3] = {{}, {}, 

[PATCH] c++: unifying REAL_CSTs [PR110809]

2023-07-26 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13 (after the branch is unfrozen)?

-- >8 --

This teaches unify how to compare two REAL_CSTs.

PR c++/110809

gcc/cp/ChangeLog:

* pt.cc (unify) : Generalize to handle
REAL_CST as well.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-float3.C: New test.
---
 gcc/cp/pt.cc|  5 +++--
 gcc/testsuite/g++.dg/cpp2a/nontype-float3.C | 12 
 2 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-float3.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d342ab5929a..1e09f304490 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24890,12 +24890,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
   /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
   /* Type INTEGER_CST can come from ordinary constant template args.  */
 case INTEGER_CST:
+case REAL_CST:
   while (CONVERT_EXPR_P (arg))
arg = TREE_OPERAND (arg, 0);
 
-  if (TREE_CODE (arg) != INTEGER_CST)
+  if (TREE_CODE (arg) != TREE_CODE (parm))
return unify_template_argument_mismatch (explain_p, parm, arg);
-  return (tree_int_cst_equal (parm, arg)
+  return (simple_cst_equal (parm, arg)
  ? unify_success (explain_p)
  : unify_template_argument_mismatch (explain_p, parm, arg));
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C 
b/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C
new file mode 100644
index 000..044fb99905a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-float3.C
@@ -0,0 +1,12 @@
+// PR c++/110809
+// { dg-do compile { target c++20 } }
+
+template struct A { };
+
+template void f(A);
+template void f(A);
+
+int main() {
+  f(A{});
+  f(A{}); // { dg-error "no match" }
+}
-- 
2.41.0.450.ga80be15292



Re: [PATCH 2/1] c++: passing partially inst ttp as ttp [PR110566]

2023-07-24 Thread Patrick Palka via Gcc-patches
On Fri, 21 Jul 2023, Jason Merrill wrote:

> On 7/21/23 14:34, Patrick Palka wrote:
> > (This is a follow-up of
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624951.html)
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, how does this look?
> > 
> > -- >8 --
> > 
> > The previous fix doesn't work for partially instantiated ttps primarily
> > because most_general_template doesn't work for them.  This patch fixes
> > this by giving such ttps a DECL_TEMPLATE_INFO (extending the
> > r11-734-g2fb595f8348e16 fix) with which we can obtain the original ttp.
> > 
> > This patch additionally makes us be more careful about using the correct
> > amount of levels from the scope of a ttp argument during
> > coerce_template_template_parms.
> > 
> > PR c++/110566
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO
> > on the DECL_TEMPLATE_RESULT of a reduced template template
> > parameter.
> > (add_defaults_to_ttp): Also update DECL_TEMPLATE_INFO of the
> > ttp's DECL_TEMPLATE_RESULT.
> > (coerce_template_template_parms): Make sure 'scope_args' has
> > the right amount of levels for the ttp argument.
> > (most_general_template): Handle template template parameters.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/ttp39.C: New test.
> > ---
> >   gcc/cp/pt.cc  | 46 ---
> >   gcc/testsuite/g++.dg/template/ttp39.C | 16 ++
> >   2 files changed, 57 insertions(+), 5 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp39.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index e0ed4bc8bbb..be7119dd9a0 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -4570,8 +4570,14 @@ reduce_template_parm_level (tree index, tree type,
> > int levels, tree args,
> >   TYPE_DECL, DECL_NAME (decl), type);
> >   DECL_TEMPLATE_RESULT (decl) = inner;
> >   DECL_ARTIFICIAL (inner) = true;
> > - DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms
> > -   (DECL_TEMPLATE_PARMS (orig_decl), args, complain);
> > + tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl),
> > + args, complain);
> > + DECL_TEMPLATE_PARMS (decl) = parms;
> > + retrofit_lang_decl (inner);
> > + tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl);
> > + DECL_TEMPLATE_INFO (inner)
> > +   = build_template_info (DECL_TI_TEMPLATE (orig_inner),
> > +  template_parms_to_args (parms));
> 
> Should we assert that orig_inner doesn't have its own DECL_TEMPLATE_INFO?  I'm
> wondering if it's possible to reduce the level of a TTP more than once.

It's possible for a ttp belonging to a nested generic lambda:

  template
  void f() {
[](auto) {
  [] class TT>() {
  };
}(0);
  }

  template void f();

> 
> > }
> >   /* Attach the TPI to the decl.  */
> > @@ -7936,6 +7942,19 @@ add_defaults_to_ttp (tree otmpl)
> > }
> >   }
> >   +  tree oresult = DECL_TEMPLATE_RESULT (otmpl);
> > +  tree gen_otmpl = DECL_TI_TEMPLATE (oresult);
> 
> Hmm, here we're assuming that all TTPs have DECL_TEMPLATE_INFO?

I figured it's a reasonable assumption since all "formal" ttps
originally start out with DECL_TEMPLATE_INFO (via process_template_parm).
Though I realized I missed adjusting rewrite_template_parm to set
DECL_TEMPLATE_INFO on the new ttp, which the below patch fixes (and
adds a testcase that we'd otherwise segfualt on).

> 
> > +  tree gen_ntmpl;
> > +  if (gen_otmpl == otmpl)
> > +gen_ntmpl = ntmpl;
> > +  else
> > +gen_ntmpl = add_defaults_to_ttp (gen_otmpl);
> > +
> > +  tree nresult = copy_node (oresult);

Another fixed bug: since we build the new DECL_TEMPLATE_RESULT via
copy_node, we need to avoid sharing its DECL_LANG_SPECIFIC with the
old decl.

> > +  DECL_TEMPLATE_INFO (nresult) = copy_node (DECL_TEMPLATE_INFO (oresult));
> > +  DECL_TI_TEMPLATE (nresult) = gen_ntmpl;
> > +  DECL_TEMPLATE_RESULT (ntmpl) = nresult;
> > +
> > hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl);
> > return ntmpl;
> >   }
> > @@ -8121,15 +8140,29 @@ coerce_template_template_parms (tree parm_tmpl,
> >  OUTER_ARGS are not the right outer levels in this case, as they are
> >  the args we're building up for PARM, and for the coercion we want the
> >  args for ARG.  If DECL_CONTEXT isn't set for a template template
> > -parameter, we can assume that it's in the current scope.  In that
> > case
> > -we might end up adding more levels than needed, but that shouldn't be
> > -a problem; any args we need to refer to are at the right level.  */
> > +parameter, we can assume that it's in the current scope.  */
> > tree ctx = DECL_CONTEXT (arg_tmpl);
> > if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
> > ctx = current_scope ();
> > tree scope_args = NULL_TREE;
> >  

Re: [PATCH] testsuite: Adjust g++.dg/gomp/pr58567.C to new compiler message

2023-07-24 Thread Patrick Palka via Gcc-patches
On Fri, Jul 21, 2023 at 5:29 PM Thiago Jung Bauermann
 wrote:
>
> Commit 92d1425ca780 "c++: redundant targ coercion for var/alias tmpls"
> changed the compiler error message in this testcase from
>
> : In instantiation of 'void foo() [with T = int]':
> :14:11:   required from here
> :8:22: error: 'int' is not a class, struct, or union type
> :8:22: error: 'int' is not a class, struct, or union type
> :8:22: error: 'int' is not a class, struct, or union type
> :8:3: error: expected iteration declaration or initialization
> compiler exited with status 1
>
> to:
>
> : In instantiation of 'void foo() [with T = int]':
> :14:11:   required from here
> :8:22: error: 'int' is not a class, struct, or union type
> :8:3: error: invalid type for iteration variable 'i'
> compiler exited with status 1
> Excess errors:
> :8:3: error: invalid type for iteration variable 'i'
>
> Andrew Pinski analysed the issue in PR 110756 and considered that it was a
> testsuite issue in that the error message changed slightly.  Also, it's a
> better error message.
>
> Therefore, we only need to adjust the testcase to expect the new message.

Thanks! I can't approve this patch but it looks good to me.


>
> gcc/testsuite/ChangeLog:
> PR testsuite/110756
> g++.dg/gomp/pr58567.C: Adjust to new compiler error message.
> ---
>  gcc/testsuite/g++.dg/gomp/pr58567.C | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gcc/testsuite/g++.dg/gomp/pr58567.C 
> b/gcc/testsuite/g++.dg/gomp/pr58567.C
> index 35a5bb027ffe..866d831c65e4 100644
> --- a/gcc/testsuite/g++.dg/gomp/pr58567.C
> +++ b/gcc/testsuite/g++.dg/gomp/pr58567.C
> @@ -5,7 +5,7 @@
>  template void foo()
>  {
>#pragma omp parallel for
> -  for (typename T::X i = 0; i < 100; ++i)  /* { dg-error "'int' is not a 
> class, struct, or union type|expected iteration declaration or 
> initialization" } */
> +  for (typename T::X i = 0; i < 100; ++i)  /* { dg-error "'int' is not a 
> class, struct, or union type|invalid type for iteration variable 'i'" } */
>  ;
>  }
>
>



[PATCH 2/1] c++: passing partially inst ttp as ttp [PR110566]

2023-07-21 Thread Patrick Palka via Gcc-patches
(This is a follow-up of
https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624951.html)

Bootstrapped and regtested on x86_64-pc-linux-gnu, how does this look?

-- >8 --

The previous fix doesn't work for partially instantiated ttps primarily
because most_general_template doesn't work for them.  This patch fixes
this by giving such ttps a DECL_TEMPLATE_INFO (extending the
r11-734-g2fb595f8348e16 fix) with which we can obtain the original ttp.

This patch additionally makes us be more careful about using the correct
amount of levels from the scope of a ttp argument during
coerce_template_template_parms.

PR c++/110566

gcc/cp/ChangeLog:

* pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO
on the DECL_TEMPLATE_RESULT of a reduced template template
parameter.
(add_defaults_to_ttp): Also update DECL_TEMPLATE_INFO of the
ttp's DECL_TEMPLATE_RESULT.
(coerce_template_template_parms): Make sure 'scope_args' has
the right amount of levels for the ttp argument.
(most_general_template): Handle template template parameters.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp39.C: New test.
---
 gcc/cp/pt.cc  | 46 ---
 gcc/testsuite/g++.dg/template/ttp39.C | 16 ++
 2 files changed, 57 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp39.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e0ed4bc8bbb..be7119dd9a0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4570,8 +4570,14 @@ reduce_template_parm_level (tree index, tree type, int 
levels, tree args,
  TYPE_DECL, DECL_NAME (decl), type);
  DECL_TEMPLATE_RESULT (decl) = inner;
  DECL_ARTIFICIAL (inner) = true;
- DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms
-   (DECL_TEMPLATE_PARMS (orig_decl), args, complain);
+ tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl),
+ args, complain);
+ DECL_TEMPLATE_PARMS (decl) = parms;
+ retrofit_lang_decl (inner);
+ tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl);
+ DECL_TEMPLATE_INFO (inner)
+   = build_template_info (DECL_TI_TEMPLATE (orig_inner),
+  template_parms_to_args (parms));
}
 
   /* Attach the TPI to the decl.  */
@@ -7936,6 +7942,19 @@ add_defaults_to_ttp (tree otmpl)
}
 }
 
+  tree oresult = DECL_TEMPLATE_RESULT (otmpl);
+  tree gen_otmpl = DECL_TI_TEMPLATE (oresult);
+  tree gen_ntmpl;
+  if (gen_otmpl == otmpl)
+gen_ntmpl = ntmpl;
+  else
+gen_ntmpl = add_defaults_to_ttp (gen_otmpl);
+
+  tree nresult = copy_node (oresult);
+  DECL_TEMPLATE_INFO (nresult) = copy_node (DECL_TEMPLATE_INFO (oresult));
+  DECL_TI_TEMPLATE (nresult) = gen_ntmpl;
+  DECL_TEMPLATE_RESULT (ntmpl) = nresult;
+
   hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl);
   return ntmpl;
 }
@@ -8121,15 +8140,29 @@ coerce_template_template_parms (tree parm_tmpl,
 OUTER_ARGS are not the right outer levels in this case, as they are
 the args we're building up for PARM, and for the coercion we want the
 args for ARG.  If DECL_CONTEXT isn't set for a template template
-parameter, we can assume that it's in the current scope.  In that case
-we might end up adding more levels than needed, but that shouldn't be
-a problem; any args we need to refer to are at the right level.  */
+parameter, we can assume that it's in the current scope.  */
   tree ctx = DECL_CONTEXT (arg_tmpl);
   if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
ctx = current_scope ();
   tree scope_args = NULL_TREE;
   if (tree tinfo = get_template_info (ctx))
scope_args = TI_ARGS (tinfo);
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
+   {
+ int level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (gen_arg_tmpl));
+ int scope_depth = TMPL_ARGS_DEPTH (scope_args);
+ if (scope_depth >= level)
+   /* Only use as many levels from the scope as needed (not
+  including the level of ARG).  */
+   scope_args = strip_innermost_template_args
+ (scope_args, scope_depth - (level - 1));
+
+ /* Add the arguments that appear at the level of ARG.  */
+ tree adj_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (arg_tmpl));
+ adj_args = TMPL_ARGS_LEVEL (adj_args, TMPL_ARGS_DEPTH (adj_args) - 1);
+ scope_args = add_to_template_args (scope_args, adj_args);
+   }
+
   pargs = add_to_template_args (scope_args, pargs);
 
   pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none);
@@ -25985,6 +26018,9 @@ most_general_template (tree decl)
return NULL_TREE;
 }
 
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (decl))
+return DECL_TI_TEMPLATE (DECL_TEMPLATE_RESULT (decl));
+
   /* Look for more 

Re: [PATCH v2] libstdc++: Define _GLIBCXX_HAS_BUILTIN_TRAIT

2023-07-20 Thread Patrick Palka via Gcc-patches
On Wed, Jul 19, 2023 at 3:33 PM Ken Matsui via Gcc-patches
 wrote:
>
> This patch defines _GLIBCXX_HAS_BUILTIN_TRAIT macro, which will be used
> as a flag to toggle the use of built-in traits in the type_traits header
> through _GLIBCXX_NO_BUILTIN_TRAITS macro, without needing to modify the
> source code.

LGTM!

>
> libstdc++-v3/ChangeLog:
>
> * include/bits/c++config (_GLIBCXX_HAS_BUILTIN_TRAIT): Define.
> (_GLIBCXX_HAS_BUILTIN): Keep defined.
>
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/bits/c++config | 10 +-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index dd47f274d5f..984985d6fff 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -854,7 +854,15 @@ namespace __gnu_cxx
>  # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
>  #endif
>
> -#undef _GLIBCXX_HAS_BUILTIN
> +// Returns 1 if _GLIBCXX_NO_BUILTIN_TRAITS is not defined and the compiler
> +// has a corresponding built-in type trait, 0 otherwise.
> +// _GLIBCXX_NO_BUILTIN_TRAITS can be defined to disable the use of built-in
> +// traits.
> +#ifndef _GLIBCXX_NO_BUILTIN_TRAITS
> +# define _GLIBCXX_HAS_BUILTIN_TRAIT(BT) _GLIBCXX_HAS_BUILTIN(BT)
> +#else
> +# define _GLIBCXX_HAS_BUILTIN_TRAIT(BT) 0
> +#endif
>
>  // Mark code that should be ignored by the compiler, but seen by Doxygen.
>  #define _GLIBCXX_DOXYGEN_ONLY(X)
> --
> 2.41.0
>



Re: [PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-20 Thread Patrick Palka via Gcc-patches
On Wed, 19 Jul 2023, Jason Merrill wrote:

> On 7/19/23 14:05, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/13?
> > 
> > -- >8 --
> > 
> > Since the arguments 'pargs' passed to the coerce_template_parms from
> > coerce_template_template_parms are always a full set, we need to make sure
> > we always pass the parameters of the most general template because if the
> > template is partially instantiated then the levels won't match up.
> 
> Hmm, so then my comment "In that case we might end up adding more levels than
> needed, but that shouldn't be a problem; any args we need to refer to are at
> the right level." is wrong for auto template parms?

I suppose, but only for the ttp case I think?  It seems all is well when
passing an ordinary template as a ttp as long as we use the parameters of the
most general template for the coercion.  I can't come up with a counterexample
at least.

> 
> So I guess we likely need to do more to assure that pargs has the right number
> of levels if there are autos in the innermost arg parms.
> 
> Also, most_general_template doesn't work for TTPs, so that probably won't help
> handle their partial instantiations.

Ah, yeah :( Here's an analagous testcase that we still ICE on due to this:

  template class>
  struct A;

  template
  struct B {
template
struct C {
  template class TT>
  using type = A;
};
  };

  template struct B::C;

I think I have a fix using get_innermost_template_args.

> 
> And is it right for an alias template in a partial specialization?

IIUC yes, e.g. tsubst directly relies on most_general_template to work
for alias templates (when substituting an alias template specialization).

> 
> > In the
> > testcase below during said call to coerce_template_parms the parameters
> > are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
> > leads to a crash during auto deduction of X and Y.
> > 
> > PR c++/110566
> 
> Since this is a regression from the patch for PR c++/108179, please list that
> PR here as well, to help avoid backporting that patch without this one.
> 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (coerce_template_template_parms): Simplify by using
> > DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
> > Always pass the parameters of the most general template to
> > coerce_template_parms.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > * g++.dg/template/ttp38.C: New test.
> > ---
> >   gcc/cp/pt.cc  | 12 +---
> >   gcc/testsuite/g++.dg/template/ttp38.C | 12 
> >   2 files changed, 17 insertions(+), 7 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index d882e9dd117..8723868823e 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
> > tree parm, arg;
> > int variadic_p = 0;
> >   -  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS
> > (parm_tmpl));
> > -  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
> > -  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
> > -
> > -  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
> > -  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
> > +  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
> > +  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
> > +  tree gen_arg_tmpl = most_general_template (arg_tmpl);
> > +  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
> >   nparms = TREE_VEC_LENGTH (parm_parms);
> > nargs = TREE_VEC_LENGTH (arg_parms);
> > @@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
> > scope_args = TI_ARGS (tinfo);
> > pargs = add_to_template_args (scope_args, pargs);
> >   -  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE,
> > tf_none);
> > +  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE,
> > tf_none);
> > if (pargs != error_mark_node)
> > {
> >   tree targs = make_tree_vec (nargs);
> > diff --git a/gcc/testsuite/g++.dg/template/ttp38.C
> > b/gcc/testsuite/g++.dg/template/ttp38.C
> > new file mode 100644
> > index 000..7d25d291e81
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/ttp38.C
> > @@ -0,0 +1,12 @@
> > +// PR c++/110566
> > +// { dg-do compile { target c++20 } }
> > +
> > +template class>
> > +struct A;
> > +
> > +template
> > +struct B {
> > +  template struct C;
> > +};
> > +
> > +using type = A::C>;
> 
> 



Re: [PATCH] libstdc++: Define _GLIBCXX_HAS_BUILTIN_TRAIT

2023-07-19 Thread Patrick Palka via Gcc-patches
On Tue, 18 Jul 2023, Ken Matsui via Libstdc++ wrote:

> This patch defines _GLIBCXX_HAS_BUILTIN_TRAIT, which will be used as a
> flag to toggle built-in traits in the type_traits header. Through this
> macro function and _GLIBCXX_NO_BUILTIN_TRAITS macro, we can switch the
> use of built-in traits without needing to modify the source code.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/bits/c++config (_GLIBCXX_HAS_BUILTIN_TRAIT): Define.

The ChangeLog entry should also mention the change to _GLIBCXX_HAS_BUILTIN,
e.g.

(_GLIBCXX_HAS_BUILTIN): Keep defined.

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/bits/c++config | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/libstdc++-v3/include/bits/c++config 
> b/libstdc++-v3/include/bits/c++config
> index dd47f274d5f..de13f61db71 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -854,7 +854,11 @@ namespace __gnu_cxx
>  # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
>  #endif
>  
> -#undef _GLIBCXX_HAS_BUILTIN
> +// Returns true if _GLIBCXX_NO_BUILTIN_TRAITS is not defined and the compiler
> +// has a corresponding built-in type trait. _GLIBCXX_NO_BUILTIN_TRAITS is
> +// defined to disable the use of built-in traits.
> +#define _GLIBCXX_HAS_BUILTIN_TRAIT(BT)  \
> +  (!defined(_GLIBCXX_NO_BUILTIN_TRAITS) && _GLIBCXX_HAS_BUILTIN(BT))

Since we don't expect _GLIBCXX_NO_BUILTIN_TRAITS to get
defined/undefined in the middle of preprocessing, perhaps we should
factor out the _GLIBCXX_NO_BUILTIN_TRAITS test from the macro function
and instead conditionally define the macro function to 0 according
_GLIBCXX_NO_BUILTIN_TRAITS?

>  
>  // Mark code that should be ignored by the compiler, but seen by Doxygen.
>  #define _GLIBCXX_DOXYGEN_ONLY(X)
> -- 
> 2.41.0
> 
> 



Re: [PATCH] c++: fix ICE with designated initializer [PR110114]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Wed, 19 Jul 2023, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

LGTM.  It might be preferable to check COMPLETE_TYPE_P in the caller
instead, so that we avoid inspecting CLASSTYPE_NON_AGGREGATE on an
incomplete class type, and so that the caller doesn't "commit" to
building an aggregate conversion.

> 
> -- >8 --
> 
> r13-1227 added an assert checking that the index in a CONSTRUCTOR
> is a FIELD_DECL.  That's a reasonable assumption but in this case
> we never called reshape_init due to the type being incomplete, and
> so the index remained an identifier node: get_class_binding never
> got around to looking up the FIELD_DECL.
> 
> We can avoid the crash by returning early in build_aggr_conv; we'd
> return NULL anyway due to:
> 
>   if (i < CONSTRUCTOR_NELTS (ctor))
> return NULL;
> 
>   PR c++/110114
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (build_aggr_conv): Return early if the type isn't
>   complete.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/desig28.C: New test.
>   * g++.dg/cpp2a/desig29.C: New test.
> ---
>  gcc/cp/call.cc   |  5 +
>  gcc/testsuite/g++.dg/cpp2a/desig28.C | 17 +
>  gcc/testsuite/g++.dg/cpp2a/desig29.C | 10 ++
>  3 files changed, 32 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig28.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig29.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index b55230d98aa..0af20a81717 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -986,6 +986,11 @@ build_aggr_conv (tree type, tree ctor, int flags, 
> tsubst_flags_t complain)
>tree empty_ctor = NULL_TREE;
>hash_set pset;
>  
> +  /* We've called complete_type on TYPE before calling this function, but
> + perhaps it wasn't successful.  */
> +  if (!COMPLETE_TYPE_P (type))
> +return nullptr;
> +
>/* We already called reshape_init in implicit_conversion, but it might not
>   have done anything in the case of parenthesized aggr init.  */
>  
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig28.C 
> b/gcc/testsuite/g++.dg/cpp2a/desig28.C
> new file mode 100644
> index 000..b63265fea51
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig28.C
> @@ -0,0 +1,17 @@
> +// PR c++/110114
> +// { dg-do compile { target c++20 } }
> +
> +struct A {
> +int a,b;
> +};
> +
> +struct B;
> +
> +void foo(const A &) {}
> +void foo(const B &) {}
> +
> +int
> +main ()
> +{
> +  foo({.a=0});
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig29.C 
> b/gcc/testsuite/g++.dg/cpp2a/desig29.C
> new file mode 100644
> index 000..bd1a82b041d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig29.C
> @@ -0,0 +1,10 @@
> +// PR c++/110114
> +// { dg-do compile { target c++20 } }
> +
> +struct B;
> +
> +void foo(const B &) {}
> +
> +int main() {
> +foo({.a=0}); // { dg-error "invalid" }
> +}
> 
> base-commit: 2971ff7b1d564ac04b537d907c70e6093af70832
> -- 
> 2.41.0
> 
> 



Re: [PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Wed, Jul 19, 2023 at 2:05 PM Patrick Palka  wrote:
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/13?
>
> -- >8 --
>
> Since the arguments 'pargs' passed to the coerce_template_parms from
> coerce_template_template_parms are always a full set, we need to make sure
> we always pass the parameters of the most general template because if the
> template is partially instantiated then the levels won't match up.  In the
> testcase below during said call to coerce_template_parms the parameters
> are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
> leads to a crash during auto deduction of X and Y.
>
> PR c++/110566
>
> gcc/cp/ChangeLog:
>
> * pt.cc (coerce_template_template_parms): Simplify by using
> DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
> Always pass the parameters of the most general template to
> coerce_template_parms.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/ttp38.C: New test.
> ---
>  gcc/cp/pt.cc  | 12 +---
>  gcc/testsuite/g++.dg/template/ttp38.C | 12 
>  2 files changed, 17 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index d882e9dd117..8723868823e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
>tree parm, arg;
>int variadic_p = 0;
>
> -  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS 
> (parm_tmpl));
> -  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
> -  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
> -
> -  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
> -  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
> +  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
> +  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
> +  tree gen_arg_tmpl = most_general_template (arg_tmpl);
> +  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
>
>nparms = TREE_VEC_LENGTH (parm_parms);
>nargs = TREE_VEC_LENGTH (arg_parms);
> @@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
> scope_args = TI_ARGS (tinfo);
>pargs = add_to_template_args (scope_args, pargs);
>
> -  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none);
> +  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, 
> tf_none);
>if (pargs != error_mark_node)
> {
>   tree targs = make_tree_vec (nargs);
> diff --git a/gcc/testsuite/g++.dg/template/ttp38.C 
> b/gcc/testsuite/g++.dg/template/ttp38.C
> new file mode 100644
> index 000..7d25d291e81
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp38.C
> @@ -0,0 +1,12 @@
> +// PR c++/110566
> +// { dg-do compile { target c++20 } }
> +
> +template class>
> +struct A;
> +
> +template
> +struct B {
> +  template struct C;

Oops, I botched a git commit --amend.  The parameter list here should
be 'auto X, auto Y'.

> +};
> +
> +using type = A::C>;
> --
> 2.41.0.376.gcba07a324d
>



[PATCH] c++: passing partially inst tmpl as ttp [PR110566]

2023-07-19 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

Since the arguments 'pargs' passed to the coerce_template_parms from
coerce_template_template_parms are always a full set, we need to make sure
we always pass the parameters of the most general template because if the
template is partially instantiated then the levels won't match up.  In the
testcase below during said call to coerce_template_parms the parameters
are {X, Y} both level 1, but the arguments are {{int}, {N, M}}, which
leads to a crash during auto deduction of X and Y.

PR c++/110566

gcc/cp/ChangeLog:

* pt.cc (coerce_template_template_parms): Simplify by using
DECL_INNERMOST_TEMPLATE_PARMS and removing redundant asserts.
Always pass the parameters of the most general template to
coerce_template_parms.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp38.C: New test.
---
 gcc/cp/pt.cc  | 12 +---
 gcc/testsuite/g++.dg/template/ttp38.C | 12 
 2 files changed, 17 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp38.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d882e9dd117..8723868823e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8073,12 +8073,10 @@ coerce_template_template_parms (tree parm_tmpl,
   tree parm, arg;
   int variadic_p = 0;
 
-  tree parm_parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm_tmpl));
-  tree arg_parms_full = DECL_TEMPLATE_PARMS (arg_tmpl);
-  tree arg_parms = INNERMOST_TEMPLATE_PARMS (arg_parms_full);
-
-  gcc_assert (TREE_CODE (parm_parms) == TREE_VEC);
-  gcc_assert (TREE_CODE (arg_parms) == TREE_VEC);
+  tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (parm_tmpl);
+  tree arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (arg_tmpl);
+  tree gen_arg_tmpl = most_general_template (arg_tmpl);
+  tree gen_arg_parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_arg_tmpl);
 
   nparms = TREE_VEC_LENGTH (parm_parms);
   nargs = TREE_VEC_LENGTH (arg_parms);
@@ -8134,7 +8132,7 @@ coerce_template_template_parms (tree parm_tmpl,
scope_args = TI_ARGS (tinfo);
   pargs = add_to_template_args (scope_args, pargs);
 
-  pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none);
+  pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none);
   if (pargs != error_mark_node)
{
  tree targs = make_tree_vec (nargs);
diff --git a/gcc/testsuite/g++.dg/template/ttp38.C 
b/gcc/testsuite/g++.dg/template/ttp38.C
new file mode 100644
index 000..7d25d291e81
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp38.C
@@ -0,0 +1,12 @@
+// PR c++/110566
+// { dg-do compile { target c++20 } }
+
+template class>
+struct A;
+
+template
+struct B {
+  template struct C;
+};
+
+using type = A::C>;
-- 
2.41.0.376.gcba07a324d



Re: [PATCH] c++: fix ICE with is_really_empty_class [PR110106]

2023-07-19 Thread Patrick Palka via Gcc-patches
On Tue, 18 Jul 2023, Marek Polacek via Gcc-patches wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk and branches?

Looks reasonable to me.

Though I wonder if we could also fix this by not checking potentiality
at all in this case?  The problematic call to is_rvalue_constant_expression
happens from cp_parser_constant_expression with 'allow_non_constant' != 0
and with 'non_constant_p' being a dummy out argument that comes from
cp_parser_functional_cast, so the result of is_rvalue_constant_expression
is effectively unused in this case, and we should be able to safely elide
it when 'allow_non_constant && non_constant_p == nullptr'.

Relatedly, ISTM the member cp_parser::non_integral_constant_expression_p
is also effectively unused and could be removed?

> 
> -- >8 --
> 
> is_really_empty_class is liable to crash when it gets an incomplete
> or dependent type.  Since r11-557, we pass the yet-uninstantiated
> class type S<0> of the PARM_DECL s to is_really_empty_class -- because
> of the potential_rvalue_constant_expression -> is_rvalue_constant_expression
> change in cp_parser_constant_expression.  Here we're not parsing
> a template so we did not check COMPLETE_TYPE_P as we should.
> 
>   PR c++/110106
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (potential_constant_expression_1): Check COMPLETE_TYPE_P
>   even when !processing_template_decl.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/noexcept80.C: New test.
> ---
>  gcc/cp/constexpr.cc |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/noexcept80.C | 12 
>  2 files changed, 13 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 6e8f1c2b61e..1f59c5472fb 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9116,7 +9116,7 @@ potential_constant_expression_1 (tree t, bool 
> want_rval, bool strict, bool now,
>if (now && want_rval)
>   {
> tree type = TREE_TYPE (t);
> -   if ((processing_template_decl && !COMPLETE_TYPE_P (type))
> +   if (!COMPLETE_TYPE_P (type)
> || dependent_type_p (type)
> || is_really_empty_class (type, /*ignore_vptr*/false))
>   /* An empty class has no data to read.  */
> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept80.C 
> b/gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> new file mode 100644
> index 000..3e90af747e2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept80.C
> @@ -0,0 +1,12 @@
> +// PR c++/110106
> +// { dg-do compile { target c++11 } }
> +
> +template struct S
> +{
> +};
> +
> +struct G {
> +  G(S<0>);
> +};
> +
> +void y(S<0> s) noexcept(noexcept(G{s}));
> 
> base-commit: fca089e8a47314a40ad93527ba9f9d0d374b3afb
> -- 
> 2.41.0
> 
> 



[PATCH] c++: deducing empty type vs non-type argument pack

2023-07-18 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Also verified by way of gcc_assert that we never see
TEMPLATE_PARM_INDEX here.

-- >8 --

Within a template parameter list, a non-type template parameter pack is
represented as a PARM_DECL.  But in a couple of spots where we need to
deduce an empty argument pack, we test for TEMPLATE_PARM_INDEX (within a
template parameter list) instead of for PARM_DECL, which means we end up
using TYPE_ARGUMENT_PACK even in the non-type case.  This patch fixes
this (seemingly harmless) bug.

gcc/cp/ChangeLog:

* pt.cc (type_unification_real): Test for PARM_DECL instead
of TEMPLATE_PARM_INDEX to distinguish a type vs non-type
template parameter pack.
(type_targs_deducible_from): Likewise.
---
 gcc/cp/pt.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3987ffc509a..d342ab5929a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23345,7 +23345,7 @@ type_unification_real (tree tparms,
{
  tree arg;
 
- if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+ if (TREE_CODE (tparm) == PARM_DECL)
{
  arg = make_node (NONTYPE_ARGUMENT_PACK);
  TREE_CONSTANT (arg) = 1;
@@ -30369,7 +30369,7 @@ type_targs_deducible_from (tree tmpl, tree type)
if (template_parameter_pack_p (tparm))
  {
tree arg;
-   if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+   if (TREE_CODE (tparm) == PARM_DECL)
  {
arg = make_node (NONTYPE_ARGUMENT_PACK);
TREE_CONSTANT (arg) = 1;
-- 
2.41.0.363.g5e238546dc



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-17 Thread Patrick Palka via Gcc-patches
On Fri, 14 Jul 2023, Jason Merrill wrote:

> On 7/14/23 14:07, Patrick Palka wrote:
> > On Thu, 13 Jul 2023, Jason Merrill wrote:
> > 
> > > On 7/13/23 11:48, Patrick Palka wrote:
> > > > On Wed, 28 Jun 2023, Patrick Palka wrote:
> > > > 
> > > > > On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill 
> > > > > wrote:
> > > > > > 
> > > > > > On 6/23/23 12:23, Patrick Palka wrote:
> > > > > > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 6/21/23 13:19, Patrick Palka wrote:
> > > > > > > > > When stepping through the variable/alias template
> > > > > > > > > specialization
> > > > > > > > > code
> > > > > > > > > paths, I noticed we perform template argument coercion twice:
> > > > > > > > > first from
> > > > > > > > > instantiate_alias_template / finish_template_variable and
> > > > > > > > > again
> > > > > > > > > from
> > > > > > > > > tsubst_decl (during instantiate_template).  It should suffice
> > > > > > > > > to
> > > > > > > > > perform
> > > > > > > > > coercion once.
> > > > > > > > > 
> > > > > > > > > To that end patch elides this second coercion from tsubst_decl
> > > > > > > > > when
> > > > > > > > > possible.  We can't get rid of it completely because we don't
> > > > > > > > > always
> > > > > > > > > specialize a variable template from finish_template_variable:
> > > > > > > > > we
> > > > > > > > > could
> > > > > > > > > also be doing so directly from instantiate_template during
> > > > > > > > > variable
> > > > > > > > > template partial specialization selection, in which case the
> > > > > > > > > coercion
> > > > > > > > > from tsubst_decl would be the first and only coercion.
> > > > > > > > 
> > > > > > > > Perhaps we should be coercing in lookup_template_variable rather
> > > > > > > > than
> > > > > > > > finish_template_variable?
> > > > > > > 
> > > > > > > Ah yes, there's a patch for that at
> > > > > > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> > > > > > 
> > > > > > So after that patch, can we get rid of the second coercion
> > > > > > completely?
> > > > > 
> > > > > On second thought it should be possible to get rid of it, if we
> > > > > rearrange things to always pass the primary arguments to tsubst_decl,
> > > > > and perform partial specialization selection from there instead of
> > > > > instantiate_template.  Let me try...
> > > > 
> > > > Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.
> > > > 
> > > > -- >8 --
> > > > 
> > > > When stepping through the variable/alias template specialization code
> > > > paths, I noticed we perform template argument coercion twice: first from
> > > > instantiate_alias_template / finish_template_variable and again from
> > > > tsubst_decl (during instantiate_template).  It'd be good to avoid this
> > > > redundant coercion.
> > > > 
> > > > It turns out that this coercion could be safely elided whenever
> > > > specializing a primary variable/alias template, because we can rely on
> > > > lookup_template_variable and instantiate_alias_template to already have
> > > > coerced the arguments.
> > > > 
> > > > The other situation to consider is when fully specializing a partial
> > > > variable template specialization (from instantiate_template), in which
> > > > case the passed 'args' are the (already coerced) arguments relative to
> > > > the partial template and 'argvec', the result of substitution into
> > > > DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
> > > > template, so coercion is still necessary.  We can still avoid this
> > > > coercion however if we always pass the primary variable template to
> > > > tsubst_decl from instantiate_template, and instead perform partial
> > > > specialization selection directly from tsubst_decl.  This patch
> > > > implements this approach.
> > > 
> > > The relationship between instantiate_template and tsubst_decl is pretty
> > > tangled.  We use the former to substitute (often deduced) template
> > > arguments
> > > into a template, and the latter to substitute template arguments into a
> > > use of
> > > a template...and also to implement the former.
> > > 
> > > For substitution of uses of a template, we expect to need to coerce the
> > > arguments after substitution.  But we avoid this issue for variable
> > > templates
> > > by keeping them as TEMPLATE_ID_EXPR until substitution time, so if we see
> > > a
> > > VAR_DECL in tsubst_decl it's either a non-template variable or under
> > > instantiate_template.
> > 
> > FWIW it seems we could also be in tsubst_decl for a VAR_DECL if
> > 
> >* we're partially instantiating a class-scope variable template
> >  during instantiation of the class
> 
> Hmm, why don't partial instantiations stay as TEMPLATE_ID_EXPR?

Whoops, I accidentally omitted a crucial word.  The situation is when
partially instantiating a class-scope variable template _declaration_,
e.g. for

  template
  struct A {
template static int v;
  };

  template struct A;

we call 

Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-14 Thread Patrick Palka via Gcc-patches
On Thu, 13 Jul 2023, Jason Merrill wrote:

> On 7/13/23 11:48, Patrick Palka wrote:
> > On Wed, 28 Jun 2023, Patrick Palka wrote:
> > 
> > > On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
> > > > 
> > > > On 6/23/23 12:23, Patrick Palka wrote:
> > > > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > > > > 
> > > > > > On 6/21/23 13:19, Patrick Palka wrote:
> > > > > > > When stepping through the variable/alias template specialization
> > > > > > > code
> > > > > > > paths, I noticed we perform template argument coercion twice:
> > > > > > > first from
> > > > > > > instantiate_alias_template / finish_template_variable and again
> > > > > > > from
> > > > > > > tsubst_decl (during instantiate_template).  It should suffice to
> > > > > > > perform
> > > > > > > coercion once.
> > > > > > > 
> > > > > > > To that end patch elides this second coercion from tsubst_decl
> > > > > > > when
> > > > > > > possible.  We can't get rid of it completely because we don't
> > > > > > > always
> > > > > > > specialize a variable template from finish_template_variable: we
> > > > > > > could
> > > > > > > also be doing so directly from instantiate_template during
> > > > > > > variable
> > > > > > > template partial specialization selection, in which case the
> > > > > > > coercion
> > > > > > > from tsubst_decl would be the first and only coercion.
> > > > > > 
> > > > > > Perhaps we should be coercing in lookup_template_variable rather
> > > > > > than
> > > > > > finish_template_variable?
> > > > > 
> > > > > Ah yes, there's a patch for that at
> > > > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> > > > 
> > > > So after that patch, can we get rid of the second coercion completely?
> > > 
> > > On second thought it should be possible to get rid of it, if we
> > > rearrange things to always pass the primary arguments to tsubst_decl,
> > > and perform partial specialization selection from there instead of
> > > instantiate_template.  Let me try...
> > 
> > Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.
> > 
> > -- >8 --
> > 
> > When stepping through the variable/alias template specialization code
> > paths, I noticed we perform template argument coercion twice: first from
> > instantiate_alias_template / finish_template_variable and again from
> > tsubst_decl (during instantiate_template).  It'd be good to avoid this
> > redundant coercion.
> > 
> > It turns out that this coercion could be safely elided whenever
> > specializing a primary variable/alias template, because we can rely on
> > lookup_template_variable and instantiate_alias_template to already have
> > coerced the arguments.
> > 
> > The other situation to consider is when fully specializing a partial
> > variable template specialization (from instantiate_template), in which
> > case the passed 'args' are the (already coerced) arguments relative to
> > the partial template and 'argvec', the result of substitution into
> > DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
> > template, so coercion is still necessary.  We can still avoid this
> > coercion however if we always pass the primary variable template to
> > tsubst_decl from instantiate_template, and instead perform partial
> > specialization selection directly from tsubst_decl.  This patch
> > implements this approach.
> 
> The relationship between instantiate_template and tsubst_decl is pretty
> tangled.  We use the former to substitute (often deduced) template arguments
> into a template, and the latter to substitute template arguments into a use of
> a template...and also to implement the former.
> 
> For substitution of uses of a template, we expect to need to coerce the
> arguments after substitution.  But we avoid this issue for variable templates
> by keeping them as TEMPLATE_ID_EXPR until substitution time, so if we see a
> VAR_DECL in tsubst_decl it's either a non-template variable or under
> instantiate_template.

FWIW it seems we could also be in tsubst_decl for a VAR_DECL if

  * we're partially instantiating a class-scope variable template
during instantiation of the class
  * we're substituting a use of an already non-dependent variable
template specialization

> 
> So it seems like the current coercion for variable templates is only needed in
> this case to support the redundant hash table lookup that we just did in
> instantiate_template.  Perhaps instead of doing coercion here or moving the
> partial spec lookup, we could skip the hash table lookup for the case of a
> variable template?

It seems we'd then also have to make instantiate_template responsible
for registering the variable template specialization since tsubst_decl
no longer necessarily has the arguments relative to the primary template
('args' could be relative to the partial template).

Like so?  The following makes us perform all the specialization table
manipulation in instantiate_template instead of tsubst_decl for variable
template 

[PATCH] c++: copy elision of object arg in static memfn call [PR110441]

2023-07-13 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

Here the call A().f() is represented as a COMPOUND_EXPR whose first
operand is the otherwise unused object argument A() and second operand
is the call result (both are TARGET_EXPRs).  Within the return statement,
this outermost COMPOUND_EXPR ends up foiling the copy elision check in
build_special_member_call, resulting in us introducing a bogus call to the
deleted move constructor.  (Within the variable initialization, which goes
through ocp_convert instead of convert_for_initialization, we've already
been eliding the copy despite the outermost COMPOUND_EXPR ever since
r10-7410-g72809d6fe8e085 made ocp_convert look through COMPOUND_EXPR).

In contrast, I noticed '(A(), A::f())' (which should be equivalent to
the above call) is represented with the COMPOUND_EXPR inside the RHS's
TARGET_EXPR initializer thanks to a special case in cp_build_compound_expr
thus avoiding the issue.

So this patch fixes this by making keep_unused_object_arg
use cp_build_compound_expr as well.

PR c++/110441

gcc/cp/ChangeLog:

* call.cc (keep_unused_object_arg): Use cp_build_compound_expr
instead of building a COMPOUND_EXPR directly.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/elide8.C: New test.
---
 gcc/cp/call.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1z/elide8.C | 25 +
 2 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/elide8.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 119063979fa..b0a69cb46d4 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -5218,7 +5218,7 @@ keep_unused_object_arg (tree result, tree obj, tree fn)
   if (TREE_THIS_VOLATILE (a))
 a = build_this (a);
   if (TREE_SIDE_EFFECTS (a))
-return build2 (COMPOUND_EXPR, TREE_TYPE (result), a, result);
+return cp_build_compound_expr (a, result, tf_warning_or_error);
   return result;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/elide8.C 
b/gcc/testsuite/g++.dg/cpp1z/elide8.C
new file mode 100644
index 000..7d471be8a2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/elide8.C
@@ -0,0 +1,25 @@
+// PR c++/110441
+// { dg-do compile { target c++11 } }
+
+struct immovable {
+  immovable(immovable &&) = delete;
+};
+
+struct A {
+  static immovable f();
+};
+
+immovable f() {
+  immovable m = A().f(); // { dg-error "deleted" "" { target c++14_down } }
+  return A().f(); // { dg-error "deleted" "" { target c++14_down } }
+}
+
+struct B {
+  A* operator->();
+};
+
+immovable g() {
+  B b;
+  immovable m = b->f(); // { dg-error "deleted" "" { target c++14_down } }
+  return b->f(); // { dg-error "deleted" "" { target c++14_down } }
+}
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-07-13 Thread Patrick Palka via Gcc-patches
On Wed, 28 Jun 2023, Patrick Palka wrote:

> On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
> >
> > On 6/23/23 12:23, Patrick Palka wrote:
> > > On Fri, 23 Jun 2023, Jason Merrill wrote:
> > >
> > >> On 6/21/23 13:19, Patrick Palka wrote:
> > >>> When stepping through the variable/alias template specialization code
> > >>> paths, I noticed we perform template argument coercion twice: first from
> > >>> instantiate_alias_template / finish_template_variable and again from
> > >>> tsubst_decl (during instantiate_template).  It should suffice to perform
> > >>> coercion once.
> > >>>
> > >>> To that end patch elides this second coercion from tsubst_decl when
> > >>> possible.  We can't get rid of it completely because we don't always
> > >>> specialize a variable template from finish_template_variable: we could
> > >>> also be doing so directly from instantiate_template during variable
> > >>> template partial specialization selection, in which case the coercion
> > >>> from tsubst_decl would be the first and only coercion.
> > >>
> > >> Perhaps we should be coercing in lookup_template_variable rather than
> > >> finish_template_variable?
> > >
> > > Ah yes, there's a patch for that at
> > > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
> >
> > So after that patch, can we get rid of the second coercion completely?
> 
> On second thought it should be possible to get rid of it, if we
> rearrange things to always pass the primary arguments to tsubst_decl,
> and perform partial specialization selection from there instead of
> instantiate_template.  Let me try...

Like so?  Bootstrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

When stepping through the variable/alias template specialization code
paths, I noticed we perform template argument coercion twice: first from
instantiate_alias_template / finish_template_variable and again from
tsubst_decl (during instantiate_template).  It'd be good to avoid this
redundant coercion.

It turns out that this coercion could be safely elided whenever
specializing a primary variable/alias template, because we can rely on
lookup_template_variable and instantiate_alias_template to already have
coerced the arguments.

The other situation to consider is when fully specializing a partial
variable template specialization (from instantiate_template), in which
case the passed 'args' are the (already coerced) arguments relative to
the partial template and 'argvec', the result of substitution into
DECL_TI_ARGS, are the (uncoerced) arguments relative to the primary
template, so coercion is still necessary.  We can still avoid this
coercion however if we always pass the primary variable template to
tsubst_decl from instantiate_template, and instead perform partial
specialization selection directly from tsubst_decl.  This patch
implements this approach.

gcc/cp/ChangeLog:

* pt.cc (tsubst_decl) : Don't call
coerce_template_parms.  Call most_specialized_partial_spec
when fully specializing a variable template here ...
(instantiate_template): ... instead of here.  Always pass
the primary variable template pattern to tsubst_decl.
---
 gcc/cp/pt.cc | 62 +++-
 1 file changed, 27 insertions(+), 35 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fa15b75b9c5..53968b823d5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15194,6 +15194,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
/* Check to see if we already have the specialization we
   need.  */
tree spec = NULL_TREE;
+   tree partial_ti = NULL_TREE;
bool local_p = false;
tree ctx = DECL_CONTEXT (t);
if (!(VAR_P (t) && DECL_LOCAL_DECL_P (t))
@@ -15230,17 +15231,29 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
-   if (argvec != error_mark_node
-   && PRIMARY_TEMPLATE_P (gen_tmpl)
-   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
- /* We're fully specializing a template declaration, so
-we need to coerce the innermost arguments corresponding to
-the template.  */
- argvec = (coerce_template_parms
-   (DECL_TEMPLATE_PARMS (gen_tmpl),
-argvec, tmpl, complain));
if (argvec == error_mark_node)
  RETURN (error_mark_node);
+   if (variable_template_p (gen_tmpl)
+   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
+ {
+   /* We need to determine if we're using a partial
+  specialization now, because the type of the
+  variable could be different.  */
+   

[PATCH] c++: mangling template-id of unknown template [PR110524]

2023-07-13 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk and perhaps 13?

-- >8 --

This fixes a crash when mangling an ADL-enabled call to a template-id
naming an unknown template (as per P0846R0).

PR c++/110524

gcc/cp/ChangeLog:

* mangle.cc (write_expression): Handle TEMPLATE_ID_EXPR
whose template is already an IDENTIFIER_NODE.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/fn-template26.C: New test.
---
 gcc/cp/mangle.cc   |  3 ++-
 gcc/testsuite/g++.dg/cpp2a/fn-template26.C | 16 
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template26.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 7dab4e62bc9..bef0fda6d22 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -3312,7 +3312,8 @@ write_expression (tree expr)
   else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
 {
   tree fn = TREE_OPERAND (expr, 0);
-  fn = OVL_NAME (fn);
+  if (!identifier_p (fn))
+   fn = OVL_NAME (fn);
   if (IDENTIFIER_ANY_OP_P (fn))
write_string ("on");
   write_unqualified_id (fn);
diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template26.C 
b/gcc/testsuite/g++.dg/cpp2a/fn-template26.C
new file mode 100644
index 000..d4a17eb9bd1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/fn-template26.C
@@ -0,0 +1,16 @@
+// PR c++/110524
+// { dg-do compile { target c++20 } }
+
+template
+auto f(T t) -> decltype(g(t));
+
+namespace N {
+  struct A { };
+  template void g(T);
+};
+
+int main() {
+  f(N::A{});
+}
+
+// { dg-final { scan-assembler "_Z1fIN1N1AEEDTcl1gIT_Efp_EES2_" } }
-- 
2.41.0.327.gaa9166bcc0



[PATCH] c++: non-standalone surrogate call template

2023-07-12 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  There might be an existing PR for this issue but Bugzilla search
seems to be timing out for me currently.

-- >8 --

I noticed we were accidentally preventing ourselves from considering
a pointer/reference-to-function conversion function template if it's
not the first conversion function that's considered, which for the
testcase below resulted in us accepting the B call but not the A call
despite the only difference between A and B being the order of member
declarations.  This patch fixes this so that the outcome of overload
resolution doesn't arbitrarily depend on declaration order in this
situation.

gcc/cp/ChangeLog:

* call.cc (add_template_conv_candidate): Don't check for
non-empty 'candidates' here.
(build_op_call): Check it here, before we've considered any
conversion functions.

gcc/testsuite/ChangeLog:

* g++.dg/overload/conv-op5.C: New test.
---
 gcc/cp/call.cc   | 24 ++--
 gcc/testsuite/g++.dg/overload/conv-op5.C | 18 ++
 2 files changed, 32 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/overload/conv-op5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 81935b83908..119063979fa 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -3709,12 +3709,6 @@ add_template_conv_candidate (struct z_candidate 
**candidates, tree tmpl,
 tree return_type, tree access_path,
 tree conversion_path, tsubst_flags_t complain)
 {
-  /* Making this work broke PR 71117 and 85118, so until the committee resolves
- core issue 2189, let's disable this candidate if there are any call
- operators.  */
-  if (*candidates)
-return NULL;
-
   return
 add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
 NULL_TREE, arglist, return_type, access_path,
@@ -5290,6 +5284,8 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
  LOOKUP_NORMAL, , complain);
 }
 
+  bool any_call_ops = candidates != nullptr;
+
   convs = lookup_conversions (type);
 
   for (; convs; convs = TREE_CHAIN (convs))
@@ -5306,10 +5302,18 @@ build_op_call (tree obj, vec **args, 
tsubst_flags_t complain)
  continue;
 
if (TREE_CODE (fn) == TEMPLATE_DECL)
- add_template_conv_candidate
-   (, fn, obj, *args, totype,
-/*access_path=*/NULL_TREE,
-/*conversion_path=*/NULL_TREE, complain);
+ {
+   /* Making this work broke PR 71117 and 85118, so until the
+  committee resolves core issue 2189, let's disable this
+  candidate if there are any call operators.  */
+   if (any_call_ops)
+ continue;
+
+   add_template_conv_candidate
+ (, fn, obj, *args, totype,
+  /*access_path=*/NULL_TREE,
+  /*conversion_path=*/NULL_TREE, complain);
+ }
else
  add_conv_candidate (, fn, obj,
  *args, /*conversion_path=*/NULL_TREE,
diff --git a/gcc/testsuite/g++.dg/overload/conv-op5.C 
b/gcc/testsuite/g++.dg/overload/conv-op5.C
new file mode 100644
index 000..b7724908b62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/conv-op5.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+
+template using F = int(*)(T);
+using G = int(*)(int*);
+
+struct A {
+  template operator F();  // #1
+  operator G() = delete; // #2
+};
+
+int i = A{}(0); // selects #1
+
+struct B {
+  operator G() = delete; // #2
+  template operator F();  // #1
+};
+
+int j = B{}(0); // selects #1
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] c++: constrained surrogate calls [PR110535]

2023-07-12 Thread Patrick Palka via Gcc-patches
On Wed, 12 Jul 2023, Patrick Palka wrote:

> We're not checking constraints of pointer/reference-to-function conversion
> functions during overload resolution, which causes us to ICE on the first
> testcase and incorrectly reject the second testcase.

Er, I noticed [over.call.object] doesn't exactly say that surrogate
call functions inherit the constraints of the corresponding conversion
function, but I reckon that's the intent?

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/13?
> 
>   PR c++/110535
> 
> gcc/cp/ChangeLog:
> 
>   * call.cc (add_conv_candidate): Check constraints.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp2a/concepts-surrogate1.C: New test.
>   * g++.dg/cpp2a/concepts-surrogate2.C: New test.
> ---
>  gcc/cp/call.cc   |  8 
>  gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C | 12 
>  gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C | 14 ++
>  3 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 15a3d6f2a1f..81935b83908 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -2588,6 +2588,14 @@ add_conv_candidate (struct z_candidate **candidates, 
> tree fn, tree obj,
>if (*candidates && (*candidates)->fn == totype)
>  return NULL;
>  
> +  if (!constraints_satisfied_p (fn))
> +{
> +  reason = constraint_failure ();
> +  viable = 0;
> +  return add_candidate (candidates, fn, obj, arglist, len, convs,
> + access_path, conversion_path, viable, reason, 
> flags);
> +}
> +
>for (i = 0; i < len; ++i)
>  {
>tree arg, argtype, convert_type = NULL_TREE;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
> new file mode 100644
> index 000..e8481a31656
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
> @@ -0,0 +1,12 @@
> +// PR c++/110535
> +// { dg-do compile { target c++20 } }
> +
> +using F = int(int);
> +
> +template
> +struct A {
> + operator F*() requires B;
> +};
> +
> +int i = A{}(0);  // OK
> +int j = A{}(0); // { dg-error "no match" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> new file mode 100644
> index 000..8bf8364beb7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
> @@ -0,0 +1,14 @@
> +// PR c++/110535
> +// { dg-do compile { target c++20 } }
> +
> +using F = int(int);
> +using G = long(int);
> +
> +template
> +struct A {
> + operator F&() requires B;
> + operator G&() requires (!B);
> +};
> +
> +int i = A{}(0);  // { dg-bogus "ambiguous" }
> +int j = A{}(0); // { dg-bogus "ambiguous" }
> -- 
> 2.41.0.327.gaa9166bcc0
> 
> 



[PATCH] c++: constrained surrogate calls [PR110535]

2023-07-12 Thread Patrick Palka via Gcc-patches
We're not checking constraints of pointer/reference-to-function conversion
functions during overload resolution, which causes us to ICE on the first
testcase and incorrectly reject the second testcase.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

PR c++/110535

gcc/cp/ChangeLog:

* call.cc (add_conv_candidate): Check constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-surrogate1.C: New test.
* g++.dg/cpp2a/concepts-surrogate2.C: New test.
---
 gcc/cp/call.cc   |  8 
 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C | 12 
 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C | 14 ++
 3 files changed, 34 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15a3d6f2a1f..81935b83908 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2588,6 +2588,14 @@ add_conv_candidate (struct z_candidate **candidates, 
tree fn, tree obj,
   if (*candidates && (*candidates)->fn == totype)
 return NULL;
 
+  if (!constraints_satisfied_p (fn))
+{
+  reason = constraint_failure ();
+  viable = 0;
+  return add_candidate (candidates, fn, obj, arglist, len, convs,
+   access_path, conversion_path, viable, reason, 
flags);
+}
+
   for (i = 0; i < len; ++i)
 {
   tree arg, argtype, convert_type = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
new file mode 100644
index 000..e8481a31656
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate1.C
@@ -0,0 +1,12 @@
+// PR c++/110535
+// { dg-do compile { target c++20 } }
+
+using F = int(int);
+
+template
+struct A {
+ operator F*() requires B;
+};
+
+int i = A{}(0);  // OK
+int j = A{}(0); // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
new file mode 100644
index 000..8bf8364beb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-surrogate2.C
@@ -0,0 +1,14 @@
+// PR c++/110535
+// { dg-do compile { target c++20 } }
+
+using F = int(int);
+using G = long(int);
+
+template
+struct A {
+ operator F&() requires B;
+ operator G&() requires (!B);
+};
+
+int i = A{}(0);  // { dg-bogus "ambiguous" }
+int j = A{}(0); // { dg-bogus "ambiguous" }
-- 
2.41.0.327.gaa9166bcc0



[PATCH] c++: coercing variable template from current inst [PR110580]

2023-07-11 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk?

-- >8 --

Here during ahead of time coercion of the variable template-id v1,
since we pass only the innermost arguments to coerce_template_parms (and
outer arguments are still dependent at this point), substitution of the
default template argument V=U prematurely lowers U from level 2 to level 1.
Thus we incorrectly resolve v1 to v1 (effectively) instead
of to v1.

Coercion of a class/alias template-id on the other hand is always done
using the full set of arguments relative to the most general template,
so ahead of time coercion there does the right thing.  I suppose we
should do the same for variable template-ids.

PR c++/110580

gcc/cp/ChangeLog:

* pt.cc (lookup_template_variable): Pass all arguments to
coerce_template_parms, and use the innermost parameters from
the most general template.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/var-templ83.C: New test.
---
 gcc/cp/pt.cc |  4 +++-
 gcc/testsuite/g++.dg/cpp1y/var-templ83.C | 16 
 2 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ83.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 076f788281e..fa15b75b9c5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10345,7 +10345,9 @@ lookup_template_variable (tree templ, tree arglist, 
tsubst_flags_t complain)
   if (flag_concepts && variable_concept_p (templ))
 return build_concept_check (templ, arglist, tf_none);
 
-  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (templ);
+  tree gen_templ = most_general_template (templ);
+  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_templ);
+  arglist = add_outermost_template_args (templ, arglist);
   arglist = coerce_template_parms (parms, arglist, templ, complain);
   if (arglist == error_mark_node)
 return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ83.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ83.C
new file mode 100644
index 000..f5268f258d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ83.C
@@ -0,0 +1,16 @@
+// PR c++/110580
+// { dg-do compile { target c++14 } }
+
+template
+struct A {
+  template
+  static constexpr bool v1 = __is_same(U, V);
+
+  template
+  static constexpr bool v2 = !__is_same(U, V);
+
+  static_assert(v1, "");
+  static_assert(v2, "");
+};
+
+template struct A;
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH v3 0/3] c++: Track lifetimes in constant evaluation [PR70331,...]

2023-07-10 Thread Patrick Palka via Gcc-patches
On Sat, 1 Jul 2023, Nathaniel Shead wrote:

> This is an update of the patch series at
> https://gcc.gnu.org/pipermail/gcc-patches/2023-March/614811.html
> 
> Changes since v2:
> 
> - Use a separate 'hash_set' to track expired variables instead of
>   adding a flag to 'lang_decl_base'.
> - Use 'iloc_sentinel' to propagate location information down to
>   subexpressions instead of manually saving and falling back to a
>   parent expression's location.
> - Update more tests with improved error location information.

Thanks very much! This patch series looks good to me.

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu.
> 
> ---
> 
> Nathaniel Shead (3):
>   c++: Track lifetimes in constant evaluation [PR70331,PR96630,PR98675]
>   c++: Improve constexpr error for dangling local variables
>   c++: Improve location information in constant evaluation
> 
>  gcc/cp/constexpr.cc   | 158 +++---
>  gcc/cp/semantics.cc   |   5 +-
>  gcc/cp/typeck.cc  |   5 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  |  10 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C  |   8 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C |   8 +-
>  .../g++.dg/cpp0x/constexpr-delete2.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |   2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |   1 +
>  .../g++.dg/cpp0x/constexpr-recursion.C|   6 +-
>  gcc/testsuite/g++.dg/cpp0x/overflow1.C|   2 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C|  14 ++
>  .../g++.dg/cpp1y/constexpr-lifetime2.C|  20 +++
>  .../g++.dg/cpp1y/constexpr-lifetime3.C|  13 ++
>  .../g++.dg/cpp1y/constexpr-lifetime4.C|  11 ++
>  .../g++.dg/cpp1y/constexpr-lifetime5.C|  11 ++
>  .../g++.dg/cpp1y/constexpr-tracking-const14.C |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const16.C |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const18.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const19.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const21.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const22.C |   4 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const3.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const4.C  |   3 +-
>  .../g++.dg/cpp1y/constexpr-tracking-const7.C  |   3 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |   4 +-
>  gcc/testsuite/g++.dg/cpp1y/pr68180.C  |   4 +-
>  .../g++.dg/cpp1z/constexpr-lambda6.C  |   4 +-
>  .../g++.dg/cpp1z/constexpr-lambda8.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   |  14 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |   4 +-
>  .../g++.dg/cpp2a/constexpr-dynamic17.C|   5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |   5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |   6 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   |  10 +-
>  gcc/testsuite/g++.dg/cpp2a/constinit10.C  |   5 +-
>  .../g++.dg/cpp2a/is-corresponding-member4.C   |   4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla2.C |   4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla3.C |   4 +-
>  gcc/testsuite/g++.dg/ubsan/pr63956.C  |  23 +--
>  .../g++.dg/warn/Wreturn-local-addr-6.C|   3 -
>  .../25_algorithms/equal/constexpr_neg.cc  |   7 +-
>  .../testsuite/26_numerics/gcd/105844.cc   |  10 +-
>  .../testsuite/26_numerics/lcm/105844.cc   |  14 +-
>  48 files changed, 330 insertions(+), 143 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> 
> -- 
> 2.41.0
> 
> 



[pushed] c++: redeclare_class_template and ttps [PR110523]

2023-07-10 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, pushed to trunk as obvious.

-- >8 --

Now that we cache level-lowered ttps we can end up processing the same
ttp multiple times via (multiple calls to) redeclare_class_template, so
we can't assume a ttp's DECL_CONTEXT is initially empty.

PR c++/110523

gcc/cp/ChangeLog:

* pt.cc (redeclare_class_template): Relax the ttp DECL_CONTEXT
assert, and downgrade it to a checking assert.

gcc/testsuite/ChangeLog:

* g++.dg/template/ttp37.C: New test.
---
 gcc/cp/pt.cc  |  3 ++-
 gcc/testsuite/g++.dg/template/ttp37.C | 15 +++
 2 files changed, 17 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp37.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d7d774fd9e5..076f788281e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6388,7 +6388,8 @@ redeclare_class_template (tree type, tree parms, tree 
cons)
 DECL_CONTEXT of the template for which they are a parameter.  */
   if (TREE_CODE (parm) == TEMPLATE_DECL)
{
- gcc_assert (DECL_CONTEXT (parm) == NULL_TREE);
+ gcc_checking_assert (DECL_CONTEXT (parm) == NULL_TREE
+  || DECL_CONTEXT (parm) == tmpl);
  DECL_CONTEXT (parm) = tmpl;
}
 }
diff --git a/gcc/testsuite/g++.dg/template/ttp37.C 
b/gcc/testsuite/g++.dg/template/ttp37.C
new file mode 100644
index 000..c5f4e99c20a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp37.C
@@ -0,0 +1,15 @@
+// PR c++/110523
+
+template class>
+class basic_json;
+
+template
+struct json_pointer {
+  template class>
+  friend class basic_json;
+};
+
+template struct json_pointer;
+template struct json_pointer;
+template struct json_pointer;
+template struct json_pointer;
-- 
2.41.0.327.gaa9166bcc0



Re: [PATCH] libstdc++: Fix iostream init for Clang on darwin [PR110432]

2023-06-30 Thread Patrick Palka via Gcc-patches
On Fri, 30 Jun 2023, Jonathan Wakely wrote:

> Tested x86_64-linux. Patrick, PTAL.
> 
> -- >8 --
> 
> The __has_attribute(init_priority) check in  is true for Clang
> on darwin, which means that user code including  thinks the
> library will initialize the global streams. However, when libstdc++ is
> built by GCC on darwin, the __has_attribute(init_priority) check is
> false, which means that the library thinks that user code will do the
> initialization when  is included. This means that the
> initialization is never done.
> 
> Add an autoconf check so that the header and the library both make their
> decision based on the static properties of GCC at build time, with a
> consistent outcome.
> 
> As a belt and braces check, also do the initialization in  if
> the compiler including that header doesn't support the attribute (even
> if the library also containers the initialization). This might result in
> redundant initialization done in , but ensures the
> initialization happens somewhere if there's any doubt about the
> attribute working correctly due to missing linker support.
> 
> libstdc++-v3/ChangeLog:
> 
>   PR libstdc++/110432
>   * acinclude.m4 (GLIBCXX_CHECK_INIT_PRIORITY): New.
>   * config.h.in: Regenerate.
>   * configure: Regenerate.
>   * configure.ac: Use GLIBCXX_CHECK_INIT_PRIORITY.
>   * include/std/iostream:

Missing ChangeLog entry?

>   * src/c++98/ios_base_init.h: Use new autoconf macro instead of
>   __has_attribute.
> ---
>  libstdc++-v3/acinclude.m4  | 27 ++
>  libstdc++-v3/config.h.in   |  3 ++
>  libstdc++-v3/configure | 51 ++
>  libstdc++-v3/configure.ac  |  3 ++
>  libstdc++-v3/include/std/iostream  |  2 +-
>  libstdc++-v3/src/c++98/ios_base_init.h |  2 +-
>  6 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
> index 277ae10e031..823832f97d4 100644
> --- a/libstdc++-v3/acinclude.m4
> +++ b/libstdc++-v3/acinclude.m4
> @@ -5680,6 +5680,33 @@ AC_DEFUN([GLIBCXX_CHECK_ALIGNAS_CACHELINE], [
>AC_LANG_RESTORE
>  ])
>  
> +dnl
> +dnl Check whether iostream initialization should be done in the library,
> +dnl using the init_priority attribute.
> +dnl
> +dnl Defines:
> +dnl  _GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE if GCC supports the init_priority
> +dnlattribute for the target.
> +dnl
> +AC_DEFUN([GLIBCXX_CHECK_INIT_PRIORITY], [
> +AC_LANG_SAVE
> +  AC_LANG_CPLUSPLUS
> +
> +  AC_MSG_CHECKING([whether init_priority attribute is supported])
> +  AC_TRY_COMPILE(, [
> +  #if ! __has_attribute(init_priority)
> +  #error init_priority not supported
> +  #endif
> +  ], [ac_init_priority=yes], [ac_init_priority=no])
> +  if test "$ac_init_priority" = yes; then
> +AC_DEFINE_UNQUOTED(_GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE, 1,
> +  [Define if init_priority should be used for iostream initialization.])
> +  fi
> +  AC_MSG_RESULT($ac_init_priority)
> +
> +  AC_LANG_RESTORE
> +])
> +
>  # Macros from the top-level gcc directory.
>  m4_include([../config/gc++filt.m4])
>  m4_include([../config/tls.m4])
> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
> index 9770c178767..fc0f2522027 100644
> --- a/libstdc++-v3/configure.ac
> +++ b/libstdc++-v3/configure.ac
> @@ -550,6 +550,9 @@ GLIBCXX_ZONEINFO_DIR
>  # For src/c++11/shared_ptr.cc alignment.
>  GLIBCXX_CHECK_ALIGNAS_CACHELINE
>  
> +# For using init_priority in ios_init.cc
> +GLIBCXX_CHECK_INIT_PRIORITY
> +
>  # Define documentation rules conditionally.
>  
>  # See if makeinfo has been installed and is modern enough
> diff --git a/libstdc++-v3/include/std/iostream 
> b/libstdc++-v3/include/std/iostream
> index cfd124dcf43..ec337cf89dd 100644
> --- a/libstdc++-v3/include/std/iostream
> +++ b/libstdc++-v3/include/std/iostream
> @@ -75,7 +75,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// For construction of filebuffers for cout, cin, cerr, clog et. al.
>// When the init_priority attribute is usable, we do this initialization
>// in the compiled library instead (src/c++98/globals_io.cc).
> -#if !__has_attribute(__init_priority__)
> +#if !(_GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE && __has_attribute(init_priority))

This should check __init_priority__ since init_priority is a non-reserved
name I think?  LGTM otherwise.

>static ios_base::Init __ioinit;
>  #elif defined(_GLIBCXX_SYMVER_GNU)
>__extension__ __asm (".globl _ZSt21ios_base_library_initv");
> diff --git a/libstdc++-v3/src/c++98/ios_base_init.h 
> b/libstdc++-v3/src/c++98/ios_base_init.h
> index b600ec3298e..f7edfc84625 100644
> --- a/libstdc++-v3/src/c++98/ios_base_init.h
> +++ b/libstdc++-v3/src/c++98/ios_base_init.h
> @@ -8,6 +8,6 @@
>  // constructor when statically linking with libstdc++.a), instead of
>  // doing so in (each TU that includes) .
>  // This needs to be done in the same TU that defines the stream objects.
> -#if 

[PATCH] c++: unpropagated CONSTRUCTOR_MUTABLE_POISON [PR110463]

2023-06-29 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13?

-- >8 --

cp_fold is neglecting to propagate CONSTRUCTOR_MUTABLE_POISON when folding
a CONSTRUCTOR initializer, which for the below testcase causes us to fail
to reject a mutable member access of a constexpr variable during constexpr
evaluation.

PR c++/110463

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_fold) : Propagate
CONSTRUCTOR_MUTABLE_POISON.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-mutable6.C: New test.
---
 gcc/cp/cp-gimplify.cc  |  2 ++
 .../g++.dg/cpp0x/constexpr-mutable6.C  | 18 ++
 2 files changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 853b1e44236..f5734197774 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -3079,6 +3079,8 @@ cp_fold (tree x, fold_flags_t flags)
x = build_constructor (TREE_TYPE (x), nelts);
CONSTRUCTOR_PLACEHOLDER_BOUNDARY (x)
  = CONSTRUCTOR_PLACEHOLDER_BOUNDARY (org_x);
+   CONSTRUCTOR_MUTABLE_POISON (x)
+ = CONSTRUCTOR_MUTABLE_POISON (org_x);
  }
if (VECTOR_TYPE_P (TREE_TYPE (x)))
  x = fold (x);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C
new file mode 100644
index 000..2c946e388ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-mutable6.C
@@ -0,0 +1,18 @@
+// PR c++/110463
+// { dg-do compile { target c++11 } }
+
+struct U {
+  mutable int x = 1;
+};
+
+struct V {
+  mutable int y = 1+1;
+};
+
+int main() {
+  constexpr U u = {};
+  constexpr int x = u.x; // { dg-error "mutable" }
+
+  constexpr V v = {};
+  constexpr int y = v.y; // { dg-error "mutable" }
+}
-- 
2.41.0.199.ga9e066fa63



[PATCH] c++: NSDMI instantiation during overload resolution [PR110468]

2023-06-29 Thread Patrick Palka via Gcc-patches
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/13/12?

-- >8 --

Here we find ourselves instantiating the NSDMI for A<1>::m when
computing argument conversions during overload resolution, and
thus tf_conv is set.  This causes mark_used for the constructor
used in the NSDMI to exit early and not instantiate its noexcept-spec,
leading to an ICE from nothrow_spec_p.

This patch fixes this by clearing any unusual tsubst flags during
instantiation of an NSDMI, since the result should be independent of
the context that requires the instantiation.

PR c++/110468

gcc/cp/ChangeLog:

* init.cc (maybe_instantiate_nsdmi_init): Mask out all
tsubst flags except for tf_warning_or_error.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept79.C: New test.
---
 gcc/cp/init.cc  |  4 
 gcc/testsuite/g++.dg/cpp0x/noexcept79.C | 18 ++
 2 files changed, 22 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept79.C

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e..f01a11c5299 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -579,6 +579,10 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t 
complain)
   /* tsubst_decl uses void_node to indicate an uninstantiated DMI.  */
   if (init == void_node)
 {
+  /* The result of NSDMI instantiation should be independent of
+the tsubst flags we're given.  */
+  complain &= tf_warning_or_error;
+
   init = DECL_INITIAL (DECL_TI_TEMPLATE (member));
   location_t expr_loc
= cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (member));
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept79.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept79.C
new file mode 100644
index 000..d1f54d14431
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept79.C
@@ -0,0 +1,18 @@
+// PR c++/110468
+// { dg-do compile { target c++11 } }
+
+template
+struct variant {
+  variant() noexcept(T > 0);
+};
+
+template
+struct A {
+  variant m = {};
+};
+
+struct B {
+  B(A<1>);
+};
+
+B b = {{}};
-- 
2.41.0.199.ga9e066fa63



Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-28 Thread Patrick Palka via Gcc-patches
On Wed, Jun 28, 2023 at 11:50 AM Jason Merrill  wrote:
>
> On 6/23/23 12:23, Patrick Palka wrote:
> > On Fri, 23 Jun 2023, Jason Merrill wrote:
> >
> >> On 6/21/23 13:19, Patrick Palka wrote:
> >>> When stepping through the variable/alias template specialization code
> >>> paths, I noticed we perform template argument coercion twice: first from
> >>> instantiate_alias_template / finish_template_variable and again from
> >>> tsubst_decl (during instantiate_template).  It should suffice to perform
> >>> coercion once.
> >>>
> >>> To that end patch elides this second coercion from tsubst_decl when
> >>> possible.  We can't get rid of it completely because we don't always
> >>> specialize a variable template from finish_template_variable: we could
> >>> also be doing so directly from instantiate_template during variable
> >>> template partial specialization selection, in which case the coercion
> >>> from tsubst_decl would be the first and only coercion.
> >>
> >> Perhaps we should be coercing in lookup_template_variable rather than
> >> finish_template_variable?
> >
> > Ah yes, there's a patch for that at
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)
>
> So after that patch, can we get rid of the second coercion completely?

On second thought it should be possible to get rid of it, if we
rearrange things to always pass the primary arguments to tsubst_decl,
and perform partial specialization selection from there instead of
instantiate_template.  Let me try...

>
> Jason
>



Re: [PATCH] c++: Fix ICE with parameter pack of decltype(auto) [PR103497]

2023-06-28 Thread Patrick Palka via Gcc-patches
On Sat, Jun 24, 2023 at 9:24 AM Nathaniel Shead
 wrote:
>
> On Fri, Jun 23, 2023 at 11:59:51AM -0400, Patrick Palka wrote:
> > Hi,
> >
> > On Sat, 22 Apr 2023, Nathaniel Shead via Gcc-patches wrote:
> >
> > > Bootstrapped and tested on x86_64-pc-linux-gnu.
> > >
> > > -- 8< --
> > >
> > > This patch raises an error early when the decltype(auto) specifier is
> > > used as a parameter of a function. This prevents any issues with an
> > > unexpected tree type later on when performing the call.
> >
> > Thanks very much for the patch!  Some minor comments below.
> >
> > >
> > > PR 103497
> >
> > We should include the bug component name when referring to the PR in the
> > commit message (i.e. PR c++/103497) so that upon pushing the patch the
> > post-commit hook automatically adds a comment to the PR reffering to the
> > commit.  I could be wrong but AFAIK the hook only performs this when the
> > component name is included.
>
> Thanks for the review! Fixed.
>
> > >
> > > gcc/cp/ChangeLog:
> > >
> > > * parser.cc (cp_parser_simple_type_specifier): Add check for
> > > decltype(auto) as function parameter.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > > * g++.dg/pr103497.C: New test.
> > >
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/parser.cc| 10 ++
> > >  gcc/testsuite/g++.dg/pr103497.C |  7 +++
> > >  2 files changed, 17 insertions(+)
> > >  create mode 100644 gcc/testsuite/g++.dg/pr103497.C
> > >
> > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > index e5f032f2330..1415e07e152 100644
> > > --- a/gcc/cp/parser.cc
> > > +++ b/gcc/cp/parser.cc
> > > @@ -19884,6 +19884,16 @@ cp_parser_simple_type_specifier (cp_parser* 
> > > parser,
> > >&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
> > >  {
> > >type = saved_checks_value (token->u.tree_check_value);
> > > +  /* Within a function parameter declaration, decltype(auto) is 
> > > always an
> > > +error.  */
> > > +  if (parser->auto_is_implicit_function_template_parm_p
> > > + && TREE_CODE (type) == TEMPLATE_TYPE_PARM
> >
> > We could check is_auto (type) here instead, to avoid any confusion with
> > checking AUTO_IS_DECLTYPE for a non-auto TEMPLATE_TYPE_PARM.
> >
> > > + && AUTO_IS_DECLTYPE (type))
> > > +   {
> > > + error_at (token->location,
> > > +   "cannot declare a parameter with %");
> > > + type = error_mark_node;
> > > +   }
> > >if (decl_specs)
> > > {
> > >   cp_parser_set_decl_spec_type (decl_specs, type,
> > > diff --git a/gcc/testsuite/g++.dg/pr103497.C 
> > > b/gcc/testsuite/g++.dg/pr103497.C
> > > new file mode 100644
> > > index 000..bcd421c2907
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/pr103497.C
> > > @@ -0,0 +1,7 @@
> > > +// { dg-do compile { target c++14 } }
> > > +
> > > +void foo(decltype(auto)... args);  // { dg-error "parameter with 
> > > .decltype.auto..|no parameter packs" }
> >
> > I noticed for
> >
> >   void foo(decltype(auto) arg);
> >
> > we already issue an identical error from grokdeclarator.  Perhaps we could
> > instead extend the error handling there to detect decltype(auto)... as well,
> > rather than adding new error handling in cp_parser_simple_type_specifier?
>
> Ah thanks, I didn't notice this; this simplifies the change a fair bit.
> How about this patch instead?

LGTM! Though I can't approve the patch myself.

>
> Regtested on x86_64-pc-linux-gnu.
>
> -- 8< --
>
> This patch ensures that checks for usages of 'auto' in function
> parameters also consider parameter packs, since 'type_uses_auto' does
> not seem to consider this case.
>
> PR c++/103497
>
> gcc/cp/ChangeLog:
>
> * decl.cc (grokdeclarator): Check for decltype(auto) in
> parameter pack.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp1y/decltype-auto-103497.C: New test.
>
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/decl.cc| 3 +++
>  gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C | 8 
>  2 files changed, 11 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 60f107d50c4..aaf691fce68 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -14044,6 +14044,9 @@ grokdeclarator (const cp_declarator *declarator,
> error ("cannot use %<::%> in parameter declaration");
>
>tree auto_node = type_uses_auto (type);
> +  if (!auto_node && parameter_pack_p)
> +   auto_node = type_uses_auto (PACK_EXPANSION_PATTERN (type));
> +
>if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
> {
>   if (cxx_dialect >= cxx14)
> diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
> b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
> new file mode 100644
> index 000..cedd661710c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
> @@ 

[PATCH] c++: cache partial template specialization selection

2023-06-28 Thread Patrick Palka via Gcc-patches
There's currently no cheap way to obtain the partial template
specialization (and arguments relative to it) that was selected for a
class or variable template specialization.  Our only option is to
compute the result from scratch via most_specialized_partial_spec.

For class templates this isn't really an issue because we usually need
this information just once, upon instantiation.  But for variable
templates we need it upon specialization and later upon instantiation.
It'd be good for this information to be readily available in general
however.

To that end, this patch adds a TI_PARTIAL_INFO field to TEMPLATE_INFO
that holds another TEMPLATE_INFO consisting of the partial template and
arguments relative to it, which most_specialized_partial_spec then
uses to transparently cache its (now TEMPLATE_INFO) result.

Similarly, there's no easy way to go from the DECL_TEMPLATE_RESULT of a
partial TEMPLATE_DECL back to the TEMPLATE_DECL.  (Our best option is to
walk the DECL_TEMPLATE_SPECIALIZATIONS list of the primary TEMPLATE_DECL.)
So this patch also uses this new field to link these entities in this
other direction.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Memory usage increases by ~0.2% overall with this patch (due to
the larger TEMPLATE_INFO, which now is the same size as TREE_LIST),
which seems acceptable.

gcc/cp/ChangeLog:

* cp-tree.h (tree_template_info::partial): New data member.
(TI_PARTIAL_INFO): New tree accessor.
(most_specialized_partial_spec): Add defaulted bool parameter.
* module.cc (trees_out::core_vals) :
Stream TI_PARTIAL_INFO.
(trees_in::core_vals) : Likewise.
* parser.cc (specialization_of): Adjust after making
most_specialized_partial_spec return TEMPLATE_INFO instead
of TREE_LIST.
* pt.cc (process_partial_specialization): Set TI_PARTIAL_INFO
of 'decl' to point back to the partial TEMPLATE_DECL.  Likewise
(and pass rechecking=true to most_specialization_partial_spec).
(instantiate_class_template): Likewise.
(instantiate_template): Set TI_PARTIAL_INFO to the result of
most_specialization_partial_spec after forming a variable
template specialization.
(most_specialized_partial_spec): Add 'rechecking' parameter.
Exit early if the template is not primary.  Use the TI_PARTIAL_INFO
of the corresponding TEMPLATE_INFO as a cache unless 'rechecking'
is true.  Don't bother setting TREE_TYPE of each TREE_LIST.
(instantiate_decl): Adjust after making
most_specialized_partial_spec return TEMPLATE_INFO instead of
TREE_LIST.
* ptree.cc (cxx_print_xnode) : Dump
TI_PARTIAL_INFO.
---
 gcc/cp/cp-tree.h | 11 ++-
 gcc/cp/module.cc |  2 ++
 gcc/cp/parser.cc |  6 ++--
 gcc/cp/pt.cc | 75 +++-
 gcc/cp/ptree.cc  |  3 ++
 5 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 83982233111..fe94af46346 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1564,6 +1564,7 @@ struct GTY(()) tree_template_info {
   struct tree_base base;
   tree tmpl;
   tree args;
+  tree partial;
   vec *deferred_access_checks;
 };
 
@@ -3755,6 +3756,14 @@ struct GTY(()) lang_decl {
   ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->args
 #define TI_PENDING_TEMPLATE_FLAG(NODE) \
   TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE))
+
+/* For a class or variable template specialization, this contains the
+   TEMPLATE_INFO result of most_specialized_partial_spec, i.e. the selected
+   partial template specialization and arguments relative to it.  */
+#define TI_PARTIAL_INFO(NODE) \
+  (gcc_checking_assert (PRIMARY_TEMPLATE_P (TI_TEMPLATE (NODE))), \
+   ((struct tree_template_info*)NODE)->partial)
+
 /* For a given TREE_VEC containing a template argument list,
this property contains the number of arguments that are not
defaulted.  */
@@ -7397,7 +7406,7 @@ extern bool comp_template_args(tree, 
tree, tree * = NULL,
 extern int template_args_equal  (tree, tree, bool = false);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation (tree);
-extern tree most_specialized_partial_spec   (tree, tsubst_flags_t);
+extern tree most_specialized_partial_spec   (tree, tsubst_flags_t, bool = 
false);
 extern void print_candidates   (tree);
 extern void instantiate_pending_templates  (int);
 extern tree tsubst_default_argument(tree, int, tree, tree,
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ecde98d69b4..ea362bdffa4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6364,6 +6364,7 @@ trees_out::core_vals (tree t)
   {
WT (((lang_tree_node *)t)->template_info.tmpl);
WT (((lang_tree_node *)t)->template_info.args);
+   WT 

Re: [PATCH v2 1/3] c++: Track lifetimes in constant evaluation [PR70331, PR96630, PR98675]

2023-06-26 Thread Patrick Palka via Gcc-patches
On Sun, 25 Jun 2023, Nathaniel Shead wrote:

> On Fri, Jun 23, 2023 at 12:43:21PM -0400, Patrick Palka wrote:
> > On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:
> > 
> > > This adds rudimentary lifetime tracking in C++ constexpr contexts,
> > > allowing the compiler to report errors with using values after their
> > > backing has gone out of scope. We don't yet handle other ways of ending
> > > lifetimes (e.g. explicit destructor calls).
> > 
> > Awesome!
> > 
> > > 
> > >   PR c++/96630
> > >   PR c++/98675
> > >   PR c++/70331
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   * constexpr.cc (constexpr_global_ctx::put_value): Mark value as
> > >   in lifetime.
> > >   (constexpr_global_ctx::remove_value): Mark value as expired.
> > >   (cxx_eval_call_expression): Remove comment that is no longer
> > >   applicable.
> > >   (non_const_var_error): Add check for expired values.
> > >   (cxx_eval_constant_expression): Add checks for expired values. Forget
> > >   local variables at end of bind expressions. Forget temporaries at end
> > >   of cleanup points.
> > >   * cp-tree.h (struct lang_decl_base): New flag to track expired values
> > >   in constant evaluation.
> > >   (DECL_EXPIRED_P): Access the new flag.
> > >   (SET_DECL_EXPIRED_P): Modify the new flag.
> > >   * module.cc (trees_out::lang_decl_bools): Write out the new flag.
> > >   (trees_in::lang_decl_bools): Read in the new flag.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   * g++.dg/cpp0x/constexpr-ice20.C: Update error raised by test.
> > >   * g++.dg/cpp1y/constexpr-lifetime1.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime2.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime3.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime4.C: New test.
> > >   * g++.dg/cpp1y/constexpr-lifetime5.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead 
> > > ---
> > >  gcc/cp/constexpr.cc   | 69 +++
> > >  gcc/cp/cp-tree.h  | 10 ++-
> > >  gcc/cp/module.cc  |  2 +
> > >  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  2 +-
> > >  .../g++.dg/cpp1y/constexpr-lifetime1.C| 13 
> > >  .../g++.dg/cpp1y/constexpr-lifetime2.C| 20 ++
> > >  .../g++.dg/cpp1y/constexpr-lifetime3.C| 13 
> > >  .../g++.dg/cpp1y/constexpr-lifetime4.C| 11 +++
> > >  .../g++.dg/cpp1y/constexpr-lifetime5.C| 11 +++
> > >  9 files changed, 137 insertions(+), 14 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> > >  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> > > 
> > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > > index 3de60cfd0f8..bdbc12144a7 100644
> > > --- a/gcc/cp/constexpr.cc
> > > +++ b/gcc/cp/constexpr.cc
> > > @@ -1185,10 +1185,22 @@ public:
> > >void put_value (tree t, tree v)
> > >{
> > >  bool already_in_map = values.put (t, v);
> > > +if (!already_in_map && DECL_P (t))
> > > +  {
> > > + if (!DECL_LANG_SPECIFIC (t))
> > > +   retrofit_lang_decl (t);
> > > + if (DECL_LANG_SPECIFIC (t))
> > > +   SET_DECL_EXPIRED_P (t, false);
> > > +  }
> > 
> > Since this new flag would only be used only during constexpr evaluation,
> > could we instead use an on-the-side hash_set in constexpr_global_ctx for
> > tracking expired-ness?  That way we won't have to allocate a
> > DECL_LANG_SPECIFIC structure for decls that lack it, and won't have to
> > worry about the flag in other parts of the compiler.
> 
> I've tried this but I haven't been able to get it to work well. The main
> issue I'm running into is the caching of function calls in constant
> evaluation. For example, consider the following:
> 
> constexpr const double& test() {
>   const double& local = 3.0;
>   return local;
> }
> 
> constexpr int foo(const double&) { return 5; }
> 
> constexpr int a = foo(test());
> static_assert(test() == 3.0);
> 
> When constant-evaluating 'a', we evaluate 'test()'. It returns a value
> that ends its lifetime immediately, so we mark this in 'ctx->global' as
> expired. However, 'foo()' never actually evaluates this expired value,
> so the initialisation of 'a' succeeds.
> 
> However, then when the static assertion attempts to constant evaluate a
> second time, the result of 'test' has already been cached, and we just
> get directly handed a value. This is a new constant evaluation, so
> 'ctx->global' has been reset, and because we just got the result of the
> cached function we don't actually know whether this is expired or not
> anymore, and so this compiles without any error in case it was valid.

Ouch, good catch..

> 
> I haven't yet been able to come up with a good way 

Re: [PATCH v2 3/3] c++: Improve location information in constexpr evaluation

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> This patch caches the current expression's location information in the
> constexpr_global_ctx struct, which allows subexpressions that have lost
> location information to still provide accurate diagnostics. Also
> rewrites a number of 'error' calls as 'error_at' to provide more
> specific location information.
> 
> The primary effect of this change is that many errors within evaluation
> of a constexpr function will now point at the offending expression (with
> expansion tracing information) rather than just the outermost call.

This seems like a great improvement!

In other parts of the frontend, e.g. during substitution from
tsubst_expr or tsubst_copy_and_build, we do something similar by
setting/restoring input_location directly.  (We've since added the RAII
class iloc_sentinel for this.)  I wonder if that'd be preferable here?

> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (constexpr_global_ctx): New field for cached
>   tree location, defaulting to input_location.
>   (cxx_eval_internal_function): Fall back to ctx->global->loc
>   rather than input_location.
>   (modifying_const_object_error): Likewise.
>   (cxx_eval_dynamic_cast_fn): Likewise.
>   (eval_and_check_array_index): Likewise.
>   (cxx_eval_array_reference): Likewise.
>   (cxx_eval_bit_field_ref): Likewise.
>   (cxx_eval_component_reference): Likewise.
>   (cxx_eval_indirect_ref): Likewise.
>   (cxx_eval_store_expression): Likewise.
>   (cxx_eval_increment_expression): Likewise.
>   (cxx_eval_loop_expr): Likewise.
>   (cxx_eval_binary_expression): Likewise.
>   (cxx_eval_constant_expression): Cache location of trees for use
> in errors, and prefer it instead of input_location.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations.
>   * g++.dg/cpp0x/constexpr-diag3.C: Likewise.
>   * g++.dg/cpp0x/constexpr-ice20.C: Likewise.
>   * g++.dg/cpp1y/constexpr-89481.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime1.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime2.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime3.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime4.C: Likewise.
>   * g++.dg/cpp1y/constexpr-lifetime5.C: Likewise.
>   * g++.dg/cpp1y/constexpr-union5.C: Likewise.
>   * g++.dg/cpp1y/pr68180.C: Likewise.
>   * g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
>   * g++.dg/cpp2a/bit-cast11.C: Likewise.
>   * g++.dg/cpp2a/bit-cast12.C: Likewise.
>   * g++.dg/cpp2a/bit-cast14.C: Likewise.
>   * g++.dg/cpp2a/constexpr-98122.C: Likewise.
>   * g++.dg/cpp2a/constexpr-dynamic17.C: Likewise.
>   * g++.dg/cpp2a/constexpr-init1.C: Likewise.
>   * g++.dg/cpp2a/constexpr-new12.C: Likewise.
>   * g++.dg/cpp2a/constexpr-new3.C: Likewise.
>   * g++.dg/ext/constexpr-vla2.C: Likewise.
>   * g++.dg/ext/constexpr-vla3.C: Likewise.
>   * g++.dg/ubsan/pr63956.C: Likewise.
> 
> libstdc++/ChangeLog:
> 
>   * testsuite/25_algorithms/equal/constexpr_neg.cc: Updated
>   diagnostics locations.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/constexpr.cc   | 83 +++
>  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  | 10 +--
>  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |  3 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C|  1 +
>  .../g++.dg/cpp1y/constexpr-lifetime2.C|  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime3.C|  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime4.C|  2 +-
>  .../g++.dg/cpp1y/constexpr-lifetime5.C|  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/pr68180.C  |  4 +-
>  .../g++.dg/cpp1z/constexpr-lambda6.C  |  4 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   | 14 ++--
>  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |  4 +-
>  .../g++.dg/cpp2a/constexpr-dynamic17.C|  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |  6 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   | 10 +--
>  gcc/testsuite/g++.dg/ext/constexpr-vla2.C |  4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla3.C |  4 +-
>  gcc/testsuite/g++.dg/ubsan/pr63956.C  |  4 +-
>  .../25_algorithms/equal/constexpr_neg.cc  |  7 +-
>  25 files changed, 111 insertions(+), 101 deletions(-)
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index bdbc12144a7..74045477a92 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1165,10 +1165,12 @@ public:
>hash_set *modifiable;
>/* Number of heap VAR_DECL deallocations.  */
>unsigned 

Re: [PATCH v2 2/3] c++: Improve constexpr error for dangling local variables

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> Currently, when typeck discovers that a return statement will refer to a
> local variable it rewrites to return a null pointer. This causes the
> error messages for using the return value in a constant expression to be
> unhelpful, especially for reference return values.
> 
> This patch removes this "optimisation". Relying on this raises a warning
> by default and causes UB anyway, so there should be no issue in doing
> so. We also suppress additional warnings from later passes that detect
> this as a dangling pointer, since we've already indicated this anyway.

LGTM.  It seems the original motivation for returning a null pointer
here was to avoid issuing duplicate warnings
(https://gcc.gnu.org/legacy-ml/gcc-patches/2014-04/msg00269.html)
which your patch addresses.

> 
> gcc/cp/ChangeLog:
> 
>   * semantics.cc (finish_return_stmt): Suppress dangling pointer
> reporting on return statement if already reported.
>   * typeck.cc (check_return_expr): Don't set return expression to
> zero for dangling addresses.
> 
> gcc/testsuite/ChangeLog:
> 
> * g++.dg/cpp1y/constexpr-lifetime5.C: Test reported message is
> correct.
>   * g++.dg/warn/Wreturn-local-addr-6.C: Remove check for return
> value optimisation.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/semantics.cc  | 5 -
>  gcc/cp/typeck.cc | 5 +++--
>  gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C | 4 ++--
>  gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C | 3 ---
>  4 files changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 87c2e8a7111..14b4b7f4ce1 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -1246,7 +1246,10 @@ finish_return_stmt (tree expr)
>  
>r = build_stmt (input_location, RETURN_EXPR, expr);
>if (no_warning)
> -suppress_warning (r, OPT_Wreturn_type);
> +{
> +  suppress_warning (r, OPT_Wreturn_type);
> +  suppress_warning (r, OPT_Wdangling_pointer_);
> +}
>r = maybe_cleanup_point_expr_void (r);
>r = add_stmt (r);
>  
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index afb956087ce..a7d642e2029 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -11235,8 +11235,9 @@ check_return_expr (tree retval, bool *no_warning)
>else if (!processing_template_decl
>  && maybe_warn_about_returning_address_of_local (retval, loc)
>  && INDIRECT_TYPE_P (valtype))
> - retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
> -  build_zero_cst (TREE_TYPE (retval)));
> + /* Suppress the Wdangling-pointer warning in the return statement
> +that would otherwise occur.  */
> + *no_warning = true;
>  }
>  
>if (processing_template_decl)
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C 
> b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> index a4bc71d890a..ad3ef579f63 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> @@ -1,11 +1,11 @@
>  // { dg-do compile { target c++14 } }
>  // { dg-options "-Wno-return-local-addr" }
>  
> -constexpr const int& id(int x) { return x; }
> +constexpr const int& id(int x) { return x; }  // { dg-message "note: 
> declared here" }
>  
>  constexpr bool test() {
>const int& y = id(3);
>return y == 3;
>  }
>  
> -constexpr bool x = test();  // { dg-error "" }
> +constexpr bool x = test();  // { dg-error "accessing object outside its 
> lifetime" }
> diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C 
> b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> index fae8b7e766f..ec8e241d83e 100644
> --- a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> +++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
> @@ -24,6 +24,3 @@ return_addr_local_as_intref (void)
>  
>return (const intptr_t&)a;   // { dg-warning "\\\[-Wreturn-local-addr]" } 
> */
>  }
> -
> -/* Verify that the return value has been replaced with zero:
> -  { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
> -- 
> 2.34.1
> 
> 



Re: [PATCH v2 1/3] c++: Track lifetimes in constant evaluation [PR70331, PR96630, PR98675]

2023-06-23 Thread Patrick Palka via Gcc-patches
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> This adds rudimentary lifetime tracking in C++ constexpr contexts,
> allowing the compiler to report errors with using values after their
> backing has gone out of scope. We don't yet handle other ways of ending
> lifetimes (e.g. explicit destructor calls).

Awesome!

> 
>   PR c++/96630
>   PR c++/98675
>   PR c++/70331
> 
> gcc/cp/ChangeLog:
> 
>   * constexpr.cc (constexpr_global_ctx::put_value): Mark value as
>   in lifetime.
>   (constexpr_global_ctx::remove_value): Mark value as expired.
>   (cxx_eval_call_expression): Remove comment that is no longer
>   applicable.
>   (non_const_var_error): Add check for expired values.
>   (cxx_eval_constant_expression): Add checks for expired values. Forget
>   local variables at end of bind expressions. Forget temporaries at end
>   of cleanup points.
>   * cp-tree.h (struct lang_decl_base): New flag to track expired values
>   in constant evaluation.
>   (DECL_EXPIRED_P): Access the new flag.
>   (SET_DECL_EXPIRED_P): Modify the new flag.
>   * module.cc (trees_out::lang_decl_bools): Write out the new flag.
>   (trees_in::lang_decl_bools): Read in the new flag.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/cpp0x/constexpr-ice20.C: Update error raised by test.
>   * g++.dg/cpp1y/constexpr-lifetime1.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime2.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime3.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime4.C: New test.
>   * g++.dg/cpp1y/constexpr-lifetime5.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/constexpr.cc   | 69 +++
>  gcc/cp/cp-tree.h  | 10 ++-
>  gcc/cp/module.cc  |  2 +
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  2 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C| 13 
>  .../g++.dg/cpp1y/constexpr-lifetime2.C| 20 ++
>  .../g++.dg/cpp1y/constexpr-lifetime3.C| 13 
>  .../g++.dg/cpp1y/constexpr-lifetime4.C| 11 +++
>  .../g++.dg/cpp1y/constexpr-lifetime5.C| 11 +++
>  9 files changed, 137 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 3de60cfd0f8..bdbc12144a7 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1185,10 +1185,22 @@ public:
>void put_value (tree t, tree v)
>{
>  bool already_in_map = values.put (t, v);
> +if (!already_in_map && DECL_P (t))
> +  {
> + if (!DECL_LANG_SPECIFIC (t))
> +   retrofit_lang_decl (t);
> + if (DECL_LANG_SPECIFIC (t))
> +   SET_DECL_EXPIRED_P (t, false);
> +  }

Since this new flag would only be used only during constexpr evaluation,
could we instead use an on-the-side hash_set in constexpr_global_ctx for
tracking expired-ness?  That way we won't have to allocate a
DECL_LANG_SPECIFIC structure for decls that lack it, and won't have to
worry about the flag in other parts of the compiler.

>  if (!already_in_map && modifiable)
>modifiable->add (t);
>}
> -  void remove_value (tree t) { values.remove (t); }
> +  void remove_value (tree t)
> +  {
> +if (DECL_P (t) && DECL_LANG_SPECIFIC (t))
> +  SET_DECL_EXPIRED_P (t, true);
> +values.remove (t);
> +  }
>  };
>  
>  /* Helper class for constexpr_global_ctx.  In some cases we want to avoid
> @@ -3157,10 +3169,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
> tree t,
> for (tree save_expr : save_exprs)
>   ctx->global->remove_value (save_expr);
>  
> -   /* Remove the parms/result from the values map.  Is it worth
> -  bothering to do this when the map itself is only live for
> -  one constexpr evaluation?  If so, maybe also clear out
> -  other vars from call, maybe in BIND_EXPR handling?  */
> +   /* Remove the parms/result from the values map.  */
> ctx->global->remove_value (res);
> for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
>   ctx->global->remove_value (parm);
> @@ -5708,6 +5717,13 @@ non_const_var_error (location_t loc, tree r, bool 
> fundef_p)
>   inform (DECL_SOURCE_LOCATION (r), "allocated here");
>return;
>  }
> +  if (DECL_EXPIRED_P (r))
> +{
> +  if (constexpr_error (loc, fundef_p, "accessing object outside its "
> +"lifetime"))
> + inform (DECL_SOURCE_LOCATION (r), "declared here");
> +  return;
> +}
>if (!constexpr_error (loc, fundef_p, "the value of 

Re: [PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-23 Thread Patrick Palka via Gcc-patches
On Fri, 23 Jun 2023, Jason Merrill wrote:

> On 6/21/23 13:19, Patrick Palka wrote:
> > When stepping through the variable/alias template specialization code
> > paths, I noticed we perform template argument coercion twice: first from
> > instantiate_alias_template / finish_template_variable and again from
> > tsubst_decl (during instantiate_template).  It should suffice to perform
> > coercion once.
> > 
> > To that end patch elides this second coercion from tsubst_decl when
> > possible.  We can't get rid of it completely because we don't always
> > specialize a variable template from finish_template_variable: we could
> > also be doing so directly from instantiate_template during variable
> > template partial specialization selection, in which case the coercion
> > from tsubst_decl would be the first and only coercion.
> 
> Perhaps we should be coercing in lookup_template_variable rather than
> finish_template_variable?

Ah yes, there's a patch for that at
https://gcc.gnu.org/pipermail/gcc-patches/2023-May/617377.html :)

> It looks like we currently get to
> most_specialized_partial_spec with args that haven't yet been coerced to match
> the primary template.

The call to most_specialized_partial_spec from instantiate_template?
I believe the arguments should already have been coerced by the
caller, which is presumably always finish_template_variable.

So in that patch I also made instantiate_template use
build2 (TEMPLATE_ID_EXPR, ...) directly instead of calling
lookup_template_variable, to avoid an unnecessary double coercion.

> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?  This reduces memory usage of range-v3's zip.cpp by ~0.5%.
> > 
> > gcc/cp/ChangeLog:
> > 
> > * pt.cc (tsubst_decl) : Call
> > coercion_template_parms only if DECL_TEMPLATE_SPECIALIZATION
> > is set.
> > ---
> >   gcc/cp/pt.cc | 15 +++
> >   1 file changed, 11 insertions(+), 4 deletions(-)
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index be86051abad..dd10409ce18 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -15232,10 +15232,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t
> > complain)
> > argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
> > if (argvec != error_mark_node
> > && PRIMARY_TEMPLATE_P (gen_tmpl)
> > -   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
> > - /* We're fully specializing a template declaration, so
> > -we need to coerce the innermost arguments corresponding
> > to
> > -the template.  */
> > +   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec)
> > +   && DECL_TEMPLATE_SPECIALIZATION (t))
> > + /* We're fully specializing an alias or variable template,
> > so
> > +coerce the innermost arguments if necessary.  We expect
> > +instantiate_alias_template and finish_template_variable
> > to
> > +already have done this relative to the primary template,
> > in
> > +which case this coercion is unnecessary, but we can also
> > +get here when substituting a partial variable template
> > +specialization (directly from instantiate_template), in
> > +which case DECL_TEMPLATE_SPECIALIZATION is set and
> > coercion
> > +is necessary.  */
> >   argvec = (coerce_template_parms
> > (DECL_TEMPLATE_PARMS (gen_tmpl),
> >  argvec, tmpl, complain));
> 
> 



Re: [PATCH] c++: Report invalid id-expression in decltype [PR100482]

2023-06-23 Thread Patrick Palka via Gcc-patches
On Sun, 30 Apr 2023, Nathaniel Shead via Gcc-patches wrote:

> This patch ensures that any errors raised by finish_id_expression when
> parsing a decltype expression are properly reported, rather than
> potentially going ignored and causing invalid code to be accepted.
> 
> We can also now remove the separate check for templates without args as
> this is also checked for in finish_id_expression.
> 
>   PR 100482
> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_decltype_expr): Report errors raised by
>   finish_id_expression.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/pr100482.C: New test.

LGTM.  Some minor comments about the new testcase below:

> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc| 22 +++---
>  gcc/testsuite/g++.dg/pr100482.C | 11 +++
>  2 files changed, 22 insertions(+), 11 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/pr100482.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index e5f032f2330..20ebcdc3cfd 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -16508,10 +16508,6 @@ cp_parser_decltype_expr (cp_parser *parser,
>   expr = cp_parser_lookup_name_simple (parser, expr,
>id_expr_start_token->location);
>  
> -  if (expr && TREE_CODE (expr) == TEMPLATE_DECL)
> - /* A template without args is not a complete id-expression.  */
> - expr = error_mark_node;
> -
>if (expr
>&& expr != error_mark_node
>&& TREE_CODE (expr) != TYPE_DECL
> @@ -16532,13 +16528,17 @@ cp_parser_decltype_expr (cp_parser *parser,
> _msg,
>  id_expr_start_token->location));
>  
> -  if (expr == error_mark_node)
> -/* We found an id-expression, but it was something that we
> -   should not have found. This is an error, not something
> -   we can recover from, so note that we found an
> -   id-expression and we'll recover as gracefully as
> -   possible.  */
> -id_expression_or_member_access_p = true;
> +   if (error_msg)
> + {
> +   /* We found an id-expression, but it was something that we
> +  should not have found. This is an error, not something
> +  we can recover from, so report the error we found and
> +  we'll recover as gracefully as possible.  */
> +   cp_parser_parse_definitely (parser);
> +   cp_parser_error (parser, error_msg);
> +   id_expression_or_member_access_p = true;
> +   return error_mark_node;
> + }
>  }
>  
>if (expr
> diff --git a/gcc/testsuite/g++.dg/pr100482.C b/gcc/testsuite/g++.dg/pr100482.C
> new file mode 100644
> index 000..dcf6722fda5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr100482.C

We generally prefer to organize tests according to the language dialect
they apply to and the langugae construct that they're primarily testing.
In this case we could name the test e.g.

  gcc/testsuite/g++.dg/cpp0x/decltype-100482.C

> @@ -0,0 +1,11 @@
> +// { dg-do compile { target c++10 } }

We also usually mention the PR number in the test as a comment:

// PR c++/100482

One benefit of doing so is that the git alias 'git gcc-commit-mklog'
(https://gcc.gnu.org/gitwrite.html#vendor) will then automatically
include the PR number in the commit message template.

> +
> +namespace N {}
> +decltype(std) x;   // { dg-error "expected primary-expression" }
> +
> +struct S {};
> +decltype(S) y;  // { dg-error "argument to .decltype. must be an expression" 
> }
> +
> +template 
> +struct U {};
> +decltype(U) z;  // { dg-error "missing template arguments" }
> -- 
> 2.40.0
> 
> 



Re: [PATCH] c++: Fix ICE with parameter pack of decltype(auto) [PR103497]

2023-06-23 Thread Patrick Palka via Gcc-patches
Hi,

On Sat, 22 Apr 2023, Nathaniel Shead via Gcc-patches wrote:

> Bootstrapped and tested on x86_64-pc-linux-gnu.
> 
> -- 8< --
> 
> This patch raises an error early when the decltype(auto) specifier is
> used as a parameter of a function. This prevents any issues with an
> unexpected tree type later on when performing the call.

Thanks very much for the patch!  Some minor comments below.

> 
>   PR 103497

We should include the bug component name when referring to the PR in the
commit message (i.e. PR c++/103497) so that upon pushing the patch the
post-commit hook automatically adds a comment to the PR reffering to the
commit.  I could be wrong but AFAIK the hook only performs this when the
component name is included.

> 
> gcc/cp/ChangeLog:
> 
>   * parser.cc (cp_parser_simple_type_specifier): Add check for
>   decltype(auto) as function parameter.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/pr103497.C: New test.
> 
> Signed-off-by: Nathaniel Shead 
> ---
>  gcc/cp/parser.cc| 10 ++
>  gcc/testsuite/g++.dg/pr103497.C |  7 +++
>  2 files changed, 17 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/pr103497.C
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index e5f032f2330..1415e07e152 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -19884,6 +19884,16 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
>  {
>type = saved_checks_value (token->u.tree_check_value);
> +  /* Within a function parameter declaration, decltype(auto) is always an
> +  error.  */
> +  if (parser->auto_is_implicit_function_template_parm_p
> +   && TREE_CODE (type) == TEMPLATE_TYPE_PARM

We could check is_auto (type) here instead, to avoid any confusion with
checking AUTO_IS_DECLTYPE for a non-auto TEMPLATE_TYPE_PARM.

> +   && AUTO_IS_DECLTYPE (type))
> + {
> +   error_at (token->location,
> + "cannot declare a parameter with %");
> +   type = error_mark_node;
> + }
>if (decl_specs)
>   {
> cp_parser_set_decl_spec_type (decl_specs, type,
> diff --git a/gcc/testsuite/g++.dg/pr103497.C b/gcc/testsuite/g++.dg/pr103497.C
> new file mode 100644
> index 000..bcd421c2907
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr103497.C
> @@ -0,0 +1,7 @@
> +// { dg-do compile { target c++14 } }
> +
> +void foo(decltype(auto)... args);  // { dg-error "parameter with 
> .decltype.auto..|no parameter packs" }

I noticed for

  void foo(decltype(auto) arg);

we already issue an identical error from grokdeclarator.  Perhaps we could
instead extend the error handling there to detect decltype(auto)... as well,
rather than adding new error handling in cp_parser_simple_type_specifier?

> +
> +int main() {
> +  foo();
> +}
> -- 
> 2.34.1
> 
> 



[PATCH] c++: redundant targ coercion for var/alias tmpls

2023-06-21 Thread Patrick Palka via Gcc-patches
When stepping through the variable/alias template specialization code
paths, I noticed we perform template argument coercion twice: first from
instantiate_alias_template / finish_template_variable and again from
tsubst_decl (during instantiate_template).  It should suffice to perform
coercion once.

To that end patch elides this second coercion from tsubst_decl when
possible.  We can't get rid of it completely because we don't always
specialize a variable template from finish_template_variable: we could
also be doing so directly from instantiate_template during variable
template partial specialization selection, in which case the coercion
from tsubst_decl would be the first and only coercion.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  This reduces memory usage of range-v3's zip.cpp by ~0.5%.

gcc/cp/ChangeLog:

* pt.cc (tsubst_decl) : Call
coercion_template_parms only if DECL_TEMPLATE_SPECIALIZATION
is set.
---
 gcc/cp/pt.cc | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index be86051abad..dd10409ce18 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -15232,10 +15232,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
if (argvec != error_mark_node
&& PRIMARY_TEMPLATE_P (gen_tmpl)
-   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec))
- /* We're fully specializing a template declaration, so
-we need to coerce the innermost arguments corresponding to
-the template.  */
+   && TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (argvec)
+   && DECL_TEMPLATE_SPECIALIZATION (t))
+ /* We're fully specializing an alias or variable template, so
+coerce the innermost arguments if necessary.  We expect
+instantiate_alias_template and finish_template_variable to
+already have done this relative to the primary template, in
+which case this coercion is unnecessary, but we can also
+get here when substituting a partial variable template
+specialization (directly from instantiate_template), in
+which case DECL_TEMPLATE_SPECIALIZATION is set and coercion
+is necessary.  */
  argvec = (coerce_template_parms
(DECL_TEMPLATE_PARMS (gen_tmpl),
 argvec, tmpl, complain));
-- 
2.41.0.113.g6640c2d06d



Re: [PATCH 2/2] libstdc++: use new built-in trait __is_const

2023-06-20 Thread Patrick Palka via Gcc-patches
On Tue, 21 Mar 2023, Ken Matsui wrote:

> This patch lets libstdc++ use new built-in trait __is_const.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_const): Use __is_const built-in trait.

We should also use it in is_const_v (likewise for the __is_array and
__is_volatile patches).

> ---
>  libstdc++-v3/include/std/type_traits | 7 +++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 2bd607a8b8f..e77de828501 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -764,6 +764,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Type properties.
>  
>/// is_const
> +#if __has_builtin(__is_const)
> +  template
> +struct is_const
> +: public __bool_constant<__is_const(_Tp)>
> +{ };
> +#else
>template
>  struct is_const
>  : public false_type { };
> @@ -771,6 +777,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_const<_Tp const>
>  : public true_type { };
> +#endif
>  
>/// is_volatile
>template
> -- 
> 2.40.0
> 
> 



Re: [PATCH v7 2/6] libstdc++: use new built-in trait __is_reference for std::is_reference

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch gets std::is_reference to dispatch to new built-in trait
> __is_reference.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_reference): Use __is_reference built-in
>   trait.
>   (is_reference_v): Likewise.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 14 ++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 0e7a9c9c7f3..2a14df7e5f9 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -639,6 +639,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>// Composite type categories.
>  
>/// is_reference
> +#if __has_builtin(__is_reference)
> +  template
> +struct is_reference
> +: public __bool_constant<__is_reference(_Tp)>
> +{ };
> +#else
>template
>  struct is_reference
>  : public false_type
> @@ -653,6 +659,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  struct is_reference<_Tp&&>
>  : public true_type
>  { };
> +#endif
>  
>/// is_arithmetic
>template
> @@ -3192,12 +3199,19 @@ template 
>inline constexpr bool is_class_v = __is_class(_Tp);
>  template 
>inline constexpr bool is_function_v = is_function<_Tp>::value;
> +
> +#if __has_builtin(__is_reference)
> +template 
> +  inline constexpr bool is_reference_v = __is_reference(_Tp);
> +#else
>  template 
>inline constexpr bool is_reference_v = false;
>  template 
>inline constexpr bool is_reference_v<_Tp&> = true;
>  template 
>inline constexpr bool is_reference_v<_Tp&&> = true;
> +#endif
> +
>  template 
>inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
>  template 
> -- 
> 2.41.0
> 
> 



Re: [PATCH v7 1/6] c++: implement __is_reference built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_reference.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_reference.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
>   * g++.dg/ext/is_reference.C: New test.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 +++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
>  gcc/testsuite/g++.dg/ext/is_reference.C  | 34 
>  5 files changed, 45 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 8cf0f2d0974..f6951ee2670 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3705,6 +3705,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_HAS_VIRTUAL_DESTRUCTOR:
>inform (loc, "  %qT does not have a virtual destructor", t1);
>break;
> +case CPTK_IS_REFERENCE:
> +  inform (loc, "  %qT is not a reference", t1);
> +  break;
>  case CPTK_IS_ABSTRACT:
>inform (loc, "  %qT is not an abstract class", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 8b7fece0cc8..1e3310cd682 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -67,6 +67,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
>  DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
>  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
>  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
> +DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
>  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
>  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
>  DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index a2e74a5d2c7..2f37bc353a1 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12075,6 +12075,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> +case CPTK_IS_REFERENCE:
> +  return type_code1 == REFERENCE_TYPE;
> +
>  case CPTK_IS_LAYOUT_COMPATIBLE:
>return layout_compatible_type_p (type1, type2);
>  
> @@ -12289,6 +12292,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_ENUM:
>  case CPTK_IS_UNION:
>  case CPTK_IS_SAME:
> +case CPTK_IS_REFERENCE:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index f343e153e56..b697673790c 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -146,3 +146,6 @@
>  #if !__has_builtin (__remove_cvref)
>  # error "__has_builtin (__remove_cvref) failed"
>  #endif
> +#if !__has_builtin (__is_reference)
> +# error "__has_builtin (__is_reference) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C 
> b/gcc/testsuite/g++.dg/ext/is_reference.C
> new file mode 100644
> index 000..b5ce4db7afd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_reference.C
> @@ -0,0 +1,34 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +// Positive tests.
> +SA_TEST_CATEGORY(__is_reference, int&, true);
> +SA_TEST_CATEGORY(__is_reference, ClassType&, true);
> +SA(__is_reference(int(&)(int)));
> +SA_TEST_CATEGORY(__is_reference, int&&, true);
> +SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
> +SA(__is_reference(int(&&)(int)));
> +SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
> +
> +// Negative tests
> +SA_TEST_CATEGORY(__is_reference, void, false);
> +SA_TEST_CATEGORY(__is_reference, int*, false);
> +SA_TEST_CATEGORY(__is_reference, int[3], false);
> +SA(!__is_reference(int(int)));
> +SA(!__is_reference(int(*const)(int)));
> +SA(!__is_reference(int(*volatile)(int)));
> +SA(!__is_reference(int(*const volatile)(int)));
> +
> +// Sanity check.
> +SA_TEST_CATEGORY(__is_reference, ClassType, false);
> +SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
> -- 
> 2.41.0
> 
> 



Re: [PATCH v7 3/6] c++: implement __is_function built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Gcc-patches wrote:

> This patch implements built-in trait for std::is_function.
> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_function.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
>   * g++.dg/ext/is_function.C: New test.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc |  3 ++
>  gcc/cp/cp-trait.def  |  1 +
>  gcc/cp/semantics.cc  |  4 ++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
>  gcc/testsuite/g++.dg/ext/is_function.C   | 58 
>  5 files changed, 69 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index f6951ee2670..927605c6cb7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3754,6 +3754,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_UNION:
>inform (loc, "  %qT is not a union", t1);
>break;
> +case CPTK_IS_FUNCTION:
> +  inform (loc, "  %qT is not a function", t1);
> +  break;
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 1e3310cd682..3cd3babc242 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, 
> "__is_trivially_assignable", 2)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", 
> -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
> +DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
> "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
> "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 2f37bc353a1..b976633645a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12072,6 +12072,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_ENUM:
>return type_code1 == ENUMERAL_TYPE;
>  
> +case CPTK_IS_FUNCTION:
> +  return type_code1 == FUNCTION_TYPE;
> +
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12293,6 +12296,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_UNION:
>  case CPTK_IS_SAME:
>  case CPTK_IS_REFERENCE:
> +case CPTK_IS_FUNCTION:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index b697673790c..90eb00ebf2d 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -149,3 +149,6 @@
>  #if !__has_builtin (__is_reference)
>  # error "__has_builtin (__is_reference) failed"
>  #endif
> +#if !__has_builtin (__is_function)
> +# error "__has_builtin (__is_function) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_function.C 
> b/gcc/testsuite/g++.dg/ext/is_function.C
> new file mode 100644
> index 000..2e1594b12ad
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_function.C
> @@ -0,0 +1,58 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include 
> +
> +using namespace __gnu_test;
> +
> +#define SA(X) static_assert((X),#X)
> +#define SA_TEST_CATEGORY(TRAIT, TYPE, EXPECT)\
> +  SA(TRAIT(TYPE) == EXPECT); \
> +  SA(TRAIT(const TYPE) == EXPECT);   \
> +  SA(TRAIT(volatile TYPE) == EXPECT);\
> +  SA(TRAIT(const volatile TYPE) == EXPECT)
> +
> +struct A
> +{ void fn(); };
> +
> +template
> +struct AHolder { };
> +
> +template
> +struct AHolder
> +{ using type = U; };
> +
> +// Positive tests.
> +SA(__is_function(int (int)));
> +SA(__is_function(ClassType (ClassType)));
> +SA(__is_function(float (int, float, int[], int&)));
> +SA(__is_function(int (int, ...)));
> +SA(__is_function(bool (ClassType) const));
> +SA(__is_function(AHolder::type));
> +
> +void fn();
> +SA(__is_function(decltype(fn)));
> +
> +// Negative tests.
> +SA_TEST_CATEGORY(__is_function, int, false);
> +SA_TEST_CATEGORY(__is_function, int*, false);
> +SA_TEST_CATEGORY(__is_function, int&, false);
> +SA_TEST_CATEGORY(__is_function, void, false);
> +SA_TEST_CATEGORY(__is_function, void*, false);
> +SA_TEST_CATEGORY(__is_function, void**, false);
> +SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
> +
> +SA_TEST_CATEGORY(__is_function, 

Re: [PATCH v7 4/6] libstdc++: use new built-in trait __is_function for std::is_function

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch gets std::is_function to dispatch to new built-in trait
> __is_function.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/std/type_traits (is_function): Use __is_function built-in
>   trait.
>   (is_function_v): Likewise.

LGTM

> 
> Signed-off-by: Ken Matsui 
> ---
>  libstdc++-v3/include/std/type_traits | 13 +
>  1 file changed, 13 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits 
> b/libstdc++-v3/include/std/type_traits
> index 2a14df7e5f9..954b57518de 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -594,6 +594,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>  { };
>  
>/// is_function
> +#if __has_builtin(__is_function)
> +  template
> +struct is_function
> +: public __bool_constant<__is_function(_Tp)>
> +{ };
> +#else
>template
>  struct is_function
>  : public __bool_constant::value> { };
> @@ -605,6 +611,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>template
>  struct is_function<_Tp&&>
>  : public false_type { };
> +#endif
>  
>  #define __cpp_lib_is_null_pointer 201309L
>  
> @@ -3197,8 +3204,14 @@ template 
>inline constexpr bool is_union_v = __is_union(_Tp);
>  template 
>inline constexpr bool is_class_v = __is_class(_Tp);
> +
> +#if __has_builtin(__is_function)
> +template 
> +  inline constexpr bool is_function_v = __is_function(_Tp);
> +#else
>  template 
>inline constexpr bool is_function_v = is_function<_Tp>::value;
> +#endif
>  
>  #if __has_builtin(__is_reference)
>  template 
> -- 
> 2.41.0
> 
> 



Re: [PATCH v7 5/6] c++, libstdc++: implement __is_void built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Mon, 12 Jun 2023, Ken Matsui via Libstdc++ wrote:

> This patch implements built-in trait for std::is_void. Since the new built-in
> name is __is_void, to avoid unintentional macro replacement, this patch also
> involves the removal of the existing __is_void in helper_functions.h and
> cpp_type_traits.h and renaming __is_void to is_void in the test file,
> pr46567.C.

Hmm, I suspect an __is_void built-in won't show an improvement over
the current is_void implementation in terms of four explicit specializations.
And given the __is_void name conflict in cpp_type_traits.h (which means
GCC trunk will reject older libstdc++ headers at least until we get
smarter about how we recognize built-ins), I'm leaning towards not
implementing an __is_void built-in for now.

In that case we should probably define a built-in for is_object since
we can no longer implement it solely in terms of other built-ins, and
fortunately the name __is_object seems to never have been used in
libstdc++ so we won't have to deal with any name conflicts unlike with
__is_void.

Jonathan, what do you think?

> 
> gcc/cp/ChangeLog:
> 
>   * cp-trait.def: Define __is_void.
>   * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOID.
>   * semantics.cc (trait_expr_value): Likewise.
>   (finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>   * g++.dg/tm/pr46567.C (__is_void): Rename to ...
>   (is_void): ... this.
>   * g++.dg/ext/has-builtin-1.C: Test existence of __is_void.
>   * g++.dg/ext/is_void.C: New test.
> 
> libstdc++-v3/ChangeLog:
> 
>   * include/debug/helper_functions.h (_DiffTraits): Stop using
>   __is_void.
>   * include/bits/cpp_type_traits.h (__is_void): Remove unused __is_void.
>   * include/std/type_traits (is_void_v): Use __is_void built-in
>   trait.
> 
> Signed-off-by: Ken Matsui 
> ---
>  gcc/cp/constraint.cc  |  3 ++
>  gcc/cp/cp-trait.def   |  1 +
>  gcc/cp/semantics.cc   |  4 +++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
>  gcc/testsuite/g++.dg/ext/is_void.C| 35 +++
>  gcc/testsuite/g++.dg/tm/pr46567.C |  6 ++--
>  libstdc++-v3/include/bits/cpp_type_traits.h   | 15 
>  libstdc++-v3/include/debug/helper_functions.h |  5 ++-
>  libstdc++-v3/include/std/type_traits  |  6 
>  9 files changed, 57 insertions(+), 21 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 927605c6cb7..e8cd98eb2c7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3757,6 +3757,9 @@ diagnose_trait_expr (tree expr, tree args)
>  case CPTK_IS_FUNCTION:
>inform (loc, "  %qT is not a function", t1);
>break;
> +case CPTK_IS_VOID:
> +  inform (loc, "  %qT is not a void type", t1);
> +  break;
>  case CPTK_IS_AGGREGATE:
>inform (loc, "  %qT is not an aggregate", t1);
>break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 3cd3babc242..8e76668f6ed 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -84,6 +84,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, 
> "__is_trivially_constructible", -1)
>  DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
>  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_VOID, "__is_void", 1)
>  DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, 
> "__reference_constructs_from_temporary", 2)
>  DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, 
> "__reference_converts_from_temporary", 2)
>  /* FIXME Added space to avoid direct usage in GCC 13.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index b976633645a..c4d44413dce 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12075,6 +12075,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, 
> tree type2)
>  case CPTK_IS_FUNCTION:
>return type_code1 == FUNCTION_TYPE;
>  
> +case CPTK_IS_VOID:
> +  return VOID_TYPE_P (type1);
> +
>  case CPTK_IS_FINAL:
>return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
>  
> @@ -12297,6 +12300,7 @@ finish_trait_expr (location_t loc, cp_trait_kind 
> kind, tree type1, tree type2)
>  case CPTK_IS_SAME:
>  case CPTK_IS_REFERENCE:
>  case CPTK_IS_FUNCTION:
> +case CPTK_IS_VOID:
>break;
>  
>  case CPTK_IS_LAYOUT_COMPATIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index 90eb00ebf2d..b96cc9e6f50 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -152,3 +152,6 @@
>  #if !__has_builtin (__is_function)
>  # error "__has_builtin (__is_function) failed"
>  #endif
> +#if !__has_builtin (__is_void)
> +# error "__has_builtin (__is_void) failed"
> +#endif
> diff --git 

Re: [PATCH v7 0/6] c++, libstdc++: get std::is_object to dispatch to new built-in traits

2023-06-20 Thread Patrick Palka via Gcc-patches
On Thu, 15 Jun 2023, Ken Matsui via Libstdc++ wrote:

> Hi,
> 
> For those curious about the performance improvements of this patch, I
> conducted a benchmark that instantiates 256k specializations of
> is_object_v based on Patrick's code. You can find the benchmark code
> at this link:
> 
> https://github.com/ken-matsui/gcc-benches/blob/main/is_object_benchmark.cc
> 
> On my computer, using the gcc HEAD of this patch for a release build,
> the patch with -DUSE_BUILTIN took 64% less time and used 44-47% less
> memory compared to not using it.

That's more like it :D  Though the benchmark should also invoke the
trait on non-object types too, e.g. Instantiator& or Instantiator(int).

> 
> Sincerely,
> Ken Matsui
> 
> On Mon, Jun 12, 2023 at 3:49 PM Ken Matsui  wrote:
> >
> > Hi,
> >
> > This patch series gets std::is_object to dispatch to built-in traits and
> > implements the following built-in traits, on which std::object depends.
> >
> > * __is_reference
> > * __is_function
> > * __is_void
> >
> > std::is_object was depending on them with disjunction and negation.
> >
> > __not_<__or_, is_reference<_Tp>, is_void<_Tp>>>::type
> >
> > Therefore, this patch uses them directly instead of implementing an 
> > additional
> > built-in trait __is_object, which makes the compiler slightly bigger and
> > slower.
> >
> > __bool_constant > __is_void(_Tp))>
> >
> > This would instantiate only __bool_constant and 
> > __bool_constant,
> > which can be mostly shared. That is, the purpose of built-in traits is
> > considered as achieved.
> >
> > Changes in v7
> >
> > * Removed an unnecessary new line.
> >
> > Ken Matsui (6):
> >   c++: implement __is_reference built-in trait
> >   libstdc++: use new built-in trait __is_reference for std::is_reference
> >   c++: implement __is_function built-in trait
> >   libstdc++: use new built-in trait __is_function for std::is_function
> >   c++, libstdc++: implement __is_void built-in trait
> >   libstdc++: make std::is_object dispatch to new built-in traits
> >
> >  gcc/cp/constraint.cc  |  9 +++
> >  gcc/cp/cp-trait.def   |  3 +
> >  gcc/cp/semantics.cc   | 12 
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  9 +++
> >  gcc/testsuite/g++.dg/ext/is_function.C| 58 +++
> >  gcc/testsuite/g++.dg/ext/is_reference.C   | 34 +++
> >  gcc/testsuite/g++.dg/ext/is_void.C| 35 +++
> >  gcc/testsuite/g++.dg/tm/pr46567.C |  6 +-
> >  libstdc++-v3/include/bits/cpp_type_traits.h   | 15 -
> >  libstdc++-v3/include/debug/helper_functions.h |  5 +-
> >  libstdc++-v3/include/std/type_traits  | 51 
> >  11 files changed, 216 insertions(+), 21 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_void.C
> >
> > --
> > 2.41.0
> >
> 
> 


Re: [PATCH 1/2] c++: implement __remove_pointer built-in trait

2023-06-20 Thread Patrick Palka via Gcc-patches
On Sat, 17 Jun 2023, Ken Matsui via Gcc-patches wrote:

> Hi,
> 
> I conducted a benchmark for remove_pointer as well as is_object. Just
> like the is_object benchmark, here is the benchmark code:
> 
> https://github.com/ken-matsui/gcc-benches/blob/main/remove_pointer_benchmark.cc
> 
> On my computer, using the gcc HEAD of this patch for a release build,
> the patch with -DUSE_BUILTIN took 8.7% less time and used 4.3-4.9%
> less memory on average compared to not using it. Although the
> performance improvement was not as significant as with is_object, the
> benchmark demonstrated that the compilation was consistently more
> efficient.

Thanks for the benchmark.  The improvement is lesser than I expected,
but that might be because the benchmark is "biased":

  template 
  struct Instantiator : Instantiator {
  static_assert(!std::is_pointer_v>);
  };

This only invokes remove_pointer_t on the non-pointer type Instantiator,
and so the benchmark doesn't factor in the performance of the trait when
invoked on pointer types, and traits typically will have different
performance characteristics depending on the kind of type it's given.

To more holistically assess the real-world performance of the trait the
benchmark should also consider pointer types and maybe also cv-qualified
types (given that the original implementation is in terms of
__remove_cv_t and thus performance of the original implementation may be
sensitive to cv-qualification).  So we should probably uniformly
benchmark these classes of types, via doing e.g.:

  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);
  static_assert(!std::is_pointer_v>);

(We could consider other kinds of types too, e.g. reference types and
integral types, but it seems clear based on the implementations being
benchmarked that performance won't be sensitive to reference-ness
or integral-ness.)

> 
> Sincerely,
> Ken Matsui
> 
> On Thu, Jun 15, 2023 at 5:22 AM Ken Matsui  wrote:
> >
> > This patch implements built-in trait for std::remove_pointer.
> >
> > gcc/cp/ChangeLog:
> >
> > * cp-trait.def: Define __remove_pointer.
> > * semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
> > * g++.dg/ext/remove_pointer.C: New test.
> >
> > Signed-off-by: Ken Matsui 
> > ---
> >  gcc/cp/cp-trait.def   |  1 +
> >  gcc/cp/semantics.cc   |  4 ++
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
> >  gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++
> >  4 files changed, 59 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C
> >
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 8b7fece0cc8..07823e55579 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -90,6 +90,7 @@ DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> >  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> >  DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> >  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> > +DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
> >  DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> >  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> >
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 8fb47fd179e..885c7a6fb64 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12373,6 +12373,10 @@ finish_trait_type (cp_trait_kind kind, tree type1, 
> > tree type2,
> >if (TYPE_REF_P (type1))
> > type1 = TREE_TYPE (type1);
> >return cv_unqualified (type1);
> > +case CPTK_REMOVE_POINTER:
> > +  if (TYPE_PTR_P (type1))
> > +type1 = TREE_TYPE (type1);
> > +  return type1;

Maybe add a newline before the 'case' to visually separate it from the
previous 'case'?  LGTM otherwise, thanks!

> >
> >  case CPTK_TYPE_PACK_ELEMENT:
> >return finish_type_pack_element (type1, type2, complain);
> > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C 
> > b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > index f343e153e56..e21e0a95509 100644
> > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > @@ -146,3 +146,6 @@
> >  #if !__has_builtin (__remove_cvref)
> >  # error "__has_builtin (__remove_cvref) failed"
> >  #endif
> > +#if !__has_builtin (__remove_pointer)
> > +# error "__has_builtin (__remove_pointer) failed"
> > +#endif
> > diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C 
> > b/gcc/testsuite/g++.dg/ext/remove_pointer.C
> > new file mode 100644
> > index 000..7b13db93950
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
> > @@ -0,0 +1,51 @@
> > +// { dg-do compile { target c++11 } }
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > 

  1   2   3   4   5   6   7   8   9   10   >