From 1a09197cb1bc05a71d1866d1220937289da02c5e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 23 Sep 2019 17:37:54 +0000 Subject: [PATCH] PR c++/91844 - Implement CWG 2352, Similar types and reference binding. * call.c (reference_related_p): Use similar_type_p instead of same_type_p. (reference_compatible_p): Update implementation to match CWG 2352. * cp-tree.h (similar_type_p): Declare. * typeck.c (similar_type_p): New. * g++.dg/cpp0x/pr33930.C: Add dg-error. * g++.dg/cpp0x/ref-bind1.C: New test. * g++.dg/cpp0x/ref-bind2.C: New test. * g++.dg/cpp0x/ref-bind3.C: New test. * g++.old-deja/g++.pt/spec35.C: Remove dg-error. From-SVN: r276058 --- gcc/cp/ChangeLog | 9 ++++++ gcc/cp/call.c | 22 +++++++-------- gcc/cp/cp-tree.h | 1 + gcc/cp/typeck.c | 27 ++++++++++++++++++ gcc/testsuite/ChangeLog | 9 ++++++ gcc/testsuite/g++.dg/cpp0x/pr33930.C | 2 +- gcc/testsuite/g++.dg/cpp0x/ref-bind1.C | 44 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind2.C | 15 ++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind3.C | 22 +++++++++++++++ gcc/testsuite/g++.old-deja/g++.pt/spec35.C | 8 +++--- 10 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind3.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4420d8f..7ccc7cd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-09-23 Marek Polacek + + PR c++/91844 - Implement CWG 2352, Similar types and reference binding. + * call.c (reference_related_p): Use similar_type_p instead of + same_type_p. + (reference_compatible_p): Update implementation to match CWG 2352. + * cp-tree.h (similar_type_p): Declare. + * typeck.c (similar_type_p): New. + 2019-09-22 Marek Polacek PR c++/91819 - ICE with operator++ and enum. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 2dad699..28b3f33 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1530,9 +1530,8 @@ reference_related_p (tree t1, tree t2) /* [dcl.init.ref] Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related - to "cv2 T2" if T1 is the same type as T2, or T1 is a base class - of T2. */ - return (same_type_p (t1, t2) + to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */ + return (similar_type_p (t1, t2) || (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2) && DERIVED_FROM_P (t1, t2))); } @@ -1545,14 +1544,15 @@ reference_compatible_p (tree t1, tree t2) /* [dcl.init.ref] "cv1 T1" is reference compatible with "cv2 T2" if - * T1 is reference-related to T2 or - * T2 is "noexcept function" and T1 is "function", where the - function types are otherwise the same, - and cv1 is the same cv-qualification as, or greater cv-qualification - than, cv2. */ - return ((reference_related_p (t1, t2) - || fnptr_conv_p (t1, t2)) - && at_least_as_qualified_p (t1, t2)); + a prvalue of type "pointer to cv2 T2" can be converted to the type + "pointer to cv1 T1" via a standard conversion sequence. */ + tree ptype1 = build_pointer_type (t1); + tree ptype2 = build_pointer_type (t2); + conversion *conv = standard_conversion (ptype1, ptype2, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + if (!conv || conv->bad_p) + return false; + return true; } /* A reference of the indicated TYPE is being bound directly to the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6d217fc..9c0f394 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7361,6 +7361,7 @@ enum { ce_derived, ce_type, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); +extern bool similar_type_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d85e547..f427c4f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1530,6 +1530,33 @@ same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2) return same_type_p (type1, type2); } +/* Returns nonzero iff TYPE1 and TYPE2 are similar, as per [conv.qual]. */ + +bool +similar_type_p (tree type1, tree type2) +{ + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + + /* Informally, two types are similar if, ignoring top-level cv-qualification: + * they are the same type; or + * they are both pointers, and the pointed-to types are similar; or + * they are both pointers to member of the same class, and the types of + the pointed-to members are similar; or + * they are both arrays of the same size or both arrays of unknown bound, + and the array element types are similar. */ + + if (same_type_ignoring_top_level_qualifiers_p (type1, type2)) + return true; + + /* FIXME This ought to handle ARRAY_TYPEs too. */ + if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2)) + || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))) + return comp_ptr_ttypes_const (type1, type2); + + return false; +} + /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ bool diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39fc50b..f381bb2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-09-23 Marek Polacek + + PR c++/91844 - Implement CWG 2352, Similar types and reference binding. + * g++.dg/cpp0x/pr33930.C: Add dg-error. + * g++.dg/cpp0x/ref-bind1.C: New test. + * g++.dg/cpp0x/ref-bind2.C: New test. + * g++.dg/cpp0x/ref-bind3.C: New test. + * g++.old-deja/g++.pt/spec35.C: Remove dg-error. + 2019-09-23 Rainer Orth * gcc.dg/ucnid-5-utf8.c: Skip unless ucn is supported. diff --git a/gcc/testsuite/g++.dg/cpp0x/pr33930.C b/gcc/testsuite/g++.dg/cpp0x/pr33930.C index 8d9312c..ba5b4b9 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr33930.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr33930.C @@ -6,5 +6,5 @@ int& foo( type&& ggg ); void bar( int* someptr ) { - int& x = foo( someptr ); + int& x = foo( someptr ); // { dg-error "cannot bind non-const lvalue reference" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C new file mode 100644 index 0000000..af6140a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C @@ -0,0 +1,44 @@ +// PR c++/91844 - Implement CWG 2352, Similar types and reference binding. +// { dg-do compile { target c++11 } } + +// These should bind directly to ptr, so no -Wreturn-local-addr warnings. +int *ptr; + +const int *const & +fn1 () +{ + return ptr; +} + +int **const ptr2 = nullptr; +const int *const *const & +fn2 () +{ + return ptr2; +} + +int (*ptr3)[10]; +using T = const int (*const)[10]; + +T& +fn3 () +{ + return ptr3; +} + +int (**ptr4)[5] = nullptr; +using T2 = const int (*const *const)[5]; + +T2& +fn4 () +{ + return ptr4; +} + +const int **ptr5 = nullptr; + +const int *const *const & +fn5 () +{ + return ptr5; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C new file mode 100644 index 0000000..967c59e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C @@ -0,0 +1,15 @@ +// PR c++/91844 - Implement CWG 2352, Similar types and reference binding. +// { dg-do compile { target c++11 } } + +// "const int *" and "int *" are reference-related, and 5.4.4. +// says that in that case, if the reference is an rvalue reference, +// the initializer expression shall not be an lvalue. + +int &f (const int *&&); + +void +fn (int *p) +{ + const int *&&r = p; // { dg-error "cannot bind rvalue reference" } + f (p); // { dg-error "cannot bind rvalue reference" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C new file mode 100644 index 0000000..16e1bfe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C @@ -0,0 +1,22 @@ +// 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). */ + +void +g (int *p, const int *q, const int *const r) +{ + f (p); // calls (1) + f (q); // calls (1) + f (r); // calls (1) +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C index 581bb8e..93e953d 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 &); // { dg-message "note" } -template int Bar (T *const &); // { dg-message "note" } candidate -template int Bar (T *); // { dg-message "note" } candidate +template int Bar (T const *const &); +template int Bar (T *const &); +template int Bar (T *); 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); // { dg-error "ambiguous" } + Bar (ptr2); Foo (ptr2); // { dg-error "ambiguous" } Qux (ptr2); // { dg-error "ambiguous" } return 0; -- 2.7.4