[gcc r15-1227] c++: visibility wrt concept-id as targ [PR115283]

2024-06-12 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:b1fe718cbe0c8883af89f52e0aad3ebf913683de

commit r15-1227-gb1fe718cbe0c8883af89f52e0aad3ebf913683de
Author: Patrick Palka 
Date:   Wed Jun 12 20:05:05 2024 -0400

c++: visibility wrt concept-id as targ [PR115283]

Like with alias templates, it seems we don't maintain visibility flags
for concepts either, so min_vis_expr_r should ignore them for now.
Otherwise after r14-6789 we may incorrectly give a function template that
uses a concept-id in its signature internal linkage.

PR c++/115283

gcc/cp/ChangeLog:

* decl2.cc (min_vis_expr_r) : Ignore
concepts.

gcc/testsuite/ChangeLog:

* g++.dg/template/linkage5.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/decl2.cc  |  5 +++--
 gcc/testsuite/g++.dg/template/linkage5.C | 14 ++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 7baff46a1921..6c3ef60d51f8 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2723,9 +2723,10 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void 
*data)
   break;
 
 case TEMPLATE_DECL:
-  if (DECL_ALIAS_TEMPLATE_P (t))
+  if (DECL_ALIAS_TEMPLATE_P (t) || standard_concept_p (t))
/* FIXME: We don't maintain TREE_PUBLIC / DECL_VISIBILITY for
-  alias templates so we can't trust it here (PR107906).  */
+  alias templates so we can't trust it here (PR107906).  Ditto
+  for concepts.  */
break;
   t = DECL_TEMPLATE_RESULT (t);
   /* Fall through.  */
diff --git a/gcc/testsuite/g++.dg/template/linkage5.C 
b/gcc/testsuite/g++.dg/template/linkage5.C
new file mode 100644
index ..7e8f93f546f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/linkage5.C
@@ -0,0 +1,14 @@
+// PR c++/115283
+// { dg-final { scan-assembler "(weak|glob)\[^\n\]*_Z1fIiEv1AIX1CIT_EEE" } }
+// { dg-do compile { target c++20 } }
+
+template
+concept C = true;
+
+template
+struct A { };
+
+template
+void f(A>) { }
+
+template void f(A);


[gcc r14-10301] c++: lambda in pack expansion [PR115378]

2024-06-10 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:ff8105b4910f7dbee326cb36b01c16ac9bf10c4b

commit r14-10301-gff8105b4910f7dbee326cb36b01c16ac9bf10c4b
Author: Patrick Palka 
Date:   Fri Jun 7 12:12:30 2024 -0400

c++: lambda in pack expansion [PR115378]

Here find_parameter_packs_r is incorrectly treating the 'auto' return
type of a lambda as a parameter pack due to Concepts-TS specific logic
added in r6-4517, leading to confusion later when expanding the pattern.

Since we intend on removing Concepts TS support soon anyway, this patch
fixes this by restricting the problematic logic with flag_concepts_ts.
Doing so revealed that add_capture was relying on this logic to set
TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion
init-capture, which we now need to do explicitly.

PR c++/115378

gcc/cp/ChangeLog:

* lambda.cc (lambda_capture_field_type): Set
TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture
pack expansion.
* pt.cc (find_parameter_packs_r) :
Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with
flag_concepts_ts.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic.
* g++.dg/template/pr95672.C: Likewise.
* g++.dg/cpp2a/lambda-targ5.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 5c761395402a730535983a5e49ef1775561ebc61)

Diff:
---
 gcc/cp/lambda.cc  |  3 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++
 gcc/testsuite/g++.dg/template/pr95672.C   |  2 +-
 5 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 4b1f9391fee..5b5e31c141e 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
   outermost CV qualifiers of EXPR.  */
type = build_reference_type (type);
   if (uses_parameter_packs (expr))
-   /* Stick with 'auto' even if the type could be deduced.  */;
+   /* Stick with 'auto' even if the type could be deduced.  */
+   TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
   else
type = do_auto_deduction (type, expr, auto_node);
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d3f61e90422..c7aee66f068 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3942,7 +3942,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 is a pack expansion, the invented template parameter is a template
 parameter pack.  */
-  if (ppd->type_pack_expansion_p && is_auto (t)
+  if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t)
  && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
   if (TEMPLATE_TYPE_PARAMETER_PACK (t))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
index cedd661710c..4162361d14f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
@@ -1,7 +1,7 @@
 // PR c++/103497
 // { dg-do compile { target c++14 } }
 
-void foo(decltype(auto)... args);  // { dg-error "cannot declare a parameter 
with .decltype.auto.." }
+void foo(decltype(auto)... args);  // { dg-error "contains no parameter packs" 
}
 
 int main() {
   foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
new file mode 100644
index 000..efd4bb45d58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
@@ -0,0 +1,15 @@
+// PR c++/115378
+// { dg-do compile { target c++20 } }
+
+struct tt {};
+
+template
+constexpr auto __counter = 1;
+
+template 
+using _as_base = tt;
+
+template 
+struct env : _as_base>... {};
+
+env t;
diff --git a/gcc/testsuite/g++.dg/template/pr95672.C 
b/gcc/testsuite/g++.dg/template/pr95672.C
index c752b4a2c08..d97b8db2e97 100644
--- a/gcc/testsuite/g++.dg/template/pr95672.C
+++ b/gcc/testsuite/g++.dg/template/pr95672.C
@@ -1,3 +1,3 @@
 // PR c++/95672
 // { dg-do compile { target c++14 } }
-struct g_class : decltype  (auto) ... {  }; // { dg-error "invalid use of pack 
expansion" }
+struct g_class : decltype  (auto) ... {  }; // { dg-error "contains no 
parameter packs" }


[gcc r15-1103] c++: lambda in pack expansion [PR115378]

2024-06-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:5c761395402a730535983a5e49ef1775561ebc61

commit r15-1103-g5c761395402a730535983a5e49ef1775561ebc61
Author: Patrick Palka 
Date:   Fri Jun 7 12:12:30 2024 -0400

c++: lambda in pack expansion [PR115378]

Here find_parameter_packs_r is incorrectly treating the 'auto' return
type of a lambda as a parameter pack due to Concepts-TS specific logic
added in r6-4517, leading to confusion later when expanding the pattern.

Since we intend on removing Concepts TS support soon anyway, this patch
fixes this by restricting the problematic logic with flag_concepts_ts.
Doing so revealed that add_capture was relying on this logic to set
TEMPLATE_TYPE_PARAMETER_PACK for the 'auto' type of an pack expansion
init-capture, which we now need to do explicitly.

PR c++/115378

gcc/cp/ChangeLog:

* lambda.cc (lambda_capture_field_type): Set
TEMPLATE_TYPE_PARAMETER_PACK on the auto type of an init-capture
pack expansion.
* pt.cc (find_parameter_packs_r) :
Restrict TEMPLATE_TYPE_PARAMETER_PACK promotion with
flag_concepts_ts.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/decltype-auto-103497.C: Adjust expected diagnostic.
* g++.dg/template/pr95672.C: Likewise.
* g++.dg/cpp2a/lambda-targ5.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/lambda.cc  |  3 ++-
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C | 15 +++
 gcc/testsuite/g++.dg/template/pr95672.C   |  2 +-
 5 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 630cc4eade1..0770417810e 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -223,7 +223,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
   outermost CV qualifiers of EXPR.  */
type = build_reference_type (type);
   if (uses_parameter_packs (expr))
-   /* Stick with 'auto' even if the type could be deduced.  */;
+   /* Stick with 'auto' even if the type could be deduced.  */
+   TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
   else
type = do_auto_deduction (type, expr, auto_node);
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index abbba7c6746..607753ae6b7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3940,7 +3940,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 is a pack expansion, the invented template parameter is a template
 parameter pack.  */
-  if (ppd->type_pack_expansion_p && is_auto (t)
+  if (flag_concepts_ts && ppd->type_pack_expansion_p && is_auto (t)
  && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
   if (TEMPLATE_TYPE_PARAMETER_PACK (t))
diff --git a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C 
b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
index cedd661710c..4162361d14f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
+++ b/gcc/testsuite/g++.dg/cpp1y/decltype-auto-103497.C
@@ -1,7 +1,7 @@
 // PR c++/103497
 // { dg-do compile { target c++14 } }
 
-void foo(decltype(auto)... args);  // { dg-error "cannot declare a parameter 
with .decltype.auto.." }
+void foo(decltype(auto)... args);  // { dg-error "contains no parameter packs" 
}
 
 int main() {
   foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
new file mode 100644
index 000..efd4bb45d58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ5.C
@@ -0,0 +1,15 @@
+// PR c++/115378
+// { dg-do compile { target c++20 } }
+
+struct tt {};
+
+template
+constexpr auto __counter = 1;
+
+template 
+using _as_base = tt;
+
+template 
+struct env : _as_base>... {};
+
+env t;
diff --git a/gcc/testsuite/g++.dg/template/pr95672.C 
b/gcc/testsuite/g++.dg/template/pr95672.C
index c752b4a2c08..d97b8db2e97 100644
--- a/gcc/testsuite/g++.dg/template/pr95672.C
+++ b/gcc/testsuite/g++.dg/template/pr95672.C
@@ -1,3 +1,3 @@
 // PR c++/95672
 // { dg-do compile { target c++14 } }
-struct g_class : decltype  (auto) ... {  }; // { dg-error "invalid use of pack 
expansion" }
+struct g_class : decltype  (auto) ... {  }; // { dg-error "contains no 
parameter packs" }


[gcc r15-892] c++: canonicity of fn types w/ instantiated eh specs [PR115223]

2024-05-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:58b8c87b7fb281e35a6817cc91a292096fdc02dc

commit r15-892-g58b8c87b7fb281e35a6817cc91a292096fdc02dc
Author: Patrick Palka 
Date:   Wed May 29 04:49:37 2024 -0400

c++: canonicity of fn types w/ instantiated eh specs [PR115223]

When propagating structural equality in build_cp_fntype_variant, we
should consider structural equality of the exception-less variant, not
of the given type which might use structural equality only because it
has a (complex) noexcept-spec that we're intending to replace, as in
maybe_instantiate_noexcept which calls build_exception_variant using
the deferred-noexcept function type.  Otherwise we might pessimistically
use structural equality for a function type with a simple instantiated
noexcept-spec, leading to a LTO-triggered type verification failure if we
later use that (structural-equality) type as the canonical version of
some other variant.

PR c++/115223

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Propagate structural
equality of the exception-less variant.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/noexcept87.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  |  4 
 gcc/testsuite/g++.dg/cpp0x/noexcept87.C | 11 +++
 2 files changed, 15 insertions(+)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index fe3f034d000..72dd46e1bd1 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2796,6 +2796,10 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
   bool complex_eh_spec_p = (cr && cr != noexcept_true_spec
&& !UNPARSED_NOEXCEPT_SPEC_P (cr));
 
+  if (!complex_eh_spec_p && TYPE_RAISES_EXCEPTIONS (type))
+/* We want to consider structural equality of the exception-less
+   variant since we'll be replacing the exception specification.  */
+type = build_cp_fntype_variant (type, rqual, /*raises=*/NULL_TREE, late);
   if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p)
 /* Propagate structural equality.  And always use structural equality
for function types with a complex noexcept-spec since their identity
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept87.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
new file mode 100644
index 000..339569d15ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept87.C
@@ -0,0 +1,11 @@
+// PR c++/115223
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -flto }
+
+template
+void f() noexcept(bool(T() || true));
+
+void g() { f(); }
+
+using type = void;
+type callDestructorIfNecessary() noexcept {}


[gcc r15-779] c++: canonicity of fn types w/ complex eh specs [PR115159]

2024-05-22 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3c98d06a9016a0fa3a806879bd168f13b8a606f8

commit r15-779-g3c98d06a9016a0fa3a806879bd168f13b8a606f8
Author: Patrick Palka 
Date:   Wed May 22 17:45:04 2024 -0400

c++: canonicity of fn types w/ complex eh specs [PR115159]

Here the member functions QList::g and QList::h are given the same
function type by build_cp_fntype_variant since their noexcept-specs are
equivalent according to cp_tree_equal.  In doing so however this means
that the function type of QList::h refers to a function parameter from
QList::g, which ends up confusing modules streaming.

I'm not sure if modules can be fixed to handle this situation, but
regardless it seems weird in principle that a function parameter can
escape in such a way.  The analogous situation with a trailing return
type and decltype

  auto g(QList ) -> decltype(f(other));
  auto h(QList ) -> decltype(f(other));

behaves better because we don't canonicalize decltype, and so the
function types of g and h are non-canonical and therefore not shared.

In light of this, it seems natural to treat function types with complex
noexcept-specs as non-canonical as well so that each such function
declaration is given a unique function type node.  (The main benefit of
type canonicalization is to speed up repeated type comparisons, but it
should be rare to repeatedly compare two otherwise compatible function
types with complex noexcept-specs.)

To that end, this patch strengthens the ce_exact case of comp_except_specs
to require identity instead of equivalence of the noexcept-spec so that
build_cp_fntype_variant doesn't reuse a variant when it shouldn't.  In
turn we need to use structural equality for types with a complex eh spec.
This lets us get rid of the tricky handling of canonical types when updating
unparsed noexcept-spec variants.

PR c++/115159

gcc/cp/ChangeLog:

* tree.cc (build_cp_fntype_variant): Always use structural
equality for types with a complex exception specification.
(fixup_deferred_exception_variants): Use structural equality
for adjusted variants.
* typeck.cc (comp_except_specs): Require == instead of
cp_tree_equal for ce_exact noexcept-spec comparison.

gcc/testsuite/ChangeLog:

* g++.dg/modules/noexcept-2_a.H: New test.
* g++.dg/modules/noexcept-2_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  | 48 ++---
 gcc/cp/typeck.cc|  4 ++-
 gcc/testsuite/g++.dg/modules/noexcept-2_a.H | 24 +++
 gcc/testsuite/g++.dg/modules/noexcept-2_b.C |  4 +++
 4 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 9d37d255d8d..4d87661b4ad 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2793,9 +2793,13 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 
   /* Canonicalize the exception specification.  */
   tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
+  bool complex_eh_spec_p = (cr && cr != noexcept_true_spec
+   && !UNPARSED_NOEXCEPT_SPEC_P (cr));
 
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
-/* Propagate structural equality. */
+  if (TYPE_STRUCTURAL_EQUALITY_P (type) || complex_eh_spec_p)
+/* Propagate structural equality.  And always use structural equality
+   for function types with a complex noexcept-spec since their identity
+   may depend on e.g. whether comparing_specializations is set.  */
 SET_TYPE_STRUCTURAL_EQUALITY (v);
   else if (TYPE_CANONICAL (type) != type || cr != raises || late)
 /* Build the underlying canonical type, since it is different
@@ -2812,55 +2816,23 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier 
rqual,
 /* TYPE is a function or method type with a deferred exception
specification that has been parsed to RAISES.  Fixup all the type
variants that are affected in place.  Via decltype &| noexcept
-   tricks, the unparsed spec could have escaped into the type system.
-   The general case is hard to fixup canonical types for.  */
+   tricks, the unparsed spec could have escaped into the type system.  */
 
 void
 fixup_deferred_exception_variants (tree type, tree raises)
 {
   tree original = TYPE_RAISES_EXCEPTIONS (type);
-  tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
 
   gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original));
 
-  /* Though sucky, this walk will process the canonical variants
- first.  */
-  tree prev = NULL_TREE;
   for (tree variant = TYPE_MAIN_VARIANT (type);
-   variant; prev = variant, variant = TYPE_NEXT_VARIANT (variant))
+   variant; variant = TYPE_NEXT_VARIANT (variant))
 if (TYPE_RAISES_EXCEPTIONS (variant) == original)
   

[gcc r14-10226] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-21 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:caf43cc9e5c0b3265b55e5a0dc77fc55e9618c77

commit r14-10226-gcaf43cc9e5c0b3265b55e5a0dc77fc55e9618c77
Author: Patrick Palka 
Date:   Tue May 21 15:54:10 2024 -0400

c++: folding non-dep enumerator from current inst [PR115139]

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' below ultimately because we no
longer exit early when substituting the CONST_DECLs for e1 and e2 with
args=NULL_TREE and instead proceed to substitute the class context A
(also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion
(due to processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of
tsubst_expr to use tsubst to substitute the context, which short circuits
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that would've happened in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
small optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.

Reviewed-by: Marek Polacek 
Reviewed-by: Jason Merrill 
(cherry picked from commit f0c0bced62b9c728ed1e672747aa234d918da22c)

Diff:
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 13 +
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e9882f2a3e0..ba47620ec59 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21524,7 +21524,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..ea5b41fba93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,13 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
+
+template class A;


[gcc r15-759] c++: folding non-dep enumerator from current inst [PR115139]

2024-05-21 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:f0c0bced62b9c728ed1e672747aa234d918da22c

commit r15-759-gf0c0bced62b9c728ed1e672747aa234d918da22c
Author: Patrick Palka 
Date:   Tue May 21 15:54:10 2024 -0400

c++: folding non-dep enumerator from current inst [PR115139]

After the tsubst_copy removal r14-4796-g3e3d73ed5e85e7 GCC 14 ICEs during
fold_non_dependent_expr for 'e1 | e2' below ultimately because we no
longer exit early when substituting the CONST_DECLs for e1 and e2 with
args=NULL_TREE and instead proceed to substitute the class context A
(also with args=NULL_TREE) which ends up ICEing from tsubst_pack_expansion
(due to processing_template_decl being cleared).

Incidentally, the ICE went away on trunk ever since the tsubst_aggr_type
removal r15-123-gf04dc89a991ddc since it changed the CONST_DECL case of
tsubst_expr to use tsubst to substitute the context, which short circuits
for empty args and so avoids the ICE.

This patch fixes this ICE for GCC 14 by narrowly restoring the early exit
for empty args that would've happened in tsubst_copy when substituting an
enumerator CONST_DECL.  We might as well apply this to trunk too, as a
small optimization.

PR c++/115139

gcc/cp/ChangeLog:

* pt.cc (tsubst_expr) : Exit early if args
is empty.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent33.C: New test.

Reviewed-by: Marek Polacek 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc|  2 +-
 gcc/testsuite/g++.dg/template/non-dependent33.C | 13 +
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e77c48e463e..a95ce6eb3da 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21519,7 +21519,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
if (DECL_TEMPLATE_PARM_P (t))
  RETURN (RECUR (DECL_INITIAL (t)));
-   if (!uses_template_parms (DECL_CONTEXT (t)))
+   if (!args || !uses_template_parms (DECL_CONTEXT (t)))
  RETURN (t);
 
/* Unfortunately, we cannot just call lookup_name here.
diff --git a/gcc/testsuite/g++.dg/template/non-dependent33.C 
b/gcc/testsuite/g++.dg/template/non-dependent33.C
new file mode 100644
index 000..ea5b41fba93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent33.C
@@ -0,0 +1,13 @@
+// PR c++/115139
+// { dg-do compile { target c++11 } }
+
+template
+class A {
+  enum E {
+e1 = 1,
+e2 = 2,
+e3 = e1 | e2,
+  };
+};
+
+template class A;


[gcc r14-10221] c++: aggregate CTAD w/ paren init and bases [PR115114]

2024-05-20 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:a9837934203d41c96b5cf05e34f68c0d3311c973

commit r14-10221-ga9837934203d41c96b5cf05e34f68c0d3311c973
Author: Patrick Palka 
Date:   Fri May 17 09:02:52 2024 -0400

c++: aggregate CTAD w/ paren init and bases [PR115114]

During aggregate CTAD with paren init, we're accidentally overlooking
base classes since TYPE_FIELDS of a template type doesn't contain
corresponding base fields.  So we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider bases in the paren init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2)

Diff:
---
 gcc/cp/pt.cc   |  7 +++
 .../g++.dg/cpp2a/class-deduction-aggr15.C  | 23 ++
 2 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b5c494e8d15e..e9882f2a3e0a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30205,6 +30205,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index ..16dc0f52b64c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;


[gcc r14-10220] c++: lvalueness of non-dependent assignment expr [PR114994]

2024-05-20 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:b3399b445ba7495b0479d43f2389e64d48de870e

commit r14-10220-gb3399b445ba7495b0479d43f2389e64d48de870e
Author: Patrick Palka 
Date:   Tue May 14 22:55:16 2024 -0400

c++: lvalueness of non-dependent assignment expr [PR114994]

r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment
expressions ahead of time and give them a type, as was already done for
compound assignments.  Unlike for compound assignments however, if a
simple assignment resolves to an operator overload we represent it as a
(typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload.
(I reckoned this was at worst a pessimization -- we'll just have to repeat
overload resolution at instantiatiation time.)

But this turns out to break the below testcase ultimately because
MODOP_EXPR (of non-reference type) is always treated as an lvalue
according to lvalue_kind, which is incorrect for the MODOP_EXPR
representing x=42.

We can fix this by representing such class assignment expressions as
CALL_EXPRs as well, but this turns out to require some tweaking of our
-Wparentheses warning logic and may introduce other fallout making it
unsuitable for backporting.

So this patch instead fixes lvalue_kind to consider the type of a
MODOP_EXPR representing a class assignment.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : For a class
assignment, consider the result type.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit c6cc6d4741a880109c4e0e64d5a189687fb526f6)

Diff:
---
 gcc/cp/tree.cc  |  5 -
 gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe8179..9d37d255d8d5 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index ..54252c7dfaf9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}


[gcc r15-630] c++: aggregate CTAD w/ paren init and bases [PR115114]

2024-05-17 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2

commit r15-630-g5aaf47cb1987bbc5508c4b9b7dad5ea7d69af2c2
Author: Patrick Palka 
Date:   Fri May 17 09:02:52 2024 -0400

c++: aggregate CTAD w/ paren init and bases [PR115114]

During aggregate CTAD with paren init, we're accidentally overlooking
base classes since TYPE_FIELDS of a template type doesn't contain
corresponding base fields.  So we need to consider them separately.

PR c++/115114

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Consider bases in the paren init case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr15.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   |  7 +++
 .../g++.dg/cpp2a/class-deduction-aggr15.C  | 23 ++
 2 files changed, 30 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e946d..e77c48e463e2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30200,6 +30200,13 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
+  for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
+   {
+ if (!len)
+   break;
+ parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
+ --len;
+   }
   for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
new file mode 100644
index ..16dc0f52b64c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr15.C
@@ -0,0 +1,23 @@
+// PR c++/115114
+// { dg-do compile { target c++20 } }
+
+struct X {} x;
+struct Y {} y;
+
+template
+struct A : T {
+  U m;
+};
+
+using ty1 = decltype(A{x, 42}); // OK
+using ty1 = decltype(A(x, 42)); // OK, used to fail
+using ty1 = A;
+
+template
+struct B : T, V {
+  U m = 42;
+};
+
+using ty2 = decltype(B{x, y}); // OK
+using ty2 = decltype(B(x, y)); // OK, used to fail
+using ty2 = B;


[gcc r15-498] c++: lvalueness of non-dependent assignment expr [PR114994]

2024-05-14 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c6cc6d4741a880109c4e0e64d5a189687fb526f6

commit r15-498-gc6cc6d4741a880109c4e0e64d5a189687fb526f6
Author: Patrick Palka 
Date:   Tue May 14 22:55:16 2024 -0400

c++: lvalueness of non-dependent assignment expr [PR114994]

r14-4111-g6e92a6a2a72d3b made us check non-dependent simple assignment
expressions ahead of time and give them a type, as was already done for
compound assignments.  Unlike for compound assignments however, if a
simple assignment resolves to an operator overload we represent it as a
(typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload.
(I reckoned this was at worst a pessimization -- we'll just have to repeat
overload resolution at instantiatiation time.)

But this turns out to break the below testcase ultimately because
MODOP_EXPR (of non-reference type) is always treated as an lvalue
according to lvalue_kind, which is incorrect for the MODOP_EXPR
representing x=42.

We can fix this by representing such class assignment expressions as
CALL_EXPRs as well, but this turns out to require some tweaking of our
-Wparentheses warning logic and may introduce other fallout making it
unsuitable for backporting.

So this patch instead fixes lvalue_kind to consider the type of a
MODOP_EXPR representing a class assignment.

PR c++/114994

gcc/cp/ChangeLog:

* tree.cc (lvalue_kind) : For a class
assignment, consider the result type.

gcc/testsuite/ChangeLog:

* g++.dg/template/non-dependent32.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc  |  5 -
 gcc/testsuite/g++.dg/template/non-dependent32.C | 18 ++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index f1a23ffe8179..9d37d255d8d5 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -275,7 +275,10 @@ lvalue_kind (const_tree ref)
   /* We expect to see unlowered MODOP_EXPRs only during
 template processing.  */
   gcc_assert (processing_template_decl);
-  return clk_ordinary;
+  if (CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0
+   goto default_;
+  else
+   return clk_ordinary;
 
 case MODIFY_EXPR:
 case TYPEID_EXPR:
diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C 
b/gcc/testsuite/g++.dg/template/non-dependent32.C
new file mode 100644
index ..54252c7dfaf9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent32.C
@@ -0,0 +1,18 @@
+// PR c++/114994
+// { dg-do compile { target c++11 } }
+
+struct udl_arg {
+  udl_arg operator=(int);
+};
+
+void f(udl_arg&&);
+
+template
+void g() {
+  udl_arg x;
+  f(x=42); // { dg-bogus "cannot bind" }
+}
+
+int main() {
+  g();
+}


[gcc r13-8767] c++: build_extra_args recapturing local specs [PR114303]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:47cac09307874ff1d640392e3d986453f34f7bcb

commit r13-8767-g47cac09307874ff1d640392e3d986453f34f7bcb
Author: Patrick Palka 
Date:   Thu Apr 11 10:16:41 2024 -0400

c++: build_extra_args recapturing local specs [PR114303]

r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
first so that we prefer processing a local specialization in an evaluated
context even if its first use is in an unevaluated context.  But this
means we need to avoid walking a tree that already has extra args/specs
saved because the list of saved specs appears to be an evaluated
context which we'll now walk first.  It seems then that we should be
calculating the saved specs from scratch each time, rather than
potentially walking the saved specs list from an earlier partial
instantiation when calling build_extra_args a second time around.

PR c++/114303

gcc/cp/ChangeLog:

* constraint.cc (tsubst_requires_expr): Clear
REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
* pt.cc (tree_extra_args): Define.
(extract_locals_r): Assert *_EXTRA_ARGS is empty.
(tsubst_stmt) : Clear IF_SCOPE on the new
IF_STMT.  Call build_extra_args on the new IF_STMT instead
of t which might already have IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-if-lambda6.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit b262b17636e47ae969a74f16e86ccb00678d5e88)

Diff:
---
 gcc/cp/constraint.cc  |  1 +
 gcc/cp/pt.cc  | 31 ++-
 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C | 16 
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 83df57dc6fd7..67fe2ae17cd8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2370,6 +2370,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
 matching or dguide constraint rewriting), in which case we need
 to partially substitute.  */
   t = copy_node (t);
+  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
   return t;
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index fa660fcf49ee..3af705c647a0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3861,6 +3861,24 @@ has_extra_args_mechanism_p (const_tree t)
  && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS  */
 }
 
+/* Return *_EXTRA_ARGS of the given supported tree T.  */
+
+static tree&
+tree_extra_args (tree t)
+{
+  gcc_checking_assert (has_extra_args_mechanism_p (t));
+
+  if (PACK_EXPANSION_P (t))
+return PACK_EXPANSION_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == REQUIRES_EXPR)
+return REQUIRES_EXPR_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == IF_STMT
+  && IF_STMT_CONSTEXPR_P (t))
+return IF_STMT_EXTRA_ARGS (t);
+
+  gcc_unreachable ();
+}
+
 /* Structure used to track the progress of find_parameter_packs_r.  */
 struct find_parameter_pack_data
 {
@@ -13185,6 +13203,16 @@ extract_locals_r (tree *tp, int *walk_subtrees, void 
*data_)
 /* Remember local typedefs (85214).  */
 tp = _NAME (*tp);
 
+  if (has_extra_args_mechanism_p (*tp))
+/* Assert *_EXTRA_ARGS is empty, because we don't want to walk it and
+   potentially see a previously captured local in an evaluated context
+   that's really only used in an unevaluated context (PR114303).  This
+   means callers of build_extra_args need to clear *_EXTRA_ARGS of the
+   outermost tree.  Nested *_EXTRA_ARGS should naturally be empty since
+   the outermost (extra-args) tree will intercept any substitution before
+   a nested tree can.  */
+gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE);
+
   if (TREE_CODE (*tp) == DECL_EXPR)
 {
   tree decl = DECL_EXPR_DECL (*tp);
@@ -19189,10 +19217,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 of the constexpr if is still dependent.  Don't substitute into the
 branches now, just remember the template arguments.  */
  do_poplevel (IF_SCOPE (stmt));
+ IF_SCOPE (stmt) = NULL_TREE;
  IF_COND (stmt) = IF_COND (t);
  THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
  ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+ IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
  add_stmt (stmt);
  break;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index ..038c2a41210f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0,0 +1,16 @@
+// PR 

[gcc r15-438] c++: replace tf_norm with a local flag

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:67476ba8adb432033993f429b1aa4ee5689fa046

commit r15-438-g67476ba8adb432033993f429b1aa4ee5689fa046
Author: Patrick Palka 
Date:   Mon May 13 15:46:55 2024 -0400

c++: replace tf_norm with a local flag

The tf_norm flag controlling whether to build diagnostic information
during constraint normalization doesn't need to be a global tsubst flag,
and is confusingly named.  This patch replaces it with a boolean flag
local to normalization.

gcc/cp/ChangeLog:

* constraint.cc (norm_info::norm_info): Take a bool instead of
tsubst_flags_t.
(norm_info::generate_diagnostics): Turn this predicate function
into a bool data member.
(normalize_logical_operation): Adjust after norm_info changes.
(normalize_concept_check): Likewise.
(normalize_atom): Likewise.
(get_normalized_constraints_from_info): Likewise.
(normalize_concept_definition): Likewise.
(normalize_constraint_expression): Likewise.
(normalize_placeholder_type_constraints): Likewise.
(satisfy_nondeclaration_constraints): Likewise.
* cp-tree.h (enum tsubst_flags): Remove tf_norm.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constraint.cc | 40 
 gcc/cp/cp-tree.h |  3 +--
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8679d3ce658d..ebf4255e546e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -622,33 +622,29 @@ parameter_mapping_equivalent_p (tree t1, tree t2)
 
 struct norm_info : subst_info
 {
-  explicit norm_info (tsubst_flags_t cmp)
-: norm_info (NULL_TREE, cmp)
+  explicit norm_info (bool diag)
+: norm_info (NULL_TREE, diag)
   {}
 
   /* Construct a top-level context for DECL.  */
 
-  norm_info (tree in_decl, tsubst_flags_t complain)
-: subst_info (tf_warning_or_error | complain, in_decl)
+  norm_info (tree in_decl, bool diag)
+: subst_info (tf_warning_or_error, in_decl),
+  generate_diagnostics (diag)
   {
 if (in_decl)
   {
initial_parms = DECL_TEMPLATE_PARMS (in_decl);
-   if (generate_diagnostics ())
+   if (generate_diagnostics)
  context = build_tree_list (NULL_TREE, in_decl);
   }
 else
   initial_parms = current_template_parms;
   }
 
-  bool generate_diagnostics() const
-  {
-return complain & tf_norm;
-  }
-
   void update_context(tree expr, tree args)
   {
-if (generate_diagnostics ())
+if (generate_diagnostics)
   {
tree map = build_parameter_mapping (expr, args, ctx_parms ());
context = tree_cons (map, expr, context);
@@ -679,6 +675,10 @@ struct norm_info : subst_info
  template parameters of ORIG_DECL.  */
 
   tree initial_parms = NULL_TREE;
+
+  /* Whether to build diagnostic information during normalization.  */
+
+  bool generate_diagnostics;
 };
 
 static tree normalize_expression (tree, tree, norm_info);
@@ -693,7 +693,7 @@ normalize_logical_operation (tree t, tree args, tree_code 
c, norm_info info)
   tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
 
   /* Build a new info object for the constraint.  */
-  tree ci = info.generate_diagnostics()
+  tree ci = info.generate_diagnostics
 ? build_tree_list (t, info.context)
 : NULL_TREE;
 
@@ -777,7 +777,7 @@ normalize_concept_check (tree check, tree args, norm_info 
info)
   if (!norm_cache)
 norm_cache = hash_table::create_ggc (31);
   norm_entry *entry = nullptr;
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the normal form of the substituted concept-id (when not
 diagnosing).  */
@@ -831,7 +831,7 @@ normalize_atom (tree t, tree args, norm_info info)
   if (info.in_decl && concept_definition_p (info.in_decl))
 ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (atom) = true;
 
-  if (!info.generate_diagnostics ())
+  if (!info.generate_diagnostics)
 {
   /* Cache the ATOMIC_CONSTRs that we return, so that sat_hasher::equal
 later can cheaply compare two atoms using just pointer equality.  */
@@ -910,7 +910,7 @@ get_normalized_constraints_from_info (tree ci, tree 
in_decl, bool diag = false)
 
   /* Substitution errors during normalization are fatal.  */
   ++processing_template_decl;
-  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  norm_info info (in_decl, diag);
   tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci), info);
   --processing_template_decl;
 
@@ -1012,7 +1012,7 @@ normalize_concept_definition (tree tmpl, bool diag)
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
   ++processing_template_decl;
-  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  norm_info info (tmpl, diag);
   tree norm = get_normalized_constraints (def, info);
   

[gcc r13-8765] c++: constexpr union member access folding [PR114709]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:d3659e2dfcc6db83391cd2c6d70097cba35eb4b9

commit r13-8765-gd3659e2dfcc6db83391cd2c6d70097cba35eb4b9
Author: Patrick Palka 
Date:   Wed Apr 24 17:49:56 2024 -0400

c++: constexpr union member access folding [PR114709]

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 0844170e9ef60a8b2f6fba6786672f30ce1c2749)

Diff:
---
 gcc/cp/constexpr.cc   | 3 +++
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 11 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index acb5496085bb..12dd9010148e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5547,6 +5547,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  /* We need to preserve union member accesses so that we can
+ later properly diagnose accessing the wrong member.  */
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index ..34c264944b68
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }


[gcc r14-10201] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:57cd8665fea4c339369a43be017583621aa82fed

commit r14-10201-g57cd8665fea4c339369a43be017583621aa82fed
Author: Patrick Palka 
Date:   Mon May 13 09:53:40 2024 -0400

c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since partial instantiations don't
have (partially instantiated) TYPE_FIELDS.  In turn we need to partially
substitute PARMs in the paren init case as well.  As a drive-by improvement
it seems better to use outer_template_args instead of DECL_TI_ARGS during
this partial substitution so that we lower instead of substitute the
innermost template parameters, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
substitute the outermost arguments into its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute outer template arguments into
a guide's constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 6d31a370e26eeb950c326332633b3e8e84b6630b)

Diff:
---
 gcc/cp/pt.cc   | 39 --
 .../g++.dg/cpp2a/class-deduction-aggr14.C  | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C | 22 
 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 +
 4 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3f65..b5c494e8d15e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30201,26 +30201,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30235,6 +30220,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30426,7 +30427,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+  

[gcc r15-434] c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

2024-05-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:6d31a370e26eeb950c326332633b3e8e84b6630b

commit r15-434-g6d31a370e26eeb950c326332633b3e8e84b6630b
Author: Patrick Palka 
Date:   Mon May 13 09:53:40 2024 -0400

c++: nested aggregate/alias CTAD fixes [PR114974, PR114901, PR114903]

During maybe_aggr_guide with a nested class template and paren init,
like with list init we need to consider the generic template type rather
than the partially instantiated type since partial instantiations don't
have (partially instantiated) TYPE_FIELDS.  In turn we need to partially
substitute PARMs in the paren init case as well.  As a drive-by improvement
it seems better to use outer_template_args instead of DECL_TI_ARGS during
this partial substitution so that we lower instead of substitute the
innermost template parameters, which is generally more robust.

And during alias_ctad_tweaks with a nested class template, even though
the guides may be already partially instantiated we still need to
substitute the outermost arguments into its constraints.

PR c++/114974
PR c++/114901
PR c++/114903

gcc/cp/ChangeLog:

* pt.cc (maybe_aggr_guide): Fix obtaining TYPE_FIELDS in
the paren init case.  Hoist out partial substitution logic
to apply to the paren init case as well.
(alias_ctad_tweaks): Substitute outer template arguments into
a guide's constraints.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-aggr14.C: New test.
* g++.dg/cpp2a/class-deduction-alias20.C: New test.
* g++.dg/cpp2a/class-deduction-alias21.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   | 39 --
 .../g++.dg/cpp2a/class-deduction-aggr14.C  | 11 ++
 .../g++.dg/cpp2a/class-deduction-alias20.C | 22 
 .../g++.dg/cpp2a/class-deduction-alias21.C | 38 +
 4 files changed, 93 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a7d9fcf930e2..4b71e199d27f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30194,26 +30194,11 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
   if (init == error_mark_node)
return NULL_TREE;
   parms = collect_ctor_idx_types (init, parms);
-  /* If we're creating a deduction guide for a member class template,
-we've used the original template pattern type for the reshape_init
-above; this is done because we want PARMS to be a template parameter
-type, something that can be deduced when used as a function template
-parameter.  At this point the outer class template has already been
-partially instantiated (we deferred the deduction until the enclosing
-scope is non-dependent).  Therefore we have to partially instantiate
-PARMS, so that its template level is properly reduced and we don't get
-mismatches when deducing types using the guide with PARMS.  */
-  if (member_template_p)
-   {
- ++processing_template_decl;
- parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
- --processing_template_decl;
-   }
 }
   else if (TREE_CODE (init) == TREE_LIST)
 {
   int len = list_length (init);
-  for (tree field = TYPE_FIELDS (type);
+  for (tree field = TYPE_FIELDS (template_type);
   len;
   --len, field = DECL_CHAIN (field))
{
@@ -30228,6 +30213,22 @@ maybe_aggr_guide (tree tmpl, tree init, 
vec *args)
 /* Aggregate initialization doesn't apply to an initializer expression.  */
 return NULL_TREE;
 
+  /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter.  At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent).  Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS.  */
+  if (member_template_p)
+{
+  ++processing_template_decl;
+  parms = tsubst (parms, outer_template_args (tmpl), complain, init);
+  --processing_template_decl;
+}
+
   if (parms)
 {
   tree last = parms;
@@ -30419,7 +30420,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
  /* Substitute the associated constraints.  */
  tree ci = get_constraints (f);
  if (ci)
-   ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+   {
+ if (tree outer_targs = outer_template_args (f))
+ 

[gcc r14-10176] c++/modules: imported spec befriending class tmpl [PR114889]

2024-05-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:390bd23fd9c98dc40856beef05364f5d1c7b9d04

commit r14-10176-g390bd23fd9c98dc40856beef05364f5d1c7b9d04
Author: Patrick Palka 
Date:   Mon Apr 29 21:27:59 2024 -0400

c++/modules: imported spec befriending class tmpl [PR114889]

When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an
imported class definition, we need to look through TEMPLATE_DECL like
make_friend_class does.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus
access check failure for _M_hash_code.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 22b20ac6c6aead2d3f36c413a77dd0b80adfec39)

Diff:
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c35e70b8cb8..3bf863e15d4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}


[gcc r15-123] c++: remove lookup_template_class's entering_scope flag

2024-05-02 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:f04dc89a991ddc6c08ac92c8ad29c6915c4ecafa

commit r15-123-gf04dc89a991ddc6c08ac92c8ad29c6915c4ecafa
Author: Patrick Palka 
Date:   Thu May 2 21:14:30 2024 -0400

c++: remove lookup_template_class's entering_scope flag

lookup_template_class's entering_scope flag controls whether to prefer
returning the primary template type A instead of the corresponding
implicit instantiation A.  When we want to set this flag as part of
substitution, we need to use tsubst_aggr_type which also takes this flag
as a parameter.  But having this separate entry point to type substitution
turned out to be subtly problematic because it doesn't reuse typedefs
like tsubst does, which r13-4729-gbe124477b38a71 fixed in a way that
respects the flag after the fact, by adjusting the entering_scope=false
result of lookup_template_class as if entering_scope=true was passed.

But if that's possible then it means lookup_template_class's
entering_scope flag is not necessary after all -- we can just do the
after-the-fact adjustment everywhere that we currently pass
entering_scope=true to it and tsubst_aggr_type.

To that end, this patch replaces this flag with an adjustment function
adjust_type_for_entering_scope, to be used whereever we currently need
the entering_scope=true behavior.  In turn we can get rid of
tsubst_aggr_type since the only reason we needed this entry point
was to be able to pass entering_scope=true to lookup_template_class.

gcc/cp/ChangeLog:

* coroutines.cc (instantiate_coro_traits): Adjust call to
lookup_template_class.
(instantiate_coro_handle_for_promise_type): Likewise.
* cp-tree.h (adjust_type_for_entering_scope): Declare.
(lookup_template_class): Adjust declaration.
* decl.cc (make_typename_type): Adjust call to
lookup_template_class. Likewise.
(get_tuple_size): Likewise.
(get_tuple_element_type): Likewise.
* pt.cc (adjust_type_for_entering_scope): Define.
(tsubst_entering_scope): Define.
(lookup_template_class): Remove entering_scope parameter.
Replace tsubst_aggr_type call with tsubst_entering_scope.
(tsubst_aggr_type): Remove.
(tsubst_aggr_type_1): Inline into tsubst.
(tsubst_function_decl): Replace tsubst_aggr_type call
with tsubst_entering_scope.
(tsubst_template_decl): Likewise.
(tsubst_decl): Likewise.
(tsubst) :
Inlined from tsubst_aggr_type_1.
: Adjust calls to
lookup_template_class.
: Replace tsubst_aggr_type call with
tsubst_entering_scope.
: Likewise.
Increment processing_template_decl when substituting the
context.
(tsubst_expr) : Replace tsubst_aggr_type
call with tsubst_entering_scope.
: Likewise.
(instantiate_template): Likewise.
(resolve_typename_type): Adjust lookup_template_class call
and call adjust_type_for_entering_scope afterward.
(listify): Adjust lookup_template_class call.
(alias_ctad_tweaks): Likewise.
* semantics.cc (finish_template_type): Adjust lookup_template_class
call and maybe call adjust_type_for_entering_scope afterward.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/coroutines.cc |   4 +-
 gcc/cp/cp-tree.h |   3 +-
 gcc/cp/decl.cc   |   4 +-
 gcc/cp/pt.cc | 207 ---
 gcc/cp/semantics.cc  |   4 +-
 5 files changed, 88 insertions(+), 134 deletions(-)

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index b05cb9eb330..97bc211ff67 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -353,7 +353,7 @@ instantiate_coro_traits (tree fndecl, location_t kw)
   tree traits_class
 = lookup_template_class (coro_traits_templ, targ,
 /*in_decl=*/NULL_TREE, /*context=*/NULL_TREE,
-/*entering scope=*/false, tf_warning_or_error);
+tf_warning_or_error);
 
   if (traits_class == error_mark_node)
 {
@@ -400,7 +400,7 @@ instantiate_coro_handle_for_promise_type (location_t kw, 
tree promise_type)
 = lookup_template_class (coro_handle_identifier, targ,
 /* in_decl=*/NULL_TREE,
 /* context=*/std_node,
-/* entering scope=*/false, tf_warning_or_error);
+tf_warning_or_error);
 
   if (handle_type == error_mark_node)
 {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 933504b4821..1ba7054f8bc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7524,8 +7524,9 @@ extern tree push_template_decl(tree, 
bool 

[gcc r13-8670] c++: problematic assert in reference_binding [PR113141]

2024-05-01 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c70abea054fe0021b7b2c2e07996afaadc17a07b

commit r13-8670-gc70abea054fe0021b7b2c2e07996afaadc17a07b
Author: Patrick Palka 
Date:   Wed May 1 18:16:08 2024 -0400

c++: problematic assert in reference_binding [PR113141]

r14-9946 / r14-9947 fixed this PR properly for GCC 14.

For GCC 13, let's just remove the problematic assert.

PR c++/113141

gcc/cp/ChangeLog:

* call.cc (reference_binding): Remove badness criteria sanity
check in the recursive case.

gcc/testsuite/ChangeLog:

* g++.dg/conversion/ref12.C: New test.
* g++.dg/cpp0x/initlist-ref1.C: new test.

Diff:
---
 gcc/cp/call.cc |  1 -
 gcc/testsuite/g++.dg/conversion/ref12.C| 13 +
 gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C | 16 
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index b10bdc62d38..70c7f6178b8 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2017,7 +2017,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool 
c_cast_p, int flags,
if (!new_second)
  return NULL;
conv = merge_conversion_sequences (t, new_second);
-   gcc_assert (maybe_valid_p || conv->bad_p);
return conv;
  }
 }
diff --git a/gcc/testsuite/g++.dg/conversion/ref12.C 
b/gcc/testsuite/g++.dg/conversion/ref12.C
new file mode 100644
index 000..633b7e48e47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref12.C
@@ -0,0 +1,13 @@
+// PR c++/113141
+
+struct Matrix { };
+
+struct TPoint3 { operator const Matrix(); };
+
+void f(Matrix&);
+
+int main() {
+  TPoint3 X;
+  Matrix& m = (Matrix &)X;
+  f((Matrix &)X);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C 
b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
new file mode 100644
index 000..f893f12dafa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
@@ -0,0 +1,16 @@
+// PR c++/113141
+// { dg-do compile { target c++11 } }
+
+struct ConvToRef {
+  operator int&();
+};
+
+struct A { int& r; };
+
+void f(A);
+
+int main() {
+  ConvToRef c;
+  A a{{c}};
+  f({{c}});
+}


[gcc r15-57] c++/modules: imported spec befriending class tmpl [PR114889]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:22b20ac6c6aead2d3f36c413a77dd0b80adfec39

commit r15-57-g22b20ac6c6aead2d3f36c413a77dd0b80adfec39
Author: Patrick Palka 
Date:   Mon Apr 29 21:27:59 2024 -0400

c++/modules: imported spec befriending class tmpl [PR114889]

When adding to CLASSTYPE_BEFRIENDING_CLASSES as part of installing an
imported class definition, we need to look through TEMPLATE_DECL like
make_friend_class does.

Otherwise in the below testcase we won't add _Hashtable to
CLASSTYPE_BEFRIENDING_CLASSES of _Map_base, which leads to a bogus
access check failure for _M_hash_code.

PR c++/114889

gcc/cp/ChangeLog:

* module.cc (trees_in::read_class_def): Look through
TEMPLATE_DECL when adding to CLASSTYPE_BEFRIENDING_CLASSES.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-8_a.H: New test.
* g++.dg/modules/friend-8_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  |  2 ++
 gcc/testsuite/g++.dg/modules/friend-8_a.H | 23 +++
 gcc/testsuite/g++.dg/modules/friend-8_b.C |  9 +
 3 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c35e70b8cb8..3bf863e15d4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12498,6 +12498,8 @@ trees_in::read_class_def (tree defn, tree 
maybe_template)
  for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes))
{
  tree f = TREE_VALUE (friend_classes);
+ if (TREE_CODE (f) == TEMPLATE_DECL)
+   f = TREE_TYPE (f);
 
  if (CLASS_TYPE_P (f))
{
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_a.H 
b/gcc/testsuite/g++.dg/modules/friend-8_a.H
new file mode 100644
index 000..b07ea25adfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_a.H
@@ -0,0 +1,23 @@
+// PR c++/114889
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct _Hashtable;
+
+template
+struct _Map_base {
+  void f() {
+_Hashtable<_Key, _Val> __h;
+__h._M_hash_code(0);
+  }
+};
+
+template
+struct _Hashtable {
+  template friend struct _Map_base;
+protected:
+  void _M_hash_code(int);
+};
+
+inline _Hashtable m;
diff --git a/gcc/testsuite/g++.dg/modules/friend-8_b.C 
b/gcc/testsuite/g++.dg/modules/friend-8_b.C
new file mode 100644
index 000..b04280bc91a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-8_b.C
@@ -0,0 +1,9 @@
+// PR c++/114889
+// { dg-additional-options "-fmodules-ts" }
+
+import "friend-8_a.H";
+
+int main() {
+  _Map_base m;
+  m.f();
+}


[gcc r14-10149] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3c925ac349b03ae9439c632fb1c042cdc8d78f40

commit r14-10149-g3c925ac349b03ae9439c632fb1c042cdc8d78f40
Author: Patrick Palka 
Date:   Mon Apr 29 21:14:18 2024 -0400

c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

In the sizeof / sizeof operator expression handling we're missing
a dependence check for the second operand.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 3900e944b0ac9db77380c5bb8635977dfd3b0691)

Diff:
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;


[gcc r15-56] c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

2024-04-29 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:3900e944b0ac9db77380c5bb8635977dfd3b0691

commit r15-56-g3900e944b0ac9db77380c5bb8635977dfd3b0691
Author: Patrick Palka 
Date:   Mon Apr 29 21:14:18 2024 -0400

c++: ICE with templated sizeof(E1) / sizeof(E2) [PR114888]

In the sizeof / sizeof operator expression handling we're missing
a dependence check for the second operand.

PR c++/114888

gcc/cp/ChangeLog:

* typeck.cc (cp_build_binary_op) : Add missing
dependence check for the second sizeof operand.

gcc/testsuite/ChangeLog:

* g++.dg/template/sizeof19.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/typeck.cc | 1 +
 gcc/testsuite/g++.dg/template/sizeof19.C | 8 
 2 files changed, 9 insertions(+)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index e5a52dc2b39..a25f8622651 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5501,6 +5501,7 @@ cp_build_binary_op (const op_location_t ,
  if (!TYPE_P (type1))
type1 = TREE_TYPE (type1);
  if (type0
+ && type1
  && INDIRECT_TYPE_P (type0)
  && same_type_p (TREE_TYPE (type0), type1))
{
diff --git a/gcc/testsuite/g++.dg/template/sizeof19.C 
b/gcc/testsuite/g++.dg/template/sizeof19.C
new file mode 100644
index 000..a1467995a9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sizeof19.C
@@ -0,0 +1,8 @@
+// PR c++/114888
+
+template
+struct A {
+  struct B {} *b;
+  static const int c = sizeof (b) / sizeof (b[0]);
+};
+const int d = A::c;


[gcc r14-10140] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:c014cfd8853240827feb3a4cef92403e83cd4265

commit r14-10140-gc014cfd8853240827feb3a4cef92403e83cd4265
Author: Patrick Palka 
Date:   Fri Apr 26 07:44:25 2024 -0400

c++: fix source printing for "required from here" message

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
(added in r14-4388-g1c45319b66edc9) since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test 
(42); // { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   
~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear the
pretty printer prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the "required from here" message.
* g++.dg/template/error60a.C: New test.

(cherry picked from commit 7d5479a2ecf6309281de10b747a7423169a2ff95)

Diff:
---
 gcc/cp/error.cc |  2 ++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 +++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..37987ccb570 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  pp_set_prefix (context->printer, saved_prefix);
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar();
+   ^~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "for required from 

[gcc r15-4] c++: fix source printing for "required from here" message

2024-04-26 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:7d5479a2ecf6309281de10b747a7423169a2ff95

commit r15-4-g7d5479a2ecf6309281de10b747a7423169a2ff95
Author: Patrick Palka 
Date:   Fri Apr 26 07:44:25 2024 -0400

c++: fix source printing for "required from here" message

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
(added in r14-4388-g1c45319b66edc9) since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:25 |   test 
(42); // { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:   |   
~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was 
not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
  |   ^~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void 
test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test (42); // { dg-message " required from here" }
  |   ~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion 
from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer ptr (val); // { dg-error "invalid conversion from 
'int' to 'int\\*'" }
  |^~~
  ||
  |int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing 
argument 1 of ‘my_pointer::my_pointer(Foo*) [with Foo = int]’
9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
  |   ~^~~

gcc/cp/ChangeLog:

* error.cc (print_instantiation_partial_context_line): Clear the
pretty printer prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: Expect source line printed
for the "required from here" message.
* g++.dg/template/error60a.C: New test.

Diff:
---
 gcc/cp/error.cc |  2 ++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 +++-
 gcc/testsuite/g++.dg/template/error60a.C| 46 +
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..37987ccb570 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line 
(diagnostic_context *context,
   : _("required from here\n"));
 }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, _loc, DK_NOTE);
+  pp_set_prefix (context->printer, saved_prefix);
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@ void
 baz()
 {
   bar(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar();
+   ^~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "for required from here message" }
bar();
^~
{ dg-end-multiline-output "" } */

[gcc r14-10111] c++/modules testsuite: restrict expensive pr99023 test

2024-04-24 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:26a3edbe2357cf975f345ad1b59b9f9a3444316e

commit r14-10111-g26a3edbe2357cf975f345ad1b59b9f9a3444316e
Author: Patrick Palka 
Date:   Wed Apr 24 17:51:54 2024 -0400

c++/modules testsuite: restrict expensive pr99023 test

The pr99023 testcase uses --param=ggc-min-expand=0 which forces a GC
during every collection point and consequently is very slow to run,
and ends up being the main bottleneck of the modules.exp testsuite.

So this patch restricts this test to run once, in C++20 mode, instead of
multiple times (C++17, C++20 and C++23 mode by default).  After this
patch the modules.exp testsuite finishes in 3m instead of 3m40s with -j8
on my machine.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99023_a.X: Run only in C++20 mode.
* g++.dg/modules/pr99023_b.X: Likewise.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/testsuite/g++.dg/modules/pr99023_a.X | 1 +
 gcc/testsuite/g++.dg/modules/pr99023_b.X | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/testsuite/g++.dg/modules/pr99023_a.X 
b/gcc/testsuite/g++.dg/modules/pr99023_a.X
index c872d15f792..507e9569535 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_a.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_a.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header initializer_list -fmodules-ts 
--param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }
diff --git a/gcc/testsuite/g++.dg/modules/pr99023_b.X 
b/gcc/testsuite/g++.dg/modules/pr99023_b.X
index ca5f32e5bcc..59d32bee8d5 100644
--- a/gcc/testsuite/g++.dg/modules/pr99023_b.X
+++ b/gcc/testsuite/g++.dg/modules/pr99023_b.X
@@ -1,4 +1,5 @@
 // PR c++/99023, ICE
+// { dg-require-effective-target c++20_only }
 // { dg-additional-options {-x c++-system-header iostream -fmodules-ts 
-flang-info-include-translate= --param ggc-min-expand=0} }
 
 // { dg-prune-output {linker input file unused} }


[gcc r14-10110] c++: constexpr union member access folding [PR114709]

2024-04-24 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:0844170e9ef60a8b2f6fba6786672f30ce1c2749

commit r14-10110-g0844170e9ef60a8b2f6fba6786672f30ce1c2749
Author: Patrick Palka 
Date:   Wed Apr 24 17:49:56 2024 -0400

c++: constexpr union member access folding [PR114709]

The object/offset canonicalization performed in cxx_fold_indirect_ref
is undesirable for union member accesses because it loses information
about the member being accessed which we may later need to diagnose an
inactive-member access.  So this patch restricts the canonicalization
accordingly.

PR c++/114709

gcc/cp/ChangeLog:

* constexpr.cc (cxx_fold_indirect_ref): Restrict object/offset
canonicalization to RECORD_TYPE member accesses.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-union8.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constexpr.cc   | 3 +++
 gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C | 8 
 2 files changed, 11 insertions(+)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 302b266809f..2e83d24dfda 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5799,6 +5799,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, 
location_t loc, tree type,
  more folding opportunities.  */
   auto canonicalize_obj_off = [] (tree& obj, tree& off) {
 while (TREE_CODE (obj) == COMPONENT_REF
+  /* We need to preserve union member accesses so that we can
+ later properly diagnose accessing the wrong member.  */
+  && TREE_CODE (TREE_TYPE (TREE_OPERAND (obj, 0))) == RECORD_TYPE
   && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
   {
tree field = TREE_OPERAND (obj, 1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
new file mode 100644
index 000..34c264944b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union8.C
@@ -0,0 +1,8 @@
+// PR c++/114709
+// { dg-do compile { target c++11 } }
+
+struct T1 { int a, b; };
+struct T2 { int c; double d; };
+union U { T1 t1; T2 t2; };
+
+constexpr int v = U{{1,2}}.t2.*::c; // { dg-error "accessing 'U::t2'" }


[gcc r14-10096] c++/modules: deduced return type merging [PR114795]

2024-04-23 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:4f9401d1a802325e5dfa2db841945e1a9c59a980

commit r14-10096-g4f9401d1a802325e5dfa2db841945e1a9c59a980
Author: Patrick Palka 
Date:   Tue Apr 23 14:01:22 2024 -0400

c++/modules: deduced return type merging [PR114795]

When merging an imported function template specialization with an
existing one, if the existing one has an undeduced return type and the
imported one's is already deduced, we need to propagate the deduced type
since once we install the imported definition we won't get a chance to
deduce it by normal means.

So this patch makes is_matching_decl propagate the deduced return
type alongside our propagation of the exception specification.
Another option would be to propagate it later when installing the
imported definition from read_function_def, but it seems preferable
to do it sooner rather than later.

PR c++/114795

gcc/cp/ChangeLog:

* module.cc (trees_in::is_matching_decl): Propagate deduced
function return type.

gcc/testsuite/ChangeLog:

* g++.dg/modules/auto-4_a.H: New test.
* g++.dg/modules/auto-4_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc|  9 +
 gcc/testsuite/g++.dg/modules/auto-4_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/auto-4_b.C | 15 +++
 3 files changed, 38 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d94d8ff4df9..c35e70b8cb8 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11537,6 +11537,15 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
   else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
   && !comp_except_specs (d_spec, e_spec, ce_type))
goto mismatch;
+
+  /* Similarly if EXISTING has an undeduced return type, but DECL's
+is already deduced.  */
+  if (undeduced_auto_decl (existing) && !undeduced_auto_decl (decl))
+   {
+ dump (dumper::MERGE)
+   && dump ("Propagating deduced return type to %N", existing);
+ TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), 
e_type);
+   }
 }
   else if (is_typedef)
 {
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_a.H 
b/gcc/testsuite/g++.dg/modules/auto-4_a.H
new file mode 100644
index 000..0f7cd262dfa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_a.H
@@ -0,0 +1,14 @@
+// PR c++/114795
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+template
+void g() {
+  A a;
+  a.f();
+}
diff --git a/gcc/testsuite/g++.dg/modules/auto-4_b.C 
b/gcc/testsuite/g++.dg/modules/auto-4_b.C
new file mode 100644
index 000..378684ef6d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/auto-4_b.C
@@ -0,0 +1,15 @@
+// PR c++/114795
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+template
+struct A {
+  auto f() { return T(); }
+};
+
+A a;
+
+import "auto-4_a.H";
+
+int main() {
+  g(); // { dg-bogus "before deduction of 'auto'" "" { target *-*-* } 0 }
+}


[gcc r13-8608] c++: requires-exprs and partial constraint subst [PR110006]

2024-04-15 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:38c2679ff9330d3ac1d5d86459294446733a435a

commit r13-8608-g38c2679ff9330d3ac1d5d86459294446733a435a
Author: Patrick Palka 
Date:   Fri Feb 2 19:07:08 2024 -0500

c++: requires-exprs and partial constraint subst [PR110006]

In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially
substitute into a requires-expression so as to avoid checking its
requirements out of order during e.g. generic lambda regeneration.

These PRs however illustrate that we still sometimes do need to
partially substitute into a requires-expression, in particular when it
appears in associated constraints that we're directly substituting for
sake of declaration matching or dguide constraint rewriting.  In these
cases we're being called from tsubst_constraint during which
processing_constraint_expression_p is true, so this patch checks this
predicate to control whether we defer substitution or partially
substitute.

In turn, we now need to propagate semantic tsubst flags through
tsubst_requires_expr rather than just using tf_none, notably for sake of
dguide constraint rewriting which sets tf_dguide.

PR c++/110006
PR c++/112769

gcc/cp/ChangeLog:

* constraint.cc (subst_info::quiet): Accomodate non-diagnostic
tsubst flags.
(tsubst_valid_expression_requirement): Likewise.
(tsubst_simple_requirement): Return a substituted _REQ node when
processing_template_decl.
(tsubst_type_requirement_1): Accomodate non-diagnostic tsubst
flags.
(tsubst_type_requirement): Return a substituted _REQ node when
processing_template_decl.
(tsubst_compound_requirement): Likewise.  Accomodate non-diagnostic
tsubst flags.
(tsubst_nested_requirement): Likewise.
(tsubst_requires_expr): Don't defer partial substitution when
processing_constraint_expression_p is true, in which case return
a substituted REQUIRES_EXPR.
* pt.cc (tsubst_expr) : Accomodate
non-diagnostic tsubst flags.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-alias18.C: New test.
* g++.dg/cpp2a/concepts-friend16.C: New test.

Reviewed-by: Jason Merrill 
(cherry picked from commit 686b5eb9c9ee623a604dde5c49fa11c23f384c62)

Diff:
---
 gcc/cp/constraint.cc   | 56 +-
 gcc/cp/pt.cc   |  3 +-
 .../g++.dg/cpp2a/class-deduction-alias18.C | 13 +
 gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C | 25 ++
 4 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 273d15ab097..971619eabea 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -85,7 +85,7 @@ struct subst_info
   /* True if we should not diagnose errors.  */
   bool quiet() const
   {
-return complain == tf_none;
+return !(complain & tf_warning_or_error);
   }
 
   /* True if we should diagnose errors.  */
@@ -1999,8 +1999,9 @@ hash_placeholder_constraint (tree c)
 static tree
 tsubst_valid_expression_requirement (tree t, tree args, sat_info info)
 {
-  tree r = tsubst_expr (t, args, tf_none, info.in_decl);
-  if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node)
+  tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
+  tree r = tsubst_expr (t, args, quiet, info.in_decl);
+  if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node)
 return r;
 
   if (info.diagnose_unsatisfaction_p ())
@@ -2036,6 +2037,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info 
info)
   tree expr = tsubst_valid_expression_requirement (t0, args, info);
   if (expr == error_mark_node)
 return error_mark_node;
+  if (processing_template_decl)
+return finish_simple_requirement (EXPR_LOCATION (t), expr);
   return boolean_true_node;
 }
 
@@ -2045,7 +2048,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info 
info)
 static tree
 tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc)
 {
-  tree r = tsubst (t, args, tf_none, info.in_decl);
+  tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
+  tree r = tsubst (t, args, quiet, info.in_decl);
   if (r != error_mark_node)
 return r;
 
@@ -2076,6 +2080,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info)
   tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t));
   if (type == error_mark_node)
 return error_mark_node;
+  if (processing_template_decl)
+return finish_type_requirement (EXPR_LOCATION (t), type);
   return boolean_true_node;
 }
 
@@ -2132,9 +2138,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info 
info)
 
   location_t loc = cp_expr_loc_or_input_loc (expr);
 
+  subst_info quiet (info.complain & 

[gcc r14-9956] c++/modules: make bits_in/out move-constructible

2024-04-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:da375baf54944298303f13c375a5756c6131d672

commit r14-9956-gda375baf54944298303f13c375a5756c6131d672
Author: Patrick Palka 
Date:   Sat Apr 13 16:06:28 2024 -0400

c++/modules: make bits_in/out move-constructible

gcc/cp/ChangeLog:

* module.cc (struct bytes_in::bits_in): Define defaulted
move ctor.
(struct bytes_out::bits_out): Likewise.

Diff:
---
 gcc/cp/module.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index bbed82652d4..c6f71e11515 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -706,6 +706,7 @@ struct bytes_in::bits_in {
 bflush ();
   }
 
+  bits_in(bits_in&&) = default;
   bits_in(const bits_in&) = delete;
   bits_in& operator=(const bits_in&) = delete;
 
@@ -752,6 +753,7 @@ struct bytes_out::bits_out {
 bflush ();
   }
 
+  bits_out(bits_out&&) = default;
   bits_out(const bits_out&) = delete;
   bits_out& operator=(const bits_out&) = delete;


[gcc r14-9955] c++/modules: optimize tree flag streaming

2024-04-13 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:436ab7e8e8b16866d8a807af242560ad4fdff0d6

commit r14-9955-g436ab7e8e8b16866d8a807af242560ad4fdff0d6
Author: Patrick Palka 
Date:   Sat Apr 13 10:52:32 2024 -0400

c++/modules: optimize tree flag streaming

One would expect consecutive calls to bytes_in/out::b for streaming
adjacent bits, as is done for tree flag streaming, to at least be
optimized by the compiler into individual bit operations using
statically known bit positions (and ideally combined into larger sized
reads/writes).

Unfortunately this doesn't happen because the compiler has trouble
tracking the values of this->bit_pos and this->bit_val across the
calls, likely because the compiler doesn't know the value of 'this'.
Thus for each consecutive bit stream operation, bit_pos and bit_val are
loaded from 'this', checked if buffering is needed, and finally the bit
is extracted from bit_val according to the (unknown) bit_pos, even
though relative to the previous operation (if we didn't need to buffer)
bit_val is unchanged and bit_pos is just 1 larger.  This ends up being
quite slow, with tree_node_bools taking 10% of time when streaming in
the std module.

This patch improves this by making tracking of bit_pos and bit_val
easier for the compiler.  Rather than bit_pos and bit_val being members
of the (effectively global) bytes_in/out objects, this patch factors out
the bit streaming code/state into separate classes bits_in/out that get
constructed locally as needed for bit streaming.  Since these objects
are now clearly local, the compiler can more easily track their values
and optimize away redundant buffering checks.

And since bit streaming is intended to be batched it's natural for these
new classes to be RAII-enabled such that the bit stream is flushed upon
destruction.

In order to make the most of this improved tracking of bit position,
this patch changes parts where we conditionally stream a tree flag
to unconditionally stream (the flag or a dummy value).  That way
the number of bits streamed and the respective bit positions are as
statically known as reasonably possible.  In lang_decl_bools and
lang_type_bools this patch makes us flush the current bit buffer at the
start so that subsequent bit positions are in turn statically known.
And in core_bools, we can add explicit early exits utilizing invariants
that the compiler can't figure out itself (e.g. a tree code can't have
both TS_TYPE_COMMON and TS_DECL_COMMON, and if a tree code doesn't have
TS_DECL_COMMON then it doesn't have TS_DECL_WITH_VIS).

This patch also moves the definitions of the relevant streaming classes
into anonymous namespaces so that the compiler can make more informed
decisions about inlining their member functions.

After this patch, compile time for a simple Hello World using the std
module is reduced by 7% with a release compiler.  The on-disk size of
the std module increases by 0.4% (presumably due to the extra flushing
done in lang_decl_bools and lang_type_bools).

The bit stream out performance isn't improved as much as the stream in
due to the spans/lengths instrumentation performed on stream out (which
maybe should be disabled for release builds?)

gcc/cp/ChangeLog:

* module.cc: Update comment about classes defined within.
(class data): Enclose in an anonymous namespace.
(data::calc_crc): Moved from bytes::calc_crc.
(class bytes): Remove.  Move bit_flush to namespace scope.
(class bytes_in): Enclose in an anonymous namespace.  Inherit
directly from data and adjust accordingly.  Move b and bflush
members to bits_in.
(class bytes_out): As above.  Remove is_set static data member.
(bit_flush): Moved from class bytes.
(struct bytes_in::bits_in): Define.
(struct bytes_out::bits_out): Define.
(bytes_in::stream_bits): Define.
(bytes_out::stream_bits): Define.
(bytes_out::bflush): Moved to bits_out/in.
(bytes_in::bflush): Likewise
(bytes_in::bfill): Removed.
(bytes_out::b): Moved to bits_out/in.
(bytes_in::b): Likewise.
(class trees_in): Enclose in an anonymous namespace.
(class trees_out): Enclose in an anonymous namespace.
(trees_out::core_bools): Add bits_out/in parameter and use it.
Unconditionally stream a bit for public_flag.  Add early exits
as appropriate.
(trees_out::core_bools): Likewise.
(trees_out::lang_decl_bools): Add bits_out/in parameter and use
it.  Flush the current bit buffer at the start.  Unconditionally
stream a bit for module_keyed_decls_p.

[gcc r14-9948] c++/modules: local type merging [PR99426]

2024-04-12 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:716af95fd454871473c4b118b8412b6a68459b75

commit r14-9948-g716af95fd454871473c4b118b8412b6a68459b75
Author: Patrick Palka 
Date:   Fri Apr 12 15:50:04 2024 -0400

c++/modules: local type merging [PR99426]

One known missing piece in the modules implementation is merging of a
streamed-in local type (class or enum) with the corresponding in-TU
version of the local type.  This missing piece turns out to cause a
hard-to-reduce use-after-free GC issue due to the entity_ary not being
marked as a GC root (deliberately), and manifests as a serialization
error on stream-in as in PR99426 (see comment #6 for a reduction).  It's
also reproducible on trunk when running the xtreme-header tests without
-fno-module-lazy.

This patch implements this missing piece, making us merge such local
types according to their position within the containing function's
definition, analogous to how we merge FIELD_DECLs of a class according
to their index in the TYPE_FIELDS list.

PR c++/99426

gcc/cp/ChangeLog:

* module.cc (merge_kind::MK_local_type): New enumerator.
(merge_kind_name): Update.
(trees_out::chained_decls): Move BLOCK-specific handling
of DECL_LOCAL_DECL_P decls to ...
(trees_out::core_vals) : ... here.  Stream
BLOCK_VARS manually.
(trees_in::core_vals) : Stream BLOCK_VARS
manually.  Handle deduplicated local types..
(trees_out::key_local_type): Define.
(trees_in::key_local_type): Define.
(trees_out::get_merge_kind) : Return
MK_local_type for a local type.
(trees_out::key_mergeable) : Use
key_local_type.
(trees_in::key_mergeable) : Likewise.
(trees_in::is_matching_decl): Be flexible with type mismatches
for local entities.
(trees_in::register_duplicate): Also register the
DECL_TEMPLATE_RESULT of a TEMPLATE_DECL as a duplicate.
(depset_cmp): Return 0 for equal IDENTIFIER_HASH_VALUEs.

gcc/testsuite/ChangeLog:

* g++.dg/modules/merge-17.h: New test.
* g++.dg/modules/merge-17_a.H: New test.
* g++.dg/modules/merge-17_b.C: New test.
* g++.dg/modules/xtreme-header-7_a.H: New test.
* g++.dg/modules/xtreme-header-7_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc | 180 +++
 gcc/testsuite/g++.dg/modules/merge-17.h  |  58 
 gcc/testsuite/g++.dg/modules/merge-17_a.H|   3 +
 gcc/testsuite/g++.dg/modules/merge-17_b.C|   3 +
 gcc/testsuite/g++.dg/modules/xtreme-header-7_a.H |   4 +
 gcc/testsuite/g++.dg/modules/xtreme-header-7_b.C |   5 +
 6 files changed, 222 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ad1b6bf5ca4..9917a6abe4f 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2758,6 +2758,7 @@ enum merge_kind
 
   MK_enum, /* Found by CTX, & 1stMemberNAME.  */
   MK_keyed, /* Found by key & index.  */
+  MK_local_type, /* Found by CTX, index.  */
 
   MK_friend_spec,  /* Like named, but has a tmpl & args too.  */
   MK_local_friend, /* Found by CTX, index.  */
@@ -2784,7 +2785,7 @@ static char const *const merge_kind_name[MK_hwm] =
 "unique", "named", "field", "vtable",  /* 0...3  */
 "asbase", "partial", "enum", "attached",   /* 4...7  */
 
-"friend spec", "local friend", NULL, NULL,  /* 8...11 */
+"local type", "friend spec", "local friend", NULL,  /* 8...11 */
 NULL, NULL, NULL, NULL,
 
 "type spec", "type tmpl spec", /* 16,17 type (template).  */
@@ -2913,6 +2914,7 @@ public:
   unsigned binfo_mergeable (tree *);
 
 private:
+  tree key_local_type (const merge_key&, tree, tree);
   uintptr_t *find_duplicate (tree existing);
   void register_duplicate (tree decl, tree existing);
   /* Mark as an already diagnosed bad duplicate.  */
@@ -3071,6 +3073,7 @@ public:
   void binfo_mergeable (tree binfo);
 
 private:
+  void key_local_type (merge_key&, tree, tree);
   bool decl_node (tree, walk_kind ref);
   void type_node (tree);
   void tree_value (tree);
@@ -4937,18 +4940,7 @@ void
 trees_out::chained_decls (tree decls)
 {
   for (; decls; decls = DECL_CHAIN (decls))
-{
-  if (VAR_OR_FUNCTION_DECL_P (decls)
- && DECL_LOCAL_DECL_P (decls))
-   {
- /* Make sure this is the first encounter, and mark for
-walk-by-value.  */
- gcc_checking_assert (!TREE_VISITED (decls)
-  && !DECL_TEMPLATE_INFO (decls));
- mark_by_value (decls);
-   }
-  tree_node (decls);
-}
+tree_node (decls);
   tree_node (NULL_TREE);
 }
 
@@ -6198,7 +6190,21 @@ trees_out::core_vals (tree t)
 
   /* DECL_LOCAL_DECL_P decls are first encountered here 

[gcc r14-9943] c++: templated substitution into lambda-expr, cont [PR114393]

2024-04-12 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:d74fe10b13336b9de2e025ced4af00a25ff1d3e7

commit r14-9943-gd74fe10b13336b9de2e025ced4af00a25ff1d3e7
Author: Patrick Palka 
Date:   Fri Apr 12 14:52:31 2024 -0400

c++: templated substitution into lambda-expr, cont [PR114393]

The original PR114393 testcase is unfortunately still not accepted after
r14-9938-g081c1e93d56d35 due to return type deduction confusion when a
lambda-expr is used as a default template argument.

The below reduced testcase demonstrates the bug.  Here when forming the
dependent specialization b_v we substitute the default argument of F,
a lambda-expr, with _Descriptor=U.  (In this case in_template_context is
true since we're in the context of the template c_v, so we don't defer.)
This substitution in turn lowers the level of the lambda's auto return
type from 2 to 1 and so later, when instantiating c_v we wrongly
substitute this auto with the template argument at level=0,index=0, i.e.
int, instead of going through do_auto_deduction which would yield char.

One way to fix this would be to use a level-less auto to represent a
deduced return type of a lambda, but that might be too invasive of a
change at this stage, and it might be better to do this across the board
for all deduced return types.

Another way would be to pass tf_partial from coerce_template_parms during
dependent substitution into a default template argument so that the
substitution doesn't do any level-lowering, but that wouldn't do the right
thing in this case due to the tf_partial early exit in the LAMBDA_EXPR
case of tsubst_expr.

Yet another way, and the approach that this patch takes, is to just
defer all dependent substitution into a lambda-expr, building upon the
logic added in r14-9938-g081c1e93d56d35.  This also helps ensure
LAMBDA_EXPR_REGEN_INFO consists only of the concrete template arguments
that were ultimately substituted into the most general lambda.

PR c++/114393

gcc/cp/ChangeLog:

* pt.cc (tsubst_lambda_expr): Also defer all dependent
substitution.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-targ2a.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   |  9 +++--
 gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C | 14 ++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ec259ee0fbf..3b2106dd3f6 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19622,11 +19622,16 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
   in_decl = oldfn;
 
   args = add_extra_args (LAMBDA_EXPR_EXTRA_ARGS (t), args, complain, in_decl);
-  if (processing_template_decl && !in_template_context)
+  if (processing_template_decl
+  && (!in_template_context || any_dependent_template_arguments_p (args)))
 {
   /* Defer templated substitution into a lambda-expr if we lost the
 necessary template context.  This may happen for a lambda-expr
-used as a default template argument.  */
+used as a default template argument.
+
+Defer dependent substitution as well so that we don't prematurely
+lower the level of a deduced return type or any other auto or
+template parameter belonging to the lambda.  */
   t = copy_node (t);
   LAMBDA_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C
new file mode 100644
index 000..7136ce79872
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2a.C
@@ -0,0 +1,14 @@
+// PR c++/114393
+// { dg-do compile { target c++20 } }
+
+template  struct c1 {};
+
+template 
+inline constexpr auto b_v = F;
+
+template 
+inline constexpr auto c_v = b_v;
+
+auto f = c_v;
+using type = decltype(f());
+using type = char;


[gcc r14-9938] c++: templated substitution into lambda-expr [PR114393]

2024-04-12 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:081c1e93d56d35c7314ed68e6d87628b430de917

commit r14-9938-g081c1e93d56d35c7314ed68e6d87628b430de917
Author: Patrick Palka 
Date:   Fri Apr 12 08:59:27 2024 -0400

c++: templated substitution into lambda-expr [PR114393]

The below testcases use a lambda-expr as a template argument and they
all trip over the below added tsubst_lambda_expr sanity check ultimately
because current_template_parms is empty which causes push_template_decl
to return error_mark_node from the call to begin_lambda_type.  Were it
not for the sanity check this silent error_mark_node result leads to
nonsensical errors down the line, or silent breakage.

In the first testcase, we hit this assert during instantiation of the
dependent alias template-id c1_t<_Data> from instantiate_template, which
clears current_template_parms via push_to_top_level.  Similar story for
the second testcase.  For the third testcase we hit the assert during
partial instantiation of the member template from instantiate_class_template
which similarly calls push_to_top_level.

These testcases illustrate that templated substitution into a lambda-expr
is not always possible, in particular when we lost the relevant template
context.  I experimented with recovering the template context by making
tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
current_template_parms is empty which worked but seemed like a hack.  I
also experimented with preserving the template context by keeping
current_template_parms set during instantiate_template for a dependent
specialization which also worked but it's at odds with the fact that we
cache dependent specializations (and so they should be independent of
the template context).

So instead of trying to make such substitution work, this patch uses the
extra-args mechanism to defer templated substitution into a lambda-expr
when we lost the relevant template context.

PR c++/114393
PR c++/107457
PR c++/93595

gcc/cp/ChangeLog:

* cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS): Define.
(tree_lambda_expr::extra_args): New field.
* module.cc (trees_out::core_vals) : Stream
LAMBDA_EXPR_EXTRA_ARGS.
(trees_in::core_vals) : Likewise.
* pt.cc (has_extra_args_mechanism_p): Return true for LAMBDA_EXPR.
(tree_extra_args): Handle LAMBDA_EXPR.
(tsubst_lambda_expr): Use LAMBDA_EXPR_EXTRA_ARGS to defer templated
substitution into a lambda-expr if we lost the template context.
Add sanity check for error_mark_node result from begin_lambda_type.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-targ2.C: New test.
* g++.dg/cpp2a/lambda-targ3.C: New test.
* g++.dg/cpp2a/lambda-targ4.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h  |  5 +
 gcc/cp/module.cc  |  2 ++
 gcc/cp/pt.cc  | 22 --
 gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C | 19 +++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C | 12 
 gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C | 12 
 6 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d53589e51..1dbb577a38d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_REGEN_INFO(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info)
 
+/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions.  */
+#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \
+  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args)
+
 /* The closure type of the lambda, which is also the type of the
LAMBDA_EXPR.  */
 #define LAMBDA_EXPR_CLOSURE(NODE) \
@@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr
   tree this_capture;
   tree extra_scope;
   tree regen_info;
+  tree extra_args;
   vec *pending_proxies;
   location_t locus;
   enum cp_lambda_default_capture_mode_type default_capture_mode : 2;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 4e91fa6e052..ad1b6bf5ca4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6312,6 +6312,7 @@ trees_out::core_vals (tree t)
   WT (((lang_tree_node *)t)->lambda_expression.this_capture);
   WT (((lang_tree_node *)t)->lambda_expression.extra_scope);
   WT (((lang_tree_node *)t)->lambda_expression.regen_info);
+  WT (((lang_tree_node *)t)->lambda_expression.extra_args);
   /* pending_proxies is a parse-time thing.  */
   gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies);
   if (state)
@@ -6814,6 +6815,7 @@ trees_in::core_vals (tree t)
   RT (((lang_tree_node 

[gcc r14-9916] c++: build_extra_args recapturing local specs [PR114303]

2024-04-11 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:b262b17636e47ae969a74f16e86ccb00678d5e88

commit r14-9916-gb262b17636e47ae969a74f16e86ccb00678d5e88
Author: Patrick Palka 
Date:   Thu Apr 11 10:16:41 2024 -0400

c++: build_extra_args recapturing local specs [PR114303]

r13-6452-g341e6cd8d603a3 made build_extra_args walk evaluated contexts
first so that we prefer processing a local specialization in an evaluated
context even if its first use is in an unevaluated context.  But this
means we need to avoid walking a tree that already has extra args/specs
saved because the list of saved specs appears to be an evaluated
context which we'll now walk first.  It seems then that we should be
calculating the saved specs from scratch each time, rather than
potentially walking the saved specs list from an earlier partial
instantiation when calling build_extra_args a second time around.

PR c++/114303

gcc/cp/ChangeLog:

* constraint.cc (tsubst_requires_expr): Clear
REQUIRES_EXPR_EXTRA_ARGS before calling build_extra_args.
* pt.cc (tree_extra_args): Define.
(extract_locals_r): Assert *_EXTRA_ARGS is empty.
(tsubst_stmt) : Clear IF_SCOPE on the new
IF_STMT.  Call build_extra_args on the new IF_STMT instead
of t which might already have IF_STMT_EXTRA_ARGS.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/constexpr-if-lambda6.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/constraint.cc  |  1 +
 gcc/cp/pt.cc  | 31 ++-
 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C | 16 
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 49de3211d4c..8a3b5d80ba7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2362,6 +2362,7 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
 matching or dguide constraint rewriting), in which case we need
 to partially substitute.  */
   t = copy_node (t);
+  REQUIRES_EXPR_EXTRA_ARGS (t) = NULL_TREE;
   REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
   return t;
 }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 767778e53ef..7c91c6959aa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3858,6 +3858,24 @@ has_extra_args_mechanism_p (const_tree t)
  && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS  */
 }
 
+/* Return *_EXTRA_ARGS of the given supported tree T.  */
+
+static tree&
+tree_extra_args (tree t)
+{
+  gcc_checking_assert (has_extra_args_mechanism_p (t));
+
+  if (PACK_EXPANSION_P (t))
+return PACK_EXPANSION_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == REQUIRES_EXPR)
+return REQUIRES_EXPR_EXTRA_ARGS (t);
+  else if (TREE_CODE (t) == IF_STMT
+  && IF_STMT_CONSTEXPR_P (t))
+return IF_STMT_EXTRA_ARGS (t);
+
+  gcc_unreachable ();
+}
+
 /* Structure used to track the progress of find_parameter_packs_r.  */
 struct find_parameter_pack_data
 {
@@ -13291,6 +13309,16 @@ extract_locals_r (tree *tp, int *walk_subtrees, void 
*data_)
 /* Remember local typedefs (85214).  */
 tp = _NAME (*tp);
 
+  if (has_extra_args_mechanism_p (*tp))
+/* Assert *_EXTRA_ARGS is empty, because we don't want to walk it and
+   potentially see a previously captured local in an evaluated context
+   that's really only used in an unevaluated context (PR114303).  This
+   means callers of build_extra_args need to clear *_EXTRA_ARGS of the
+   outermost tree.  Nested *_EXTRA_ARGS should naturally be empty since
+   the outermost (extra-args) tree will intercept any substitution before
+   a nested tree can.  */
+gcc_checking_assert (tree_extra_args (*tp) == NULL_TREE);
+
   if (TREE_CODE (*tp) == DECL_EXPR)
 {
   tree decl = DECL_EXPR_DECL (*tp);
@@ -18716,10 +18744,11 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 of the constexpr if is still dependent.  Don't substitute into the
 branches now, just remember the template arguments.  */
  do_poplevel (IF_SCOPE (stmt));
+ IF_SCOPE (stmt) = NULL_TREE;
  IF_COND (stmt) = IF_COND (t);
  THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
  ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
- IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+ IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (stmt, args, complain);
  add_stmt (stmt);
  break;
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
new file mode 100644
index 000..038c2a41210
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda6.C
@@ -0,0 +1,16 @@
+// PR c++/114303
+// { dg-do compile { target c++17 } }
+
+struct A { static constexpr 

[gcc r14-9673] c++/modules testsuite: fix a couple of dg-module-do directives

2024-03-26 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:2f47ca046eecf8f2fcae23df3ccee44d943ef512

commit r14-9673-g2f47ca046eecf8f2fcae23df3ccee44d943ef512
Author: Patrick Palka 
Date:   Tue Mar 26 10:21:53 2024 -0400

c++/modules testsuite: fix a couple of dg-module-do directives

gcc/testsuite/ChangeLog:

* g++.dg/modules/decltype-1_a.C: Add missing } to dg-module-do
directive.
* g++.dg/modules/lambda-5_a.C: Likewise.

Diff:
---
 gcc/testsuite/g++.dg/modules/decltype-1_a.C | 2 +-
 gcc/testsuite/g++.dg/modules/lambda-5_a.C   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/decltype-1_a.C 
b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
index ca66e8b598a..e4202a26de4 100644
--- a/gcc/testsuite/g++.dg/modules/decltype-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
@@ -1,5 +1,5 @@
 // PR c++/105322
-// { dg-module-do link
+// { dg-module-do link }
 // { dg-additional-options -fmodules-ts }
 // { dg-module-cmi pr105322.Decltype }
 
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_a.C 
b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
index 6b589d4965c..37d0e77b1e1 100644
--- a/gcc/testsuite/g++.dg/modules/lambda-5_a.C
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
@@ -1,5 +1,5 @@
 // PR c++/105322
-// { dg-module-do link
+// { dg-module-do link }
 // { dg-additional-options -fmodules-ts }
 // { dg-module-cmi pr105322.Lambda }


[gcc r14-9374] c++/modules: member alias tmpl partial inst [PR103994]

2024-03-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:f5c1224708a0cf9cc2770c44bbbe7d0c883942be

commit r14-9374-gf5c1224708a0cf9cc2770c44bbbe7d0c883942be
Author: Patrick Palka 
Date:   Thu Mar 7 16:39:20 2024 -0500

c++/modules: member alias tmpl partial inst [PR103994]

Alias templates are weird in that their specializations can appear in
both decl_specializations and type_specializations.  They're always in
the decl table, and additionally appear in the type table only at parse
time via finish_template_type.  There seems to be no good reason for
them to appear in both tables, and the code paths end up stepping over
each other in particular for a partial instantiation such as
A::key_arg in the below modules testcase: the type code path
(lookup_template_class) wants to set TI_TEMPLATE to the most general
template whereas the decl code path (tsubst_template_decl called during
instantiation of A) already set TI_TEMPLATE to the partially
instantiated TEMPLATE_DECL.  This TI_TEMPLATE change ends up confusing
modules which decides to stream the logically equivalent TYPE_DECL and
TEMPLATE_DECL for this partial instantiation separately.

This patch fixes this by making lookup_template_class dispatch to
instantiate_alias_template early for alias template specializations.
In turn we now add such specializations only to the decl table.  This
admits some nice simplification in the modules code which otherwise has
to cope with such specializations appearing in both tables.

PR c++/103994

gcc/cp/ChangeLog:

* cp-tree.h (add_mergeable_specialization): Remove second
parameter.
* module.cc (depset::disc_bits::DB_ALIAS_TMPL_INST_BIT): Remove.
(depset::disc_bits::DB_ALIAS_SPEC_BIT): Remove.
(depset::is_alias_tmpl_inst): Remove.
(depset::is_alias): Remove.
(merge_kind::MK_tmpl_alias_mask): Remove.
(merge_kind::MK_alias_spec): Remove.
(merge_kind_name): Remove entries for alias specializations.
(trees_out::core_vals) : Adjust after
removing is_alias_tmpl_inst.
(trees_in::decl_value): Adjust add_mergeable_specialization
calls.
(trees_out::get_merge_kind) :
Use MK_decl_spec for alias template specializations.
(trees_out::key_mergeable): Simplify after MK_tmpl_alias_mask
removal.
(depset::hash::make_dependency): Adjust after removing
DB_ALIAS_TMPL_INST_BIT.
(specialization_add): Don't allow alias templates when !decl_p.
(depset::hash::add_specializations): Remove now-dead code
accomodating alias template specializations in the type table.
* pt.cc (lookup_template_class): Dispatch early to
instantiate_alias_template for alias templates.  Simplify
accordingly.
(add_mergeable_specialization): Remove alias_p parameter and
simplify accordingly.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99425-1_b.H: s/alias/decl in dump scan.
* g++.dg/modules/tpl-alias-1_a.H: Likewise.
* g++.dg/modules/tpl-alias-2_a.H: New test.
* g++.dg/modules/tpl-alias-2_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h |  3 +-
 gcc/cp/module.cc | 86 ++--
 gcc/cp/pt.cc | 84 +++
 gcc/testsuite/g++.dg/modules/pr99425-1_b.H   |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-1_a.H |  2 +-
 gcc/testsuite/g++.dg/modules/tpl-alias-2_a.H | 15 +
 gcc/testsuite/g++.dg/modules/tpl-alias-2_b.C |  9 +++
 7 files changed, 77 insertions(+), 124 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4469d965ef0..14895bc6585 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7642,8 +7642,7 @@ extern void walk_specializations  (bool,
 void *);
 extern tree match_mergeable_specialization (bool is_decl, spec_entry *);
 extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
-extern void add_mergeable_specialization(bool is_decl, bool is_alias,
-spec_entry *,
+extern void add_mergeable_specialization(bool is_decl, spec_entry *,
 tree outer, unsigned);
 extern tree add_to_template_args   (tree, tree);
 extern tree add_outermost_template_args(tree, tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d52db76f59f..53104753737 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2305,11 +2305,7 @@ private:
 DB_HIDDEN_BIT, /* A hidden binding.  */
 /* The following bits are not independent, but 

[gcc r14-9372] c++/modules: inline namespace abi_tag streaming [PR110730]

2024-03-07 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:0552560f6d2eaa1ae6df5c80660b489de1d5c772

commit r14-9372-g0552560f6d2eaa1ae6df5c80660b489de1d5c772
Author: Patrick Palka 
Date:   Thu Mar 7 16:23:22 2024 -0500

c++/modules: inline namespace abi_tag streaming [PR110730]

The unreduced testcase from PR110730 crashes at runtime ultimately
because we don't stream the abi_tag attribute on inline namespaces and
so the filesystem::current_path() call resolves to the non-C++11 ABI
version even though the C++11 ABI is active, leading to a crash when
destroying the path temporary (which contains an std::string member).
Similar story for the PR105512 testcase.

While we do stream the DECL_ATTRIBUTES of all decls that go through
the generic tree streaming routines, it seems namespaces are streamed
separately from other decls and we don't use the generic routines for
them.  So this patch makes us stream the abi_tag manually for (inline)
namespaces.

PR c++/110730
PR c++/105512

gcc/cp/ChangeLog:

* module.cc (module_state::write_namespaces): Stream the
abi_tag attribute of an inline namespace.
(module_state::read_namespaces): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/modules/hello-2_a.C: New test.
* g++.dg/modules/hello-2_b.C: New test.
* g++.dg/modules/namespace-6_a.H: New test.
* g++.dg/modules/namespace-6_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc | 28 
 gcc/testsuite/g++.dg/modules/hello-2_a.C | 11 +++
 gcc/testsuite/g++.dg/modules/hello-2_b.C | 10 ++
 gcc/testsuite/g++.dg/modules/namespace-6_a.H | 10 ++
 gcc/testsuite/g++.dg/modules/namespace-6_b.C |  7 +++
 5 files changed, 66 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f7e8b357fc2..d52db76f59f 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -15276,6 +15276,19 @@ module_state::write_namespaces (elf_out *to, 
vec spaces,
 
   sec.u (flags);
   write_location (sec, DECL_SOURCE_LOCATION (ns));
+
+  if (DECL_NAMESPACE_INLINE_P (ns))
+   {
+ if (tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (ns)))
+   {
+ tree tags = TREE_VALUE (attr);
+ sec.u (list_length (tags));
+ for (tree tag = tags; tag; tag = TREE_CHAIN (tag))
+   sec.str (TREE_STRING_POINTER (TREE_VALUE (tag)));
+   }
+ else
+   sec.u (0);
+   }
 }
 
   sec.end (to, to->name (MOD_SNAME_PFX ".nms"), crc_p);
@@ -15306,11 +15319,22 @@ module_state::read_namespaces (unsigned num)
   /* See comment in write_namespace about why not bits.  */
   unsigned flags = sec.u ();
   location_t src_loc = read_location (sec);
+  unsigned tags_count = (flags & 2) ? sec.u () : 0;
 
   if (entity_index >= entity_num
  || !parent
  || (flags & 0xc) == 0x8)
sec.set_overrun ();
+
+  tree tags = NULL_TREE;
+  while (tags_count--)
+   {
+ size_t len;
+ const char *str = sec.str ();
+ tags = tree_cons (NULL_TREE, build_string (len + 1, str), tags);
+ tags = nreverse (tags);
+   }
+
   if (sec.get_overrun ())
break;
 
@@ -15342,6 +15366,10 @@ module_state::read_namespaces (unsigned num)
DECL_MODULE_EXPORT_P (inner) = true;
}
 
+  if (tags)
+   DECL_ATTRIBUTES (inner)
+ = tree_cons (get_identifier ("abi_tag"), tags, DECL_ATTRIBUTES 
(inner));
+
   /* Install the namespace.  */
   (*entity_ary)[entity_lwm + entity_index] = inner;
   if (DECL_MODULE_IMPORT_P (inner))
diff --git a/gcc/testsuite/g++.dg/modules/hello-2_a.C 
b/gcc/testsuite/g++.dg/modules/hello-2_a.C
new file mode 100644
index 000..a8f8b813839
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hello-2_a.C
@@ -0,0 +1,11 @@
+// PR c++/105512
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi Hello2 }
+
+module;
+#include 
+export module Hello2;
+
+export std::string tester() {
+  return "hello world\n";
+}
diff --git a/gcc/testsuite/g++.dg/modules/hello-2_b.C 
b/gcc/testsuite/g++.dg/modules/hello-2_b.C
new file mode 100644
index 000..dafd3c2f7a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/hello-2_b.C
@@ -0,0 +1,10 @@
+// PR c++/105512
+// { dg-additional-options -fmodules-ts }
+// { dg-module-do run }
+
+#include 
+import Hello2;
+
+int main() {
+  std::cout << tester();
+}
diff --git a/gcc/testsuite/g++.dg/modules/namespace-6_a.H 
b/gcc/testsuite/g++.dg/modules/namespace-6_a.H
new file mode 100644
index 000..b412cbe6cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/namespace-6_a.H
@@ -0,0 +1,10 @@
+// PR c++/110730
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+namespace std::filesystem {
+  inline namespace 

[gcc r14-9327] c++/modules: befriending template from current class scope

2024-03-05 Thread Patrick Palka via Gcc-cvs
https://gcc.gnu.org/g:b0d11bb02a4a4c7d61e9b53411ccdc54610b1429

commit r14-9327-gb0d11bb02a4a4c7d61e9b53411ccdc54610b1429
Author: Patrick Palka 
Date:   Tue Mar 5 20:36:36 2024 -0500

c++/modules: befriending template from current class scope

Here the TEMPLATE_DECL representing the template friend declaration
naming B has class scope since the template B has class scope, but
get_merge_kind assumes all DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P
TEMPLATE_DECL have namespace scope and wrongly returns MK_named instead
of MK_local_friend for the friend.

gcc/cp/ChangeLog:

* module.cc (trees_out::get_merge_kind) :
Accomodate class-scope DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P
TEMPLATE_DECL.  Consolidate IDENTIFIER_ANON_P cases.

gcc/testsuite/ChangeLog:

* g++.dg/modules/friend-7.h: New test.
* g++.dg/modules/friend-7_a.H: New test.
* g++.dg/modules/friend-7_b.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  | 19 +--
 gcc/testsuite/g++.dg/modules/friend-7.h   |  5 +
 gcc/testsuite/g++.dg/modules/friend-7_a.H |  3 +++
 gcc/testsuite/g++.dg/modules/friend-7_b.C |  6 ++
 4 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 67f132d28d7..80b63a70a62 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -10498,21 +10498,20 @@ trees_out::get_merge_kind (tree decl, depset *dep)
}
}
 
-   if (RECORD_OR_UNION_TYPE_P (ctx))
+   if (TREE_CODE (decl) == TEMPLATE_DECL
+   && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
  {
-   if (IDENTIFIER_ANON_P (DECL_NAME (decl)))
- mk = MK_field;
+   mk = MK_local_friend;
break;
  }
 
-   if (TREE_CODE (decl) == TEMPLATE_DECL
-   && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
- mk = MK_local_friend;
-   else if (IDENTIFIER_ANON_P (DECL_NAME (decl)))
+   if (IDENTIFIER_ANON_P (DECL_NAME (decl)))
  {
-   if (DECL_IMPLICIT_TYPEDEF_P (decl)
-   && UNSCOPED_ENUM_P (TREE_TYPE (decl))
-   && TYPE_VALUES (TREE_TYPE (decl)))
+   if (RECORD_OR_UNION_TYPE_P (ctx))
+ mk = MK_field;
+   else if (DECL_IMPLICIT_TYPEDEF_P (decl)
+&& UNSCOPED_ENUM_P (TREE_TYPE (decl))
+&& TYPE_VALUES (TREE_TYPE (decl)))
  /* Keyed by first enum value, and underlying type.  */
  mk = MK_enum;
else
diff --git a/gcc/testsuite/g++.dg/modules/friend-7.h 
b/gcc/testsuite/g++.dg/modules/friend-7.h
new file mode 100644
index 000..c0f00394f3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-7.h
@@ -0,0 +1,5 @@
+template
+struct A {
+  template struct B { };
+  template friend struct B;
+};
diff --git a/gcc/testsuite/g++.dg/modules/friend-7_a.H 
b/gcc/testsuite/g++.dg/modules/friend-7_a.H
new file mode 100644
index 000..e750e4c7d8d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-7_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+#include "friend-7.h"
diff --git a/gcc/testsuite/g++.dg/modules/friend-7_b.C 
b/gcc/testsuite/g++.dg/modules/friend-7_b.C
new file mode 100644
index 000..eb5e45a3f43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-7_b.C
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodules-ts" }
+#include "friend-7.h"
+import "friend-7_a.H";
+
+A a;
+A::B b;