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