https://gcc.gnu.org/g:ee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2
commit r15-3741-gee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2 Author: Patrick Palka <ppa...@redhat.com> Date: Fri Sep 20 12:33:13 2024 -0400 c++: CWG 2789 and usings [PR116492] After CWG 2789, the "more constrained" tiebreaker for non-template functions should exclude member functions that are defined in different classes. This patch implements this missing refinement. In turn we can get rid of four-parameter version of object_parms_correspond and call the main overload directly since now correspondence is only only checked for members from the same class. PR c++/116492 DR 2789 gcc/cp/ChangeLog: * call.cc (object_parms_correspond): Remove. (cand_parms_match): Return false for member functions that come from different classes. Adjust call to object_parms_correspond. (joust): Update comment for the non-template "more constrained" case. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-memfun4.C: Also compile in C++20 mode. Expect ambiguity when candidates come from different classes. * g++.dg/cpp2a/concepts-inherit-ctor12.C: New test. Reviewed-by: Jason Merrill <ja...@redhat.com> Diff: --- gcc/cp/call.cc | 54 ++++++++-------------- .../g++.dg/cpp2a/concepts-inherit-ctor12.C | 16 +++++++ gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C | 24 +++++----- 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6229dc452636..f2ce50857ece 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -12808,27 +12808,6 @@ class_of_implicit_object (z_candidate *cand) return BINFO_TYPE (cand->conversion_path); } -/* True if candidates C1 and C2 have corresponding object parameters per - [basic.scope.scope]. */ - -static bool -object_parms_correspond (z_candidate *c1, tree fn1, z_candidate *c2, tree fn2) -{ - tree context = class_of_implicit_object (c1); - tree ctx2 = class_of_implicit_object (c2); - if (!ctx2) - /* Leave context as is. */; - else if (!context) - context = ctx2; - else if (context != ctx2) - /* This can't happen for normal function calls, since it means finding - functions in multiple bases which would fail with an ambiguous lookup, - but it can occur with reversed operators. */ - return false; - - return object_parms_correspond (fn1, fn2, context); -} - /* Return whether the first parameter of C1 matches the second parameter of C2. */ @@ -12893,16 +12872,19 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind) tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1)); tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); - if (!(DECL_FUNCTION_MEMBER_P (fn1) - && DECL_FUNCTION_MEMBER_P (fn2))) - /* Early escape. */; - - /* CWG2789 is not adequate, it should specify corresponding object - parameters, not same typed object parameters. */ - else if (!object_parms_correspond (c1, fn1, c2, fn2)) - return false; - else + if (DECL_FUNCTION_MEMBER_P (fn1) + && DECL_FUNCTION_MEMBER_P (fn2)) { + tree base1 = DECL_CONTEXT (strip_inheriting_ctors (fn1)); + tree base2 = DECL_CONTEXT (strip_inheriting_ctors (fn2)); + if (base1 != base2) + return false; + + /* Use object_parms_correspond to simplify comparing iobj/xobj/static + member functions. */ + if (!object_parms_correspond (fn1, fn2, base1)) + return false; + /* We just compared the object parameters, if they don't correspond we already returned false. */ auto skip_parms = [] (tree fn, tree parms) @@ -13269,10 +13251,14 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, return winner; } - /* Concepts: F1 and F2 are non-template functions with the same - parameter-type-lists, and F1 is more constrained than F2 according to the - partial ordering of constraints described in 13.5.4. */ - + /* F1 and F2 are non-template functions and + - they have the same non-object-parameter-type-lists ([dcl.fct]), and + - if they are member functions, both are direct members of the same + class, and + - if both are non-static member functions, they have the same types for + their object parameters, and + - F1 is more constrained than F2 according to the partial ordering of + constraints described in [temp.constr.order]. */ if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn) && !cand1->template_decl && !cand2->template_decl && cand_parms_match (cand1, cand2, pmatch::current)) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C new file mode 100644 index 000000000000..3e5dbfc37ad0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C @@ -0,0 +1,16 @@ +// PR c++/116492 +// CWG 2789 +// { dg-do compile { target c++20 } } + +template<class T> +struct A { + A() requires true = delete; +}; + +struct B : A<int> { + B(); + using A<int>::A; +}; + +B b; // OK, selects the non-inherited constructor over the more constrained + // inherited constructor. diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C index 91e34f1cd7ae..cf7f13c007d1 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C @@ -1,5 +1,7 @@ // PR c++/113191 -// { dg-do compile { target c++23 } } +// CWG 2789 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-Wno-error=c++23-extensions" { target c++20_only } } template<typename> struct S; @@ -8,6 +10,7 @@ struct B { constexpr int f() const requires true { return 5; } constexpr operator int () const requires true { return 5; } constexpr int g(this S<T>&&) requires true { return 5; } + // { dg-warning "explicit object" "" { target c++20_only } .-1 } constexpr int h() requires true { return 5; } }; @@ -20,12 +23,14 @@ struct S : B<> { constexpr operator int () const { return 10; } constexpr int g() { return 10; } constexpr int h(this S&&) { return 10; } + // { dg-warning "explicit object" "" { target c++20_only } .-1 } }; -// implicit object parms match, B::f is more constrained -static_assert(S<>{}.f() == 5); -static_assert(S<>{}.g() == 5); -static_assert(S<>{}.h() == 5); +// ambiguous, constraints aren't considered since the candidates +// come from different classes +static_assert(S<>{}.f() == 5); // { dg-error "ambiguous" } +static_assert(S<>{}.g() == 5); // { dg-error "ambiguous" } +static_assert(S<>{}.h() == 5); // { dg-error "ambiguous" } template <typename = void> struct C { @@ -36,9 +41,8 @@ struct C { template <typename = void> struct S2: B<>, C<> { }; -// implicit object parms for conversion functions are all considered to be from -// the class of the object argument -static_assert(S2<>{} == 5); +// ambiguous as above +static_assert(S2<>{} == 5); // { dg-error "ambiguous" } // ambiguous lookup, so we never actually compare the candidates // if we did, implicit object parms don't match due to different classes @@ -51,7 +55,6 @@ struct S3 : B<> { constexpr int f() volatile { return 10; } }; -// implicit object parms don't match due to different cv-quals static_assert(S3<>{}.f() == 5); // { dg-error "ambiguous" } template <typename = void> @@ -60,8 +63,7 @@ struct S4 : B<> { constexpr int f() const & { return 10; } }; -// no ref-qual matches any ref-qual -static_assert(S4<>{}.f() == 5); +static_assert(S4<>{}.f() == 5); // { dg-error "ambiguous" } template <typename = void> struct C2 {