aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-07-31 23:08:00 +0200
committerGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-17 13:20:30 -0300
commite4f40984441e7201c373514d00e7d7f76c8487d7 (patch)
treee50d856db44c74bf3ecf077e4f9d2bce0c8c1589 /gcc
parent30bfee107c80e8f096f82119847d9b4463873780 (diff)
downloadgcc-e4f40984441e7201c373514d00e7d7f76c8487d7.zip
gcc-e4f40984441e7201c373514d00e7d7f76c8487d7.tar.gz
gcc-e4f40984441e7201c373514d00e7d7f76c8487d7.tar.bz2
c++: Use error_at rather than warning_at for missing return in constexpr functions [PR96182]
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. 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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/decl.c83
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr63996.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/var-templ44.C1
-rw-r--r--gcc/testsuite/g++.dg/other/error35.C2
6 files changed, 55 insertions, 39 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b4beaa9..a68bbe0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C
new file mode 100644
index 0000000..9c07d71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-96182.C
@@ -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 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C
index cb01854..3357fe3 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C
@@ -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 " }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr63996.C b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
index fe47544..8eee2e0 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr63996.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ44.C b/gcc/testsuite/g++.dg/cpp1y/var-templ44.C
index 2ef01cf..74954ed 100644
--- a/gcc/testsuite/g++.dg/cpp1y/var-templ44.C
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ44.C
@@ -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();
diff --git a/gcc/testsuite/g++.dg/other/error35.C b/gcc/testsuite/g++.dg/other/error35.C
index e9c8371..063bc4a 100644
--- a/gcc/testsuite/g++.dg/other/error35.C
+++ b/gcc/testsuite/g++.dg/other/error35.C
@@ -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 }