c++: ill-formed constexpr function [PR113360]
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.
This commit is contained in:
parent
5e3646a3cb
commit
ac31e41c58
9 changed files with 45 additions and 12 deletions
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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" }
|
||||
};
|
||||
|
|
12
gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
Normal file
12
gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C
Normal file
|
@ -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" }
|
|
@ -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);
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue