From: Patrick Palka Date: Sun, 7 May 2023 14:24:49 +0000 (-0400) Subject: c++: potentiality of templated memfn call [PR109480] X-Git-Tag: basepoints/gcc-15~9583 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f4840ddef9746ab591c78ecdd750e3b18aa1ce6;p=thirdparty%2Fgcc.git c++: potentiality of templated memfn call [PR109480] Here we're incorrectly deeming the templated call a.g() inside b's initializer as potentially constant, despite g being non-constexpr, which leads to us needlessly instantiating the initializer ahead of time and which subsequently triggers a bug in access checking deferral (to be fixed by the follow-up patch). This patch fixes this by calling get_fns earlier during CALL_EXPR potentiality checking so that when we extract a FUNCTION_DECL out of a templated member function call (whose overall callee is typically a COMPONENT_REF) we do the usual constexpr-eligibility checking for it. In passing, I noticed the nearby special handling of the object argument of a non-static member function call is effectively the same as the generic argument handling a few lines below. So this patch just gets rid of this special handling; otherwise we'd have to adapt it to handle templated versions of such calls. PR c++/109480 gcc/cp/ChangeLog: * constexpr.cc (potential_constant_expression_1) : Reorganize to call get_fns sooner. Remove special handling of the object argument of a non-static member function call. Remove dead store to 'fun'. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the expected "without object" diagnostic isn't replaced by a "call to non-constexpr function" diagnostic. * g++.dg/template/non-dependent25.C: New test. --- diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 70dd6cf4d904..987a536d515c 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -9135,6 +9135,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, if (fun && is_overloaded_fn (fun)) { + if (!RECUR (fun, true)) + return false; + fun = get_fns (fun); + if (TREE_CODE (fun) == FUNCTION_DECL) { if (builtin_valid_in_constant_expr_p (fun)) @@ -9165,36 +9169,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, explain_invalid_constexpr_fn (fun); return false; } - /* A call to a non-static member function takes the address - of the object as the first argument. But in a constant - expression the address will be folded away, so look - through it now. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) - && !DECL_CONSTRUCTOR_P (fun)) - { - tree x = get_nth_callarg (t, 0); - if (is_this_parameter (x)) - return true; - /* Don't require an immediately constant value, as - constexpr substitution might not use the value. */ - bool sub_now = false; - if (!potential_constant_expression_1 (x, rval, strict, - sub_now, fundef_p, - flags, jump_target)) - return false; - i = 1; - } - } - else - { - if (!RECUR (fun, true)) - return false; - fun = get_first_fn (fun); } + + fun = OVL_FIRST (fun); /* Skip initial arguments to base constructors. */ if (DECL_BASE_CONSTRUCTOR_P (fun)) i = num_artificial_parms_for (fun); - fun = DECL_ORIGIN (fun); } else if (fun) { diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C index c752601ba09e..1dc826d3111a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C @@ -3,7 +3,7 @@ template class A { - void e (); + constexpr bool e () { return true; }; bool f (int() noexcept(this->e())); // { dg-error "this" } bool g (int() noexcept(e())); // { dg-error "without object" } }; diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C b/gcc/testsuite/g++.dg/template/non-dependent25.C new file mode 100644 index 000000000000..c00e44532b06 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C @@ -0,0 +1,14 @@ +// PR c++/109480 + +template +struct A { + void f() { + A a; + const bool b = a.g(); // { dg-bogus "private" } + } + +private: + bool g() const; +}; + +template struct A;