Tested x86_64-pc-linux-gnu, applying to trunk. -- 8< --
We represent a reference binding where the referent type is more qualified by a ck_ref_bind around a ck_qual. We performed the ck_qual and then tried to undo it with STRIP_NOPS, but that doesn't work if the conversion is buried in COMPOUND_EXPR. So instead let's avoid performing that fake conversion in the first place. PR c++/114561 PR c++/114562 gcc/cp/ChangeLog: * call.cc (convert_like_internal): Avoid adding qualification conversion in direct reference binding. gcc/testsuite/ChangeLog: * g++.dg/conversion/ref10.C: New test. * g++.dg/conversion/ref11.C: New test. --- gcc/cp/call.cc | 23 +++++++---------- gcc/testsuite/g++.dg/conversion/ref10.C | 5 ++++ gcc/testsuite/g++.dg/conversion/ref11.C | 33 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/conversion/ref10.C create mode 100644 gcc/testsuite/g++.dg/conversion/ref11.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 9e4c8073600..9568b5eb2c4 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -8742,7 +8742,15 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, break; }; - expr = convert_like (next_conversion (convs), expr, fn, argnum, + conversion *nc = next_conversion (convs); + if (convs->kind == ck_ref_bind && nc->kind == ck_qual + && !convs->need_temporary_p) + /* direct_reference_binding might have inserted a ck_qual under + this ck_ref_bind for the benefit of conversion sequence ranking. + Don't actually perform that conversion. */ + nc = next_conversion (nc); + + expr = convert_like (nc, expr, fn, argnum, convs->kind == ck_ref_bind ? issue_conversion_warnings : false, c_cast_p, /*nested_p=*/true, complain & ~tf_no_cleanup); @@ -8820,19 +8828,6 @@ convert_like_internal (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 - && !convs->need_temporary_p) - { - 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/g++.dg/conversion/ref10.C b/gcc/testsuite/g++.dg/conversion/ref10.C new file mode 100644 index 00000000000..1913f733a6b --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref10.C @@ -0,0 +1,5 @@ +// PR c++/114561 + +void create(void* u) { + const void* const& r = ( (void)0, u ); +} diff --git a/gcc/testsuite/g++.dg/conversion/ref11.C b/gcc/testsuite/g++.dg/conversion/ref11.C new file mode 100644 index 00000000000..bb9b835034c --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref11.C @@ -0,0 +1,33 @@ +// PR c++/114562 +// { dg-do compile { target c++11 } } + +template <typename T> +struct Optional { + Optional(T&&); +}; + +struct MyClass { + MyClass(Optional<const void*>); +}; + +// const void* NONE = nullptr; // Correct Error +void* NONE = nullptr; // Crash + +void beforeParam(); + +template<typename T> +struct Create { + template <typename U> static T create(U &&) noexcept; +}; + + +template <typename T> +template<typename U> +T Create<T>::create(U && u) noexcept { + return T( ( (beforeParam()), (u) ) ); // { dg-error "cannot bind rvalue reference" } + // return T( (u) ); // Correct Error +} + +void test_func() { + Create<MyClass>::create(NONE); +} base-commit: 35408b3669fac104cd380582b32e32c64a603d8b -- 2.44.0