Here when instantiating a constrained template friend naming an already declared class template, we erroneously pass the existing template's constraints instead of the friend declaration's constraints to redeclare_class_template, which causes the constraint comparison check therein to always be vacuously true, and we fail to diagnose legitimate constraint mismatches.
Bootstrapped and regtested on x86_64-pc-linxu-gnu, does this look OK for trunk/12? PR c++/96830 gcc/cp/ChangeLog: * pt.cc (redeclare_class_template): Add missing "of" in constraint mismatch diagnostic. (tsubst_friend_class): For an already declared class template, substitute and pass the friend declaration's constraints to redeclare_class_template instead of passing the existing template's constraints. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-friend14.C: New test. --- gcc/cp/pt.cc | 8 ++++-- .../g++.dg/cpp2a/concepts-friend14.C | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend14.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 85136df1730..053cc52b285 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6377,7 +6377,7 @@ redeclare_class_template (tree type, tree parms, tree cons) if (!cp_tree_equal (req1, req2)) { auto_diagnostic_group d; - error_at (input_location, "redeclaration %q#D with different " + error_at (input_location, "redeclaration of %q#D with different " "constraints", tmpl); inform (DECL_SOURCE_LOCATION (tmpl), "original declaration appeared here"); @@ -11503,7 +11503,11 @@ tsubst_friend_class (tree friend_tmpl, tree args) tf_warning_or_error); location_t saved_input_location = input_location; input_location = DECL_SOURCE_LOCATION (friend_tmpl); - tree cons = get_constraints (tmpl); + tree cons = get_constraints (friend_tmpl); + ++processing_template_decl; + cons = tsubst_constraint_info (cons, args, tf_warning_or_error, + DECL_FRIEND_CONTEXT (friend_tmpl)); + --processing_template_decl; redeclare_class_template (TREE_TYPE (tmpl), parms, cons); input_location = saved_input_location; } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend14.C new file mode 100644 index 00000000000..f46c7e4bdfb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend14.C @@ -0,0 +1,26 @@ +// PR c++/96830 +// { dg-do compile { target c++20 } } + +template<class T> requires true +struct A { + template<class U> friend struct A; // { dg-error "different constraints" } + template<class U> requires (!!true) friend struct A; // { dg-error "different constraints" } +}; + +template<class T> +struct B { + template<class U> requires true friend struct A; + template<class U> requires true friend struct B; // { dg-error "different constraints" } +}; + +template<class T> concept C = true; + +template<C T> +struct D { + template<class U> friend struct D; // { dg-error "different constraints" } + template<C U> friend struct D; +}; + +template struct A<int>; +template struct B<int>; +template struct D<int>; -- 2.40.0