Tested x86_64-pc-linux-gnu, applying to trunk.
-- 8< --
If we already gave an error while parsing a function, we don't also need to
try to explain what's wrong with it when we later try to use it in a
constant-expression. In the new testcase explain_invalid_constexpr_fn
couldn't find anything still in the function to complain about, so it said
because: followed by nothing.
We still try to constant-evaluate it to reduce error cascades, but we
shouldn't complain if it doesn't work very well.
This flag is similar to CLASSTYPE_ERRONEOUS that I added a while back.
PR c++/113360
gcc/cp/ChangeLog:
* cp-tree.h (struct language_function): Add erroneous bit.
* constexpr.cc (explain_invalid_constexpr_fn): Return if set.
(cxx_eval_call_expression): Quiet if set.
* parser.cc (cp_parser_function_definition_after_declarator)
* pt.cc (instantiate_body): Set it.
gcc/testsuite/ChangeLog:
* g++.dg/cpp23/constexpr-nonlit18.C: Remove redundant message.
* g++.dg/cpp1y/constexpr-diag2.C: New test.
* g++.dg/cpp1y/pr63996.C: Adjust expected errors.
* g++.dg/template/explicit-args6.C: Likewise.
* g++.dg/cpp0x/constexpr-ice21.C: Likewise.
---
gcc/cp/cp-tree.h | 2 ++
gcc/cp/constexpr.cc | 18 +++++++++++++-----
gcc/cp/parser.cc | 5 +++++
gcc/cp/pt.cc | 5 +++++
gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C | 2 +-
gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C | 12 ++++++++++++
gcc/testsuite/g++.dg/cpp1y/pr63996.C | 3 +--
.../g++.dg/cpp23/constexpr-nonlit18.C | 2 +-
gcc/testsuite/g++.dg/template/explicit-args6.C | 8 +++++---
9 files changed, 45 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 55f986e25c1..7798efba3db 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2206,6 +2206,8 @@ struct GTY(()) language_function {
BOOL_BITFIELD invalid_constexpr : 1;
BOOL_BITFIELD throwing_cleanup : 1;
+ /* True if we gave any errors in this function. */
+ BOOL_BITFIELD erroneous : 1;
hash_table<named_label_hash> *x_named_labels;
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 4346b29abc6..d647a09269d 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1048,6 +1048,12 @@ explain_invalid_constexpr_fn (tree fun)
{
static hash_set<tree> *diagnosed;
tree body;
+
+ /* Don't try to explain a function we already complained about. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ return;
+
/* In C++23, a function marked 'constexpr' may not actually be a constant
expression. We haven't diagnosed the problem yet: -Winvalid-constexpr
wasn't enabled. The function was called, so diagnose why it cannot be
@@ -3079,6 +3085,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree
t,
}
constexpr_ctx new_ctx = *ctx;
+ ctx = &new_ctx;
if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
&& TREE_CODE (t) == AGGR_INIT_EXPR)
{
@@ -3088,16 +3095,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
tree t,
tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
CONSTRUCTOR_NO_CLEARING (ctor) = true;
ctx->global->put_value (new_ctx.object, ctor);
- ctx = &new_ctx;
}
/* An immediate invocation is manifestly constant evaluated including the
arguments of the call, so use mce_true even for the argument
evaluation. */
if (DECL_IMMEDIATE_FUNCTION_P (fun))
- {
- new_ctx.manifestly_const_eval = mce_true;
- ctx = &new_ctx;
- }
+ new_ctx.manifestly_const_eval = mce_true;
/* We used to shortcut trivial constructor/op= here, but nowadays
we can only get a trivial function here with -fno-elide-constructors. */
@@ -3185,6 +3188,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree
t,
}
}
+ /* Don't complain about problems evaluating an ill-formed function. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ new_ctx.quiet = true;
+
int depth_ok = push_cx_call_context (t);
/* Remember the object we are constructing or destructing. */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 812a7c5ae7d..3628cfefa07 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -33634,6 +33634,8 @@ cp_parser_function_definition_after_declarator
(cp_parser* parser,
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ int errs = errorcount + sorrycount;
+
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
or function-transaction-block. Note that all of these include the
@@ -33653,6 +33655,9 @@ cp_parser_function_definition_after_declarator
(cp_parser* parser,
fn = finish_function (inline_p);
check_module_decl_linkage (fn);
+ if ((errorcount + sorrycount) > errs)
+ DECL_STRUCT_FUNCTION (fn)->language->erroneous = true;
+
if (modules_p ()
&& !inline_p
&& TYPE_P (DECL_CONTEXT (fn))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 51433e7c4ec..a71705fd085 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -27758,6 +27758,11 @@ instantiate_body (tree pattern, tree args, tree d,
bool nested_p)
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
cp_check_omp_declare_reduction (d);
+
+ if (int errs = errorcount + sorrycount)
+ if (errs > current_tinst_level->errors)
+ if (function *f = DECL_STRUCT_FUNCTION (d))
+ f->language->erroneous = true;
}
/* We're not deferring instantiation any more. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
index 46273654f24..dcc404489be 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C
@@ -3,7 +3,7 @@
struct NoMut1 { int a, b; };
struct NoMut3 : virtual NoMut1 {
- constexpr NoMut3(int a, int b) // { dg-error "virtual base" "" { target
c++23 } }
+ constexpr NoMut3(int a, int b)
: NoMut1{a, b}
{} // { dg-error "virtual base" }
};
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
b/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
new file mode 100644
index 00000000000..93f3f10898e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
@@ -0,0 +1,12 @@
+// PR c++/113360
+// { dg-do compile { target c++14 } }
+
+constexpr bool init_list() // { dg-bogus "because" }
+{
+ int total{};
+ for (int x : {1, 2, 3}) // { dg-error "initializer list" }
+ total += x;
+ return total == 6;
+}
+
+static_assert(init_list(), ""); // { dg-error "constant" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr63996.C
b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
index 8eee2e0af30..347c86cc63c 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr63996.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr63996.C
@@ -1,5 +1,4 @@
// { dg-do compile { target c++14 } }
-// { dg-additional-options "-Wno-return-type" }
constexpr int
foo (int i)
@@ -8,4 +7,4 @@ foo (int i)
if (i == 23) return 0;
}
-constexpr int j = foo (1); // { dg-error "flows off the end|in .constexpr.
expansion of" }
+constexpr int j = foo (1);
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C
b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C
index 8e230ef3bc3..f8918148cda 100644
--- a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C
@@ -24,7 +24,7 @@ f3 ()
}
constexpr int
-f4 () // { dg-message "declared here" "" {
target c++20_down } }
+f4 ()
{ // { dg-message "is not usable as a
'constexpr' function because:" "" { target c++23 } .-1 }
static const int a = f1 (1); // { dg-error "'a' defined 'static' in
'constexpr' function only available with" "" { target c++20_down } }
return 0; // { dg-error "'a' defined 'static' in
'constexpr' context" "" { target c++23 } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/explicit-args6.C
b/gcc/testsuite/g++.dg/template/explicit-args6.C
index 18663d7bcf9..0d9718c38f6 100644
--- a/gcc/testsuite/g++.dg/template/explicit-args6.C
+++ b/gcc/testsuite/g++.dg/template/explicit-args6.C
@@ -24,10 +24,12 @@ frob()
// narrowing check, reject negative values
return unsigned{N}; // { dg-prune-output "narrowing" }
-} // { dg-prune-output "flows off the end" }
-// { dg-prune-output "not a return-statement" }
+}
-template<int N> void get_n(tuple& t) { get<frob<N>()>(t); } // { dg-error "" }
+// This complains about calling frob only in C++11 because
+// maybe_save_constexpr_fundef fails; in later standards it succeeds,
+// and the evaluation failure is silent due to the earlier errors.
+template<int N> void get_n(tuple& t) { get<frob<N>()>(t); } // { dg-error ""
"" { target c++11_only } }
int main()
{
base-commit: dbffeadf7f682625c7ac8c251ee62c02c90f32df
--
2.49.0