original declaration. */
if (tree orig_ci = get_constraints (decl))
{
+ if (int extra_levels = (TMPL_PARMS_DEPTH (current_template_parms)
+ - TMPL_ARGS_DEPTH (TYPE_TI_ARGS (type))))
+ {
+ /* If there is a discrepancy between the current template depth
+ and the template depth of the original declaration, then we
+ must be redeclaring a class template as part of a friend
+ declaration within another class template. Before matching
+ constraints, we need to reduce the template parameter level
+ within the current constraints via substitution. */
+ tree outer_gtargs = template_parms_to_args (current_template_parms);
+ TREE_VEC_LENGTH (outer_gtargs) = extra_levels;
+ ci = tsubst_constraint_info (ci, outer_gtargs, tf_none, NULL_TREE);
+ }
if (!equivalent_constraints (ci, orig_ci))
{
error ("%qT does not match original declaration", type);
DECL_ANTICIPATED (tmpl)
= DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (tmpl)) = true;
+ /* Substitute into and set the constraints on the new declaration. */
+ if (tree ci = get_constraints (friend_tmpl))
+ {
+ ++processing_template_decl;
+ ci = tsubst_constraint_info (ci, args, tf_warning_or_error,
+ DECL_FRIEND_CONTEXT (friend_tmpl));
+ --processing_template_decl;
+ set_constraints (tmpl, ci);
+ }
+
/* Inject this template into the enclosing namspace scope. */
tmpl = pushdecl_namespace_level (tmpl, true);
}
--- /dev/null
+// PR c++/93467
+// { dg-do compile { target c++20 } }
+
+template<bool B> requires B
+ class C;
+
+template<typename>
+class S1
+{
+ template<bool B> requires B
+ friend class ::C;
+};
+
+template<typename>
+class S2
+{
+ template<bool B> requires (!B)
+ friend class ::C; // { dg-error "does not match original declaration" }
+};
--- /dev/null
+// PR c++/93467
+// { dg-do compile { target c++20 } }
+
+template<typename T> concept True = true;
+
+template<typename U>
+struct S1 {
+ template<True T> friend struct S2; // friend declaration for S2
+};
+
+S1<int> s; // instantiate S1
+
+template<True T> struct S2; // another declaration for S2
+
+template<typename U>
+struct S3 {
+ template<True T> friend struct ::S2; // a third declaration for S2
+};