On 4/12/22 18:50, Marek Polacek wrote:
DR 2352 changed the definitions of reference-related (so that it uses "similar type" instead of "same type") and of reference-compatible (use a standard conversion sequence). That means that reference-related is now more broad, which means that we will be binding more things directly.The original patch for DR 2352 caused some problems, which were fixed in r276251 by creating a "fake" ck_qual in direct_reference_binding, so that in void f(int *); // #1 void f(const int * const &); // #2 int *x; int main() { f(x); // call #1 } we call #1. The extra ck_qual in #2 causes compare_ics to select #1, which is a better match for "int *" because then we don't have to do a qualification conversion. Let's turn to the problem in this PR. We have void f(const int * const &); // #1 void f(const int *); // #2 int *x; int main() { f(x); } We arrive in compare_ics to decide which one is better. The ICS for #1 looks like ck_ref_bind <- ck_qual <- ck_identity const int *const & const int *const int * and the ICS for #2 is ck_qual <- ck_rvalue <- ck_identity const int * int * int * We strip the reference and then comp_cv_qual_signature when comparing two ck_quals sees that "const int *" is a proper subset of "const int *const" and we return -1. But that's wrong; presumably the top-level "const" should be ignored and the call should be ambiguous. This patch adjust the type of the "fake" ck_qual so that this problem doesn't arise. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/11?
OK, thanks.
PR c++/97296 gcc/cp/ChangeLog: * call.cc (direct_reference_binding): strip_top_quals when creating a ck_qual. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/ref-bind4.C: Add dg-error. * g++.dg/cpp0x/ref-bind8.C: New test. --- gcc/cp/call.cc | 15 +++++++++++++-- gcc/testsuite/g++.dg/cpp0x/ref-bind4.C | 2 +- gcc/testsuite/g++.dg/cpp0x/ref-bind8.C | 10 ++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind8.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 3a8d7e4b131..fc2fc009f14 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -1680,8 +1680,19 @@ direct_reference_binding (tree type, conversion *conv) because the types "int *" and "const int *const" are reference-related and we were binding both directly and they had the same rank. To break it up, we add a ck_qual under the - ck_ref_bind so that conversion sequence ranking chooses #1. */ - conv = build_conv (ck_qual, t, conv); + ck_ref_bind so that conversion sequence ranking chooses #1. + + We strip_top_quals here which is also what standard_conversion + does. Failure to do so would confuse comp_cv_qual_signature + into thinking that in + + void f(const int * const &); // #1 + void f(const int *); // #2 + int *x; + f(x); + + #2 is a better match than #1 even thought they're ambiguous (97296). */ + conv = build_conv (ck_qual, strip_top_quals (t), conv);return build_conv (ck_ref_bind, type, conv);} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C index 85ac9fbfd79..d296d7c3b72 100644 --- a/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C @@ -51,6 +51,6 @@ g (int *p, const int *pc, const int **q) similar types T1 and T2 (_conv.qual_), respectively, and the cv- qualification signature of type T1 is a proper subset of the cv- qualification signature of type T2 */ - f8 (q); + f8 (q); // { dg-error "call of overloaded" } f9 (q); } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind8.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind8.C new file mode 100644 index 00000000000..eee78fd5e74 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind8.C @@ -0,0 +1,10 @@ +// PR c++/97296 +// { dg-do compile } + +void f(const int * const &); +void f(const int *); +int *x; +int main() +{ + f(x); // { dg-error "call of overloaded" } +} base-commit: 3c742621ed28540cf42d4cfbc2bf03433cd26738
