[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-patches
Subject: Re: [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96
From: Jason Merrill via Gcc-patches <gcc-patches () gcc ! gnu ! org>
Date: 2020-07-31 20:28:40
Message-ID: ee488ea1-8f47-c453-579b-c2d6cc564cfa () redhat ! com
[Download RAW message or body]
On 7/31/20 3:52 AM, Jakub Jelinek wrote:
> 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?
OK.
> 2020-07-31 Jakub Jelinek <jakub@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
>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic