https://gcc.gnu.org/g:8d204f2a536f7253e4251aca7bc12af524800b4c
commit r16-1272-g8d204f2a536f7253e4251aca7bc12af524800b4c Author: Jason Merrill <ja...@redhat.com> Date: Fri Jun 6 10:26:28 2025 -0400 c++: recursive template with deduced return [PR120555] Here since r15-4120 we were prematurely complaining about the use of func within its own definiton, which is fine at instantiation time. So don't require this for function templates that are currently being defined. But keep the error for instantiations of templates that are not currently being defined, which we similarly did not diagnose before r15-4120 but other implementations do. Both of these follow the general principle from [temp.res.general]/6 that we only error in a template body if no instatiation could be well-formed. Also remove a redundant call to require_deduced_type. PR c++/120555 gcc/cp/ChangeLog: * decl2.cc (fn_being_defined, fn_template_being_defined): New. (mark_used): Check fn_template_being_defined. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/constexpr-if39.C: New test. Diff: --- gcc/cp/decl2.cc | 33 ++++++++++++++++++++++++++--- gcc/testsuite/g++.dg/cpp1z/constexpr-if39.C | 30 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index e3fbc4093929..2bbc6180b0b9 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -6269,6 +6269,33 @@ mark_single_function (tree expr, tsubst_flags_t complain) return true; } +/* True iff we have started, but not finished, defining FUNCTION_DECL DECL. */ + +bool +fn_being_defined (tree decl) +{ + /* DECL_INITIAL is set to error_mark_node in grokfndecl for a definition, and + changed to BLOCK by poplevel at the end of the function. */ + return (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) == error_mark_node); +} + +/* True if DECL is an instantiation of a function template currently being + defined. */ + +bool +fn_template_being_defined (tree decl) +{ + if (TREE_CODE (decl) != FUNCTION_DECL + || !DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLOID_INSTANTIATION (decl) + || DECL_TEMPLATE_INSTANTIATED (decl)) + return false; + tree tinfo = DECL_TEMPLATE_INFO (decl); + tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); + return fn_being_defined (pattern); +} + /* Mark DECL (either a _DECL or a BASELINK) as "used" in the program. If DECL is a specialization or implicitly declared class member, generate the actual definition. Return false if something goes @@ -6422,6 +6449,9 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) maybe_instantiate_decl (decl); if (!decl_dependent_p (decl) + /* Don't require this yet for an instantiation of a function template + we're currently defining (c++/120555). */ + && !fn_template_being_defined (decl) && !require_deduced_type (decl, complain)) return false; @@ -6436,9 +6466,6 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) && uses_template_parms (DECL_TI_ARGS (decl))) return true; - if (!require_deduced_type (decl, complain)) - return false; - if (builtin_pack_fn_p (decl)) { error ("use of built-in parameter pack %qD outside of a template", diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if39.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if39.C new file mode 100644 index 000000000000..38ae7a0c0e10 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if39.C @@ -0,0 +1,30 @@ +// PR c++/120555 +// { dg-do compile { target c++17 } } + +struct A { int m; }; + +template<class T> +constexpr auto f() { + if constexpr (sizeof(T) == sizeof(int)) + return 1; + else + return A{f<int>()}; +} + +static_assert(f<bool>().m == 1); +static_assert(f<int>() == 1); + +template <class T> constexpr auto g(); + +template<class T> +constexpr auto f2() { + if constexpr (sizeof(T) == sizeof(int)) + return 1; + else + return A{g<int>()}; // { dg-error "auto" } +} + +template <class T> constexpr auto g() { return A{1}; } + +static_assert(f2<bool>().m == 1); +static_assert(f2<int>() == 1);