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