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

Reply via email to