c++: Improve error recovery with constexpr [PR92193]

The compiler tries to limit error cascades in limit_bad_template_recursion
by avoiding triggering a new instantiation from one that has caused errors.
We were exempting constexpr functions from this because they can be needed
for constant evaluation, but as more and more functions get marked
constexpr, this becomes an over-broad category.  So as suggested on IRC,
this patch only exempts functions that are needed for mandatory constant
evaluation.

As noted in the comment, this flag doesn't particularly need to use a bit in
the FUNCTION_DECL, but there were still some free.

	PR c++/92193

gcc/cp/ChangeLog:

	* cp-tree.h (FNDECL_MANIFESTLY_CONST_EVALUATED): New.
	* constexpr.c (cxx_eval_call_expression): Set it.
	* pt.c (neglectable_inst_p): Check it.

gcc/testsuite/ChangeLog:

	* g++.dg/diagnostic/static_assert4.C: New test.
This commit is contained in:
Jason Merrill 2021-08-30 18:42:05 -04:00
parent 18f0e57b9a
commit 9aeadd8c31
4 changed files with 42 additions and 1 deletions

View File

@ -2572,6 +2572,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
location_t save_loc = input_location;
input_location = loc;
++function_depth;
if (ctx->manifestly_const_eval)
FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
--function_depth;
input_location = save_loc;

View File

@ -500,6 +500,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
OVL_LOOKUP_P (in OVERLOAD)
LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, NAMESPACE_DECL)
FNDECL_MANIFESTLY_CONST_EVALUATED (in FUNCTION_DECL)
5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
@ -4213,6 +4214,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define FNDECL_USED_AUTO(NODE) \
TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE))
/* True if NODE is needed for a manifestly constant-evaluated expression.
This doesn't especially need to be a flag, since currently it's only
used for error recovery; if we run out of function flags it could move
to an attribute. */
#define FNDECL_MANIFESTLY_CONST_EVALUATED(NODE) \
TREE_LANG_FLAG_4 (FUNCTION_DECL_CHECK (NODE))
/* True for artificial decls added for OpenMP privatized non-static
data members. */
#define DECL_OMP_PRIVATIZED_MEMBER(NODE) \

View File

@ -10873,7 +10873,8 @@ neglectable_inst_p (tree d)
{
return (d && DECL_P (d)
&& !undeduced_auto_decl (d)
&& !(TREE_CODE (d) == FUNCTION_DECL ? DECL_DECLARED_CONSTEXPR_P (d)
&& !(TREE_CODE (d) == FUNCTION_DECL
? FNDECL_MANIFESTLY_CONST_EVALUATED (d)
: decl_maybe_constant_var_p (d)));
}

View File

@ -0,0 +1,30 @@
// PR c++/92193
// { dg-do compile { target c++11 } }
template<typename T>
struct has_foo
{ static constexpr bool value = false; };
template<typename T>
#ifndef NO_CONSTEXPR
constexpr
#endif
bool
foo(T t) noexcept(noexcept(t.foo()))
{ return t.foo(); }
template<typename T>
void
maybe_foo(T t)
{
static_assert( has_foo<T>::value, "has foo" ); // { dg-error "has foo" }
foo(t);
}
struct X { };
int main()
{
X x;
maybe_foo(x);
}