if (!compparms (parms1, parms2))
continue;
- if (!equivalently_constrained (fn, method))
+ tree fn_constraints = get_constraints (fn);
+ tree method_constraints = get_constraints (method);
+
+ if (fn_constraints && method_constraints
+ && DECL_CONTEXT (fn) != type
+ && !processing_template_decl)
+ {
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ ++processing_template_decl;
+ if (tree ti = CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (fn)))
+ fn_constraints = tsubst_constraint_info (fn_constraints,
+ TI_ARGS (ti),
+ tf_warning_or_error,
+ fn);
+ if (tree ti = CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (method)))
+ method_constraints = tsubst_constraint_info (method_constraints,
+ TI_ARGS (ti),
+ tf_warning_or_error,
+ method);
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ --processing_template_decl;
+ }
+
+ if (!equivalent_constraints (fn_constraints, method_constraints))
{
if (processing_template_decl)
/* We can't check satisfaction in dependent context, wait until
--- /dev/null
+// PR c++/121351
+// { dg-do compile { target c++20 } }
+
+template<class T> concept C = true;
+
+template<class T>
+struct A {
+ template<class U> void f(U) requires C<T> = delete; // #1
+};
+
+struct B : A<int> {
+ using A::f;
+ template<class U> void f(U) requires C<int>; // #2
+};
+
+int main() {
+ B b;
+ b.f(42); // OK, #2 corresponds to and therefore hides #1
+}
--- /dev/null
+// PR c++/121351
+// { dg-do compile { target c++20 } }
+// A version of concepts-using5a.C where B instead of A is a template.
+
+template<class T> concept C = true;
+
+struct A {
+ template<class U> void f(U) requires C<int> = delete; // #1
+};
+
+template<class T>
+struct B : A {
+ using A::f;
+ template<class U> void f(U) requires C<T>; // #2
+};
+
+int main() {
+ B<int> b;
+ b.f(42); // OK, #2 corresponds to and therefore hides #1
+}