public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182]
@ 2020-07-14  8:50 Jakub Jelinek
  2020-07-29 19:30 ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Jakub Jelinek @ 2020-07-14  8:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-07-14  Jakub Jelinek  <jakub@redhat.com>

	PR c++/96182
	* decl.c (finish_function): In constexpr functions other than
	lambdas use for C++14 and later error instead of warning if no
	return statement is present and diagnose it regardless of
	warn_return_type.

	* 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-13 19:09:27.258953908 +0200
+++ gcc/cp/decl.c	2020-07-13 22:25:42.437062842 +0200
@@ -17164,7 +17164,10 @@ finish_function (bool inline_p)
   BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
 
   /* Complain if there's just no return statement.  */
-  if (warn_return_type
+  if ((warn_return_type
+       || (cxx_dialect >= cxx14
+	   && DECL_DECLARED_CONSTEXPR_P (fndecl)
+	   && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))))
       && !VOID_TYPE_P (TREE_TYPE (fntype))
       && !dependent_type_p (TREE_TYPE (fntype))
       && !current_function_returns_value && !current_function_returns_null
@@ -17196,8 +17199,14 @@ finish_function (bool inline_p)
 					    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"))
+      if (cxx_dialect >= cxx14
+	  && DECL_DECLARED_CONSTEXPR_P (fndecl)
+	  && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (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;
     }
 
--- 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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182]
  2020-07-14  8:50 [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182] Jakub Jelinek
@ 2020-07-29 19:30 ` Jason Merrill
  2020-07-31  7:52   ` Jakub Jelinek
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2020-07-29 19:30 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 7/14/20 4:50 AM, Jakub Jelinek wrote:
> Hi!
> 
> 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?

> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2020-07-14  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/96182
> 	* decl.c (finish_function): In constexpr functions other than
> 	lambdas use for C++14 and later error instead of warning if no
> 	return statement is present and diagnose it regardless of
> 	warn_return_type.
> 
> 	* 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-13 19:09:27.258953908 +0200
> +++ gcc/cp/decl.c	2020-07-13 22:25:42.437062842 +0200
> @@ -17164,7 +17164,10 @@ finish_function (bool inline_p)
>     BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
>   
>     /* Complain if there's just no return statement.  */
> -  if (warn_return_type
> +  if ((warn_return_type
> +       || (cxx_dialect >= cxx14
> +	   && DECL_DECLARED_CONSTEXPR_P (fndecl)
> +	   && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))))
>         && !VOID_TYPE_P (TREE_TYPE (fntype))
>         && !dependent_type_p (TREE_TYPE (fntype))
>         && !current_function_returns_value && !current_function_returns_null
> @@ -17196,8 +17199,14 @@ finish_function (bool inline_p)
>   					    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"))
> +      if (cxx_dialect >= cxx14
> +	  && DECL_DECLARED_CONSTEXPR_P (fndecl)
> +	  && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (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;
>       }
>   
> --- 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
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182]
  2020-07-29 19:30 ` Jason Merrill
@ 2020-07-31  7:52   ` Jakub Jelinek
  2020-07-31 20:28     ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Jakub Jelinek @ 2020-07-31  7:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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  <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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182]
  2020-07-31  7:52   ` Jakub Jelinek
@ 2020-07-31 20:28     ` Jason Merrill
  0 siblings, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2020-07-31 20:28 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

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
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-07-31 20:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-14  8:50 [PATCH] c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182] Jakub Jelinek
2020-07-29 19:30 ` Jason Merrill
2020-07-31  7:52   ` Jakub Jelinek
2020-07-31 20:28     ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).