From: Marek Polacek Date: Sat, 28 Sep 2019 15:35:37 +0000 (+0000) Subject: PR c++/91889 - follow-up fix for DR 2352. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=406c9a1173f79dc0fb3231edb51690c1dd73f6a0;p=gcc.git PR c++/91889 - follow-up fix for DR 2352. * call.c (involves_qualification_conversion_p): New function. (direct_reference_binding): Build a ck_qual if the conversion would involve a qualification conversion. (convert_like_real): Strip the conversion created by the ck_qual in direct_reference_binding. * g++.dg/cpp0x/ref-bind3.C: Add dg-error. * g++.dg/cpp0x/ref-bind4.C: New test. * g++.dg/cpp0x/ref-bind5.C: New test. * g++.dg/cpp0x/ref-bind6.C: New test. * g++.old-deja/g++.pt/spec35.C: Revert earlier change. From-SVN: r276251 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c30d704aa4f..a1e520a5137 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2019-09-28 Marek Polacek + PR c++/91889 - follow-up fix for DR 2352. + * call.c (involves_qualification_conversion_p): New function. + (direct_reference_binding): Build a ck_qual if the conversion + would involve a qualification conversion. + (convert_like_real): Strip the conversion created by the ck_qual + in direct_reference_binding. + PR c++/91921 - stray warning with -Woverloaded-virtual. * class.c (warn_hidden): Only emit the second part of -Woverloaded-virtual if the first part was issued. Use inform instead diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5ccf3b89682..56dcbd391c1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1555,6 +1555,27 @@ reference_compatible_p (tree t1, tree t2) return true; } +/* Return true if converting FROM to TO would involve a qualification + conversion. */ + +static bool +involves_qualification_conversion_p (tree to, tree from) +{ + /* If we're not convering a pointer to another one, we won't get + a qualification conversion. */ + if (!((TYPE_PTR_P (to) && TYPE_PTR_P (from)) + || (TYPE_PTRDATAMEM_P (to) && TYPE_PTRDATAMEM_P (from)))) + return false; + + conversion *conv = standard_conversion (to, from, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + for (conversion *t = conv; t; t = next_conversion (t)) + if (t->kind == ck_qual) + return true; + + return false; +} + /* A reference of the indicated TYPE is being bound directly to the expression represented by the implicit conversion sequence CONV. Return a conversion sequence for this binding. */ @@ -1598,6 +1619,19 @@ direct_reference_binding (tree type, conversion *conv) That way, convert_like knows not to generate a temporary. */ conv->need_temporary_p = false; } + else if (involves_qualification_conversion_p (t, conv->type)) + /* Represent the qualification conversion. After DR 2352 + #1 and #2 were indistinguishable conversion sequences: + + void f(int*); // #1 + void f(const int* const &); // #2 + void g(int* p) { f(p); } + + 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); return build_conv (ck_ref_bind, type, conv); } @@ -7342,6 +7376,18 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, { tree ref_type = totype; + /* direct_reference_binding might have inserted a ck_qual under + this ck_ref_bind for the benefit of conversion sequence ranking. + Ignore the conversion; we'll create our own below. */ + if (next_conversion (convs)->kind == ck_qual) + { + gcc_assert (same_type_p (TREE_TYPE (expr), + next_conversion (convs)->type)); + /* Strip the cast created by the ck_qual; cp_build_addr_expr + below expects an lvalue. */ + STRIP_NOPS (expr); + } + if (convs->bad_p && !next_conversion (convs)->bad_p) { tree extype = TREE_TYPE (expr); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 104a83be28a..ecdce9b304f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2019-09-28 Marek Polacek + PR c++/91889 - follow-up fix for DR 2352. + * g++.dg/cpp0x/ref-bind3.C: Add dg-error. + * g++.dg/cpp0x/ref-bind4.C: New test. + * g++.dg/cpp0x/ref-bind5.C: New test. + * g++.dg/cpp0x/ref-bind6.C: New test. + * g++.old-deja/g++.pt/spec35.C: Revert earlier change. + PR c++/91921 - stray warning with -Woverloaded-virtual. * g++.dg/warn/Woverloaded-2.C: New. * g++.dg/warn/Woverloaded-2.h: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C index 16e1bfe6ccc..b2c85ec684a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C @@ -1,22 +1,18 @@ // PR c++/91844 - Implement CWG 2352, Similar types and reference binding. // { dg-do compile { target c++11 } } -template int f (const T *const &); // (1) -template int f (T *const &); // (2) -template int f (T *); // (3) - -/* Before CWG 2352, (2) was a better match than (1), but (2) and (3) were - equally good, so there was an ambiguity. (2) was better than (1) because - (1) required a qualification conversion whereas (2) didn't. But with this - CWG, (1) no longer requires a qualification conversion, because the types - "const int* const" and "int *" are now considered reference-related and we - bind directly, and (1) is more specialized than (2). And (1) is also a - better match than (3). */ +template int f (const T *const &); // 1 +template int f (T *const &); // 2 +template int f (T *); // 3 +/* There's an ambiguity: (2) is a better match than (1) because + (1) requires a qualification conversion whereas (2) doesn't, but + (2) and (3) are indistinguishable conversion sequences. */ + void g (int *p, const int *q, const int *const r) { - f (p); // calls (1) - f (q); // calls (1) - f (r); // calls (1) + f (p); // { dg-error "call of overloaded" } + f (q); + f (r); } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C new file mode 100644 index 00000000000..85ac9fbfd79 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C @@ -0,0 +1,56 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +int i; + +void f1 (int *); +void f1 (const int *const &); + +void f2 (int *); +void f2 (const int *&); + +void f3 (const int *); +void f3 (int *const &); + +void f4 (int *&); +void f4 (int *const &); + +void f5 (const int *&); +void f5 (int *const &); + +void f6 (int *const &); +void f6 (const int *const &); + +void f7 (int **const); +void f7 (const int *const *const &); + +void f8 (const int *const *); +void f8 (const int *const *const &); + +void f9 (int *const *); +void f9 (const int *const *const &); + +void +g (int *p, const int *pc, const int **q) +{ + f1 (p); + f1 (pc); + f2 (p); + f2 (pc); + f3 (p); + f3 (pc); + f4 (p); + f5 (p); + f5 (pc); + f6 (p); + f6 (pc); + f7 (q); + /* [over.ics.rank] + + --S1 and S2 differ only in their qualification conversion and yield + 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); + f9 (q); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C new file mode 100644 index 00000000000..d528b87761d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C @@ -0,0 +1,17 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +template struct A { typedef U *type; }; +struct B { + typedef A::type node_ptr; +}; +struct C { + typedef B::node_ptr node_ptr; + typedef A::type const_node_ptr; +}; +struct { + void to_value_ptr(C::node_ptr) {}; + void to_value_ptr(const C::const_node_ptr &); +} b; +C::node_ptr a; +void fn1() { b.to_value_ptr(a); } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C new file mode 100644 index 00000000000..c85a5cfb36f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C @@ -0,0 +1,12 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +template struct A { + A(const T &); +}; + +struct { + int *m; +} a; + +void fn1() { A(a.m); } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C index 93e953df7e7..1debf915fe9 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C @@ -14,9 +14,9 @@ template int Foo (T &); // { dg-message "note" } candidate template int Qux (T); // { dg-message "note" } template int Qux (T const &); // { dg-message "note" } candidate -template int Bar (T const *const &); -template int Bar (T *const &); -template int Bar (T *); +template int Bar (T const *const &); // { dg-message "note" } +template int Bar (T *const &); // { dg-message "note" } candidate +template int Bar (T *); // { dg-message "note" } candidate template int Baz (T *const &); // { dg-message "note" } template int Baz (T *); // { dg-message "note" } candidate @@ -24,7 +24,7 @@ template int Baz (T *); // { dg-message "note" } candi int Baz (int const *ptr, int *ptr2) { Baz (ptr2); // { dg-error "ambiguous" } - Bar (ptr2); + Bar (ptr2); // { dg-error "ambiguous" } Foo (ptr2); // { dg-error "ambiguous" } Qux (ptr2); // { dg-error "ambiguous" } return 0;