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  <ja...@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

Reply via email to