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 wastefully instantiating the initializer ahead of time and triggering a bug in access checking deferral (which will get fixed in the subsequent patch).
This patch fixes this by calling get_fns earlier during potentiality checking so that we also handle the templated form of a member function call (whose overall callee is a COMPONENT_REF) when checking if the called function is constexpr etc. PR c++/109480 gcc/cp/ChangeLog: * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>: Reorganize to call get_fns sooner. 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. --- gcc/cp/constexpr.cc | 16 ++++++++-------- gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +- gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index d1097764b10..29d872d0a5e 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -9132,6 +9132,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)) @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, expression the address will be folded away, so look through it now. */ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) - && !DECL_CONSTRUCTOR_P (fun)) + && !DECL_CONSTRUCTOR_P (fun) + && !processing_template_decl) { tree x = get_nth_callarg (t, 0); if (is_this_parameter (x)) @@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, 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 c752601ba09..1dc826d3111 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C @@ -3,7 +3,7 @@ template <class ...Ts> 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 00000000000..a2f9801e11f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C @@ -0,0 +1,14 @@ +// PR c++/109480 + +template<class T> +struct A { + void f() { + A<int> a; + const bool b = a.g(); + } + +private: + bool g() const; +}; + +template struct A<int>; -- 2.40.1.459.g48d89b51b3