if (DECL_UNIQUE_FRIEND_P (decl) && DECL_TEMPLATE_INFO (decl))
{
tree tmpl = DECL_TI_TEMPLATE (decl);
- tree gargs = generic_targs_for (tmpl);
+ tree outer_args = outer_template_args (tmpl);
processing_template_decl_sentinel s;
- if (uses_template_parms (gargs))
+ if (PRIMARY_TEMPLATE_P (tmpl)
+ || uses_template_parms (outer_args))
++processing_template_decl;
- reqs = tsubst_constraint (reqs, gargs,
+ reqs = tsubst_constraint (reqs, outer_args,
tf_warning_or_error, NULL_TREE);
}
return reqs;
extern tree template_parms_to_args (tree);
extern tree template_parms_level_to_args (tree);
extern tree generic_targs_for (tree);
+extern tree outer_template_args (tree);
/* in expr.cc */
extern tree cplus_expand_constant (tree);
return template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl));
}
+/* Return the template arguments corresponding to the template parameters of
+ TMPL's enclosing scope. When TMPL is a member of a partial specialization,
+ this returns the arguments for the partial specialization as opposed to those
+ for the primary template, which is the main difference between this function
+ and simply using e.g. the TYPE_TI_ARGS of TMPL's DECL_CONTEXT. */
+
+tree
+outer_template_args (tree tmpl)
+{
+ tree ti = get_template_info (DECL_TEMPLATE_RESULT (tmpl));
+ if (!ti)
+ return NULL_TREE;
+ tree args = TI_ARGS (ti);
+ if (!PRIMARY_TEMPLATE_P (tmpl))
+ return args;
+ if (TMPL_ARGS_DEPTH (args) == 1)
+ return NULL_TREE;
+ args = copy_node (args);
+ --TREE_VEC_LENGTH (args);
+ return args;
+}
+
/* Update the declared TYPE by doing any lookups which were thought to be
dependent, but are not now that we know the SCOPE of the declarator. */
static tree
ctor_deduction_guides_for (tree tmpl, tsubst_flags_t complain)
{
- tree type = TREE_TYPE (tmpl);
- tree outer_args = NULL_TREE;
- if (DECL_CLASS_SCOPE_P (tmpl)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (DECL_CONTEXT (tmpl)))
- {
- outer_args = copy_node (CLASSTYPE_TI_ARGS (type));
- gcc_assert (TMPL_ARGS_DEPTH (outer_args) > 1);
- --TREE_VEC_LENGTH (outer_args);
- type = TREE_TYPE (most_general_template (tmpl));
- }
+ tree outer_args = outer_template_args (tmpl);
+ tree type = TREE_TYPE (most_general_template (tmpl));
tree cands = NULL_TREE;
--- /dev/null
+// PR c++/107853
+// { dg-do compile { target c++20 } }
+
+template<class T, class U>
+concept C = __is_same(T, U);
+
+template<class... Ts>
+struct A {
+ template<class... Us>
+ requires (C<Ts, Us> && ...)
+ friend void f(A, A<Us...>) { }
+};
+
+int main() {
+ A<int> x;
+ f(x, x);
+ A<int, int> y;
+ f(y, y);
+ A<char> z;
+ f(x, z); // { dg-error "no match" }
+}
--- /dev/null
+// Verify we substitute the correct outer template arguments
+// when instantiating a constrained template friend declared
+// inside a partial specialization.
+// { dg-do compile { target c++20 } }
+
+template<class U>
+ requires __is_same(int*, U)
+void f() { };
+
+template<class T>
+struct A;
+
+template<class T>
+struct A<T*> {
+ template<class U>
+ requires __is_same(T, U)
+ friend void f() { } // { dg-bogus "redefinition" }
+};
+
+template struct A<int*>;