* 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
2019-09-28 Marek Polacek <polacek@redhat.com>
+ 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
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. */
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);
}
{
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);
2019-09-28 Marek Polacek <polacek@redhat.com>
+ 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.
// PR c++/91844 - Implement CWG 2352, Similar types and reference binding.
// { dg-do compile { target c++11 } }
-template<typename T> int f (const T *const &); // (1)
-template<typename T> int f (T *const &); // (2)
-template<typename T> 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<typename T> int f (const T *const &); // 1
+template<typename T> int f (T *const &); // 2
+template<typename T> 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);
}
--- /dev/null
+// 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);
+}
--- /dev/null
+// PR c++/91889 - follow-up fix for DR 2352.
+// { dg-do compile { target c++11 } }
+
+template <typename U> struct A { typedef U *type; };
+struct B {
+ typedef A<B>::type node_ptr;
+};
+struct C {
+ typedef B::node_ptr node_ptr;
+ typedef A<const B>::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); }
--- /dev/null
+// PR c++/91889 - follow-up fix for DR 2352.
+// { dg-do compile { target c++11 } }
+
+template <typename T> struct A {
+ A(const T &);
+};
+
+struct {
+ int *m;
+} a;
+
+void fn1() { A<const int *>(a.m); }
template <typename T> int Qux (T); // { dg-message "note" }
template <typename T> int Qux (T const &); // { dg-message "note" } candidate
-template <typename T> int Bar (T const *const &);
-template <typename T> int Bar (T *const &);
-template <typename T> int Bar (T *);
+template <typename T> int Bar (T const *const &); // { dg-message "note" }
+template <typename T> int Bar (T *const &); // { dg-message "note" } candidate
+template <typename T> int Bar (T *); // { dg-message "note" } candidate
template <typename T> int Baz (T *const &); // { dg-message "note" }
template <typename T> int Baz (T *); // { dg-message "note" } candidate
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;