c++: constrained template friend class matching [PR96830]
authorPatrick Palka <ppalka@redhat.com>
Tue, 14 Mar 2023 23:12:08 +0000 (19:12 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 14 Mar 2023 23:12:08 +0000 (19:12 -0400)
When instantiating a constrained template friend naming an already
declared class template, tsubst_friend_class erroneously passes to
redeclare_class_template the existing template's constraints instead of
those of the friend declaration, which causes the constraint comparison
check therein to trivially succeed and we fail to diagnose legitimate
constraint mismatches.

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
gcc/testsuite/g++.dg/cpp2a/concepts-friend14.C [new file with mode: 0644]

index c53d8e2..eb153ad 100644 (file)
@@ -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");
@@ -11564,7 +11564,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 (file)
index 0000000..f46c7e4
--- /dev/null
@@ -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>;