Message ID | 20210304231914.1202675-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Pointer-to-member fn conversion with noexcept [PR99374] | expand |
On 3/4/21 6:19 PM, Marek Polacek wrote: > The issue in this PR is that we wrongly reject converting pointers to > member function of incomplete types, one of which has noexcept. Recall > that pointers (including pointers to member functions) to non-throwing > functions can be implicitly converted to potentially-throwing functions > (but not vice versa). > > We reject the conversion when called from can_convert_arg_bad because > standard_conversion can't create such a conversion. It comes down to > the DERIVED_FROM_P check in the TYPE_PTRMEMFUNC_P block. It considers > every class derived from itself, but not when the class is incomplete. > But surely we want to reach fnptr_conv_p when tbase is fbase (one of > them could be an alias to the other so use same_type_p instead of ==). > > Another approach would be to not perform DERIVED_FROM_P at all when > either tbase or fbase are incomplete (so perhaps something like at the > end of ptr_reasonably_similar). > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10? > > gcc/cp/ChangeLog: > > PR c++/99374 > * call.c (standard_conversion): When converting pointers to > member, don't return NULL when the bases are equivalent but > incomplete. > > gcc/testsuite/ChangeLog: > > PR c++/99374 > * g++.dg/cpp1z/noexcept-type23.C: New test. > --- > gcc/cp/call.c | 4 +++- > gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C | 14 ++++++++++++++ > 2 files changed, 17 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > index 123f06b1f2b..605cbe15f4e 100644 > --- a/gcc/cp/call.c > +++ b/gcc/cp/call.c > @@ -1449,7 +1449,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, > tree fbase = class_of_this_parm (fromfn); > tree tbase = class_of_this_parm (tofn); > > - if (!DERIVED_FROM_P (fbase, tbase)) > + /* If FBASE and TBASE are equivalent but incomplete, DERIVED_FROM_P > + yields false. But a pointer to member of incomplete class is OK. */ > + if (!DERIVED_FROM_P (fbase, tbase) && !same_type_p (fbase, tbase)) Let's check same_type_p first. OK with that change. > return NULL; > > tree fstat = static_fn_type (fromfn); > diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C > new file mode 100644 > index 00000000000..612dd6ceb5e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C > @@ -0,0 +1,14 @@ > +// PR c++/99374 > +// { dg-do compile { target c++17 } } > + > +struct S; > +struct R; > +using F1 = int (S::*)(); > +using F2 = int (S::*)() noexcept; > +using F3 = int (R::*)() noexcept; > +using T = S; > +using F4 = int (T::*)() noexcept; > +F1 f21 = F2(); > +F1 f41 = F4(); > +F2 f12 = F1(); // { dg-error "cannot convert" } > +F1 f31 = F3(); // { dg-error "cannot convert" } > > base-commit: 0d737ed2171165ba39ab5647f8a94c588fc9a898 >
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 123f06b1f2b..605cbe15f4e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1449,7 +1449,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, tree fbase = class_of_this_parm (fromfn); tree tbase = class_of_this_parm (tofn); - if (!DERIVED_FROM_P (fbase, tbase)) + /* If FBASE and TBASE are equivalent but incomplete, DERIVED_FROM_P + yields false. But a pointer to member of incomplete class is OK. */ + if (!DERIVED_FROM_P (fbase, tbase) && !same_type_p (fbase, tbase)) return NULL; tree fstat = static_fn_type (fromfn); diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C new file mode 100644 index 00000000000..612dd6ceb5e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type23.C @@ -0,0 +1,14 @@ +// PR c++/99374 +// { dg-do compile { target c++17 } } + +struct S; +struct R; +using F1 = int (S::*)(); +using F2 = int (S::*)() noexcept; +using F3 = int (R::*)() noexcept; +using T = S; +using F4 = int (T::*)() noexcept; +F1 f21 = F2(); +F1 f41 = F4(); +F2 f12 = F1(); // { dg-error "cannot convert" } +F1 f31 = F3(); // { dg-error "cannot convert" }