On Wed, Jul 29, 2020 at 03:30:07PM -0400, Jason Merrill via Gcc-patches wrote: > On 7/14/20 4:50 AM, Jakub Jelinek wrote: > > For C++11 we already emit an error if a constexpr function doesn't contain > > a return statement, because in C++11 that is the only thing it needs to > > contain, but for C++14 we would normally issue a -Wreturn-type warning. > > > > As mentioned by Jonathan, such constexpr functions are invalid, no > > diagnostics required, because there doesn't exist any arguments for > > which it would result in valid constant expression. > > > > This raises it to an error in such cases. The !LAMBDA_TYPE_P case > > is to avoid error on g++.dg/pr81194.C where the user didn't write > > constexpr anywhere and the operator() is compiler generated. > > We set DECL_DECLARED_CONSTEXPR_P on lambdas earlier in finish_function if > suitable; can we move this diagnostic up before that?
That works too. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk then? 2020-07-31 Jakub Jelinek <ja...@redhat.com> PR c++/96182 * decl.c (finish_function): In constexpr functions use for C++14 and later error instead of warning if no return statement is present and diagnose it regardless of warn_return_type. Move the warn_return_type diagnostics earlier in the function. * g++.dg/cpp1y/constexpr-96182.C: New test. * g++.dg/other/error35.C (S<T>::g()): Add return statement. * g++.dg/cpp1y/pr63996.C (foo): Likewise. * g++.dg/cpp1y/constexpr-return2.C (f): Likewise. * g++.dg/cpp1y/var-templ44.C (make_array): Add throw 1. --- gcc/cp/decl.c.jj 2020-07-29 11:57:23.340517489 +0200 +++ gcc/cp/decl.c 2020-07-30 20:44:33.634951396 +0200 @@ -17112,6 +17112,51 @@ finish_function (bool inline_p) DECL_ATTRIBUTES (fndecl))) omp_declare_variant_finalize (fndecl, attr); + /* Complain if there's just no return statement. */ + if ((warn_return_type + || (cxx_dialect >= cxx14 + && DECL_DECLARED_CONSTEXPR_P (fndecl))) + && !VOID_TYPE_P (TREE_TYPE (fntype)) + && !dependent_type_p (TREE_TYPE (fntype)) + && !current_function_returns_value && !current_function_returns_null + /* Don't complain if we abort or throw. */ + && !current_function_returns_abnormally + /* Don't complain if there's an infinite loop. */ + && !current_function_infinite_loop + /* Don't complain if we are declared noreturn. */ + && !TREE_THIS_VOLATILE (fndecl) + && !DECL_NAME (DECL_RESULT (fndecl)) + && !TREE_NO_WARNING (fndecl) + /* Structor return values (if any) are set by the compiler. */ + && !DECL_CONSTRUCTOR_P (fndecl) + && !DECL_DESTRUCTOR_P (fndecl) + && targetm.warn_func_return (fndecl)) + { + gcc_rich_location richloc (input_location); + /* Potentially add a "return *this;" fix-it hint for + assignment operators. */ + if (IDENTIFIER_ASSIGN_OP_P (DECL_NAME (fndecl))) + { + tree valtype = TREE_TYPE (DECL_RESULT (fndecl)); + if (TREE_CODE (valtype) == REFERENCE_TYPE + && current_class_ref + && same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)) + && global_dc->option_enabled (OPT_Wreturn_type, + global_dc->lang_mask, + global_dc->option_state)) + add_return_star_this_fixit (&richloc, fndecl); + } + if (cxx_dialect >= cxx14 + && DECL_DECLARED_CONSTEXPR_P (fndecl)) + error_at (&richloc, "no return statement in %<constexpr%> function " + "returning non-void"); + else if (warning_at (&richloc, OPT_Wreturn_type, + "no return statement in function returning " + "non-void")) + TREE_NO_WARNING (fndecl) = 1; + } + /* Lambda closure members are implicitly constexpr if possible. */ if (cxx_dialect >= cxx17 && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))) @@ -17163,44 +17208,6 @@ finish_function (bool inline_p) to the FUNCTION_DECL node itself. */ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - /* Complain if there's just no return statement. */ - if (warn_return_type - && !VOID_TYPE_P (TREE_TYPE (fntype)) - && !dependent_type_p (TREE_TYPE (fntype)) - && !current_function_returns_value && !current_function_returns_null - /* Don't complain if we abort or throw. */ - && !current_function_returns_abnormally - /* Don't complain if there's an infinite loop. */ - && !current_function_infinite_loop - /* Don't complain if we are declared noreturn. */ - && !TREE_THIS_VOLATILE (fndecl) - && !DECL_NAME (DECL_RESULT (fndecl)) - && !TREE_NO_WARNING (fndecl) - /* Structor return values (if any) are set by the compiler. */ - && !DECL_CONSTRUCTOR_P (fndecl) - && !DECL_DESTRUCTOR_P (fndecl) - && targetm.warn_func_return (fndecl)) - { - gcc_rich_location richloc (input_location); - /* Potentially add a "return *this;" fix-it hint for - assignment operators. */ - if (IDENTIFIER_ASSIGN_OP_P (DECL_NAME (fndecl))) - { - tree valtype = TREE_TYPE (DECL_RESULT (fndecl)); - if (TREE_CODE (valtype) == REFERENCE_TYPE - && current_class_ref - && same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)) - && global_dc->option_enabled (OPT_Wreturn_type, - global_dc->lang_mask, - global_dc->option_state)) - add_return_star_this_fixit (&richloc, fndecl); - } - if (warning_at (&richloc, OPT_Wreturn_type, - "no return statement in function returning non-void")) - TREE_NO_WARNING (fndecl) = 1; - } - /* Store the end of the function, so that we get good line number info for the epilogue. */ cfun->function_end_locus = input_location; --- gcc/testsuite/g++.dg/other/error35.C.jj 2020-01-12 11:54:37.214401324 +0100 +++ gcc/testsuite/g++.dg/other/error35.C 2020-07-13 22:35:55.359228614 +0200 @@ -9,6 +9,6 @@ template <typename> struct S { enum S<char>::E; template <typename T> enum S<T>::E : int { b }; template <typename T> -constexpr int S<T>::g() const { b; } // { dg-error "not declared" } +constexpr int S<T>::g() const { b; if (false) return 0; } // { dg-error "not declared" } static_assert(S<char>().g() == 1, ""); // { dg-error "" } // { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 } --- gcc/testsuite/g++.dg/cpp1y/pr63996.C.jj 2020-01-12 11:54:37.000000000 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr63996.C 2020-07-13 22:17:39.034004329 +0200 @@ -5,6 +5,7 @@ constexpr int foo (int i) { int a[i] = { }; // { dg-error "7:ISO C\\+\\+ forbids variable length array .a" } + if (i == 23) return 0; } constexpr int j = foo (1); // { dg-error "flows off the end|in .constexpr. expansion of" } --- gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C.jj 2020-07-13 19:16:42.742936492 +0200 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C 2020-07-13 19:16:12.264357640 +0200 @@ -0,0 +1,6 @@ +// PR c++/96182 +// { dg-do compile { target c++11 } } + +constexpr int foo () {} // { dg-error "no return statement in 'constexpr' function returning non-void" "" { target c++14 } } +// { dg-error "body of 'constexpr' function 'constexpr int foo\\\(\\\)' not a return-statement" "" { target c++11_only } .-1 } +// { dg-warning "no return statement in function returning non-void" "" { target c++11_only } .-2 } --- gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C.jj 2020-01-12 11:54:37.115402818 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C 2020-07-13 22:17:03.582513397 +0200 @@ -3,6 +3,7 @@ constexpr int f (int i) { + if (i == -1) return 0; } constexpr int i = f(42); // { dg-error "flows off the end|in .constexpr. expansion of " } --- gcc/testsuite/g++.dg/cpp1y/var-templ44.C.jj 2020-01-12 11:54:37.123402697 +0100 +++ gcc/testsuite/g++.dg/cpp1y/var-templ44.C 2020-07-13 22:35:03.322980157 +0200 @@ -26,5 +26,6 @@ constexpr auto make_array() -> array<conditional_t<is_void_v<_Dest>, common_type_t<>, _Dest>, sizeof...(_Types)> { static_assert(__or_<__not_<is_void<_Dest>>, __and_<>>::value, ""); // { dg-error "static assert" } + throw 1; } auto d = make_array(); Jakub