Commit a0ab7ccd by Jason Merrill Committed by Jason Merrill

Add immediate potential_constant_expression variants.

	* constexpr.c (potential_constant_expression_1): Add "now" parm.
	(is_constant_expression, require_constant_expression): New.
	(is_static_init_expression, is_nondependent_constant_expression)
	(is_nondependent_static_init_expression): Drop "potential".
	* except.c (build_must_not_throw_expr): Do type conversion on
	value-dependent argument.
	* pt.c, semantics.c, typeck2.c: Use variants without "potential".

From-SVN: r251423
parent 12659e10
2017-08-29 Jason Merrill <jason@redhat.com> 2017-08-29 Jason Merrill <jason@redhat.com>
* constexpr.c (potential_constant_expression_1): Add "now" parm.
(is_constant_expression, require_constant_expression): New.
(is_static_init_expression, is_nondependent_constant_expression)
(is_nondependent_static_init_expression): Drop "potential".
* except.c (build_must_not_throw_expr): Do type conversion on
value-dependent argument.
* pt.c, semantics.c, typeck2.c: Use variants without "potential".
Instantiate default arguments/member initializers once. Instantiate default arguments/member initializers once.
* init.c (get_nsdmi): Remember NSDMI instantiations. * init.c (get_nsdmi): Remember NSDMI instantiations.
* parser.c (inject_this_parameter): Be more picky about * parser.c (inject_this_parameter): Be more picky about
......
...@@ -1181,7 +1181,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1181,7 +1181,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
return t; return t;
} }
if (!potential_constant_expression (new_call)) if (!is_constant_expression (new_call))
{ {
if (!*non_constant_p && !ctx->quiet) if (!*non_constant_p && !ctx->quiet)
error ("%q+E is not a constant expression", new_call); error ("%q+E is not a constant expression", new_call);
...@@ -4861,7 +4861,7 @@ maybe_constant_value (tree t, tree decl) ...@@ -4861,7 +4861,7 @@ maybe_constant_value (tree t, tree decl)
{ {
tree r; tree r;
if (!potential_nondependent_constant_expression (t)) if (!is_nondependent_constant_expression (t))
{ {
if (TREE_OVERFLOW_P (t)) if (TREE_OVERFLOW_P (t))
{ {
...@@ -4929,7 +4929,7 @@ fold_non_dependent_expr (tree t) ...@@ -4929,7 +4929,7 @@ fold_non_dependent_expr (tree t)
as two declarations of the same function, for example. */ as two declarations of the same function, for example. */
if (processing_template_decl) if (processing_template_decl)
{ {
if (potential_nondependent_constant_expression (t)) if (is_nondependent_constant_expression (t))
{ {
processing_template_decl_sentinel s; processing_template_decl_sentinel s;
t = instantiate_non_dependent_expr_internal (t, tf_none); t = instantiate_non_dependent_expr_internal (t, tf_none);
...@@ -4982,7 +4982,7 @@ maybe_constant_init (tree t, tree decl) ...@@ -4982,7 +4982,7 @@ maybe_constant_init (tree t, tree decl)
t = TREE_OPERAND (t, 1); t = TREE_OPERAND (t, 1);
if (TREE_CODE (t) == TARGET_EXPR) if (TREE_CODE (t) == TARGET_EXPR)
t = TARGET_EXPR_INITIAL (t); t = TARGET_EXPR_INITIAL (t);
if (!potential_nondependent_static_init_expression (t)) if (!is_nondependent_static_init_expression (t))
/* Don't try to evaluate it. */; /* Don't try to evaluate it. */;
else if (CONSTANT_CLASS_P (t)) else if (CONSTANT_CLASS_P (t))
/* No evaluation needed. */; /* No evaluation needed. */;
...@@ -5025,7 +5025,9 @@ check_automatic_or_tls (tree ref) ...@@ -5025,7 +5025,9 @@ check_automatic_or_tls (tree ref)
/* Return true if T denotes a potentially constant expression. Issue /* Return true if T denotes a potentially constant expression. Issue
diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true, diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true,
an lvalue-rvalue conversion is implied. an lvalue-rvalue conversion is implied. If NOW is true, we want to
consider the expression in the current context, independent of constexpr
substitution.
C++0x [expr.const] used to say C++0x [expr.const] used to say
...@@ -5041,10 +5043,12 @@ check_automatic_or_tls (tree ref) ...@@ -5041,10 +5043,12 @@ check_automatic_or_tls (tree ref)
not evaluated are not considered. */ not evaluated are not considered. */
static bool static bool
potential_constant_expression_1 (tree t, bool want_rval, bool strict, potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
tsubst_flags_t flags) tsubst_flags_t flags)
{ {
#define RECUR(T,RV) potential_constant_expression_1 ((T), (RV), strict, flags) #define RECUR(T,RV) \
potential_constant_expression_1 ((T), (RV), strict, now, flags)
enum { any = false, rval = true }; enum { any = false, rval = true };
int i; int i;
tree tmp; tree tmp;
...@@ -5087,7 +5091,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5087,7 +5091,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case USERDEF_LITERAL: case USERDEF_LITERAL:
/* We can see a FIELD_DECL in a pointer-to-member expression. */ /* We can see a FIELD_DECL in a pointer-to-member expression. */
case FIELD_DECL: case FIELD_DECL:
case PARM_DECL:
case RESULT_DECL: case RESULT_DECL:
case USING_DECL: case USING_DECL:
case USING_STMT: case USING_STMT:
...@@ -5098,6 +5101,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5098,6 +5101,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case STATIC_ASSERT: case STATIC_ASSERT:
return true; return true;
case PARM_DECL:
if (now)
{
if (flags & tf_error)
error ("%qE is not a constant expression", t);
return false;
}
return true;
case AGGR_INIT_EXPR: case AGGR_INIT_EXPR:
case CALL_EXPR: case CALL_EXPR:
/* -- an invocation of a function other than a constexpr function /* -- an invocation of a function other than a constexpr function
...@@ -5173,7 +5185,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5173,7 +5185,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
tree x = get_nth_callarg (t, 0); tree x = get_nth_callarg (t, 0);
if (is_this_parameter (x)) if (is_this_parameter (x))
return true; return true;
else if (!RECUR (x, rval)) /* Don't require an immediately constant value, as
constexpr substitution might not use the value. */
bool sub_now = false;
if (!potential_constant_expression_1 (x, rval, strict,
sub_now, flags))
return false; return false;
i = 1; i = 1;
} }
...@@ -5203,7 +5219,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5203,7 +5219,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
REFERENCE_TYPE and we might not even know if the parameter REFERENCE_TYPE and we might not even know if the parameter
is a reference, so accept lvalue constants too. */ is a reference, so accept lvalue constants too. */
bool rv = processing_template_decl ? any : rval; bool rv = processing_template_decl ? any : rval;
if (!RECUR (x, rv)) /* Don't require an immediately constant value, as constexpr
substitution might not use the value of the argument. */
bool sub_now = false;
if (!potential_constant_expression_1 (x, rv, strict,
sub_now, flags))
return false; return false;
} }
return true; return true;
...@@ -5759,7 +5779,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5759,7 +5779,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
return RECUR (TREE_OPERAND (t, 1), want_rval); return RECUR (TREE_OPERAND (t, 1), want_rval);
for (i = 1; i < 3; ++i) for (i = 1; i < 3; ++i)
if (potential_constant_expression_1 (TREE_OPERAND (t, i), if (potential_constant_expression_1 (TREE_OPERAND (t, i),
want_rval, strict, tf_none)) want_rval, strict, now, tf_none))
return true; return true;
if (flags & tf_error) if (flags & tf_error)
error_at (loc, "expression %qE is not a constant expression", t); error_at (loc, "expression %qE is not a constant expression", t);
...@@ -5816,13 +5836,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, ...@@ -5816,13 +5836,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
bool bool
potential_constant_expression (tree t) potential_constant_expression (tree t)
{ {
return potential_constant_expression_1 (t, false, true, tf_none); return potential_constant_expression_1 (t, false, true, false, tf_none);
}
bool
potential_static_init_expression (tree t)
{
return potential_constant_expression_1 (t, false, false, tf_none);
} }
/* As above, but require a constant rvalue. */ /* As above, but require a constant rvalue. */
...@@ -5830,7 +5844,7 @@ potential_static_init_expression (tree t) ...@@ -5830,7 +5844,7 @@ potential_static_init_expression (tree t)
bool bool
potential_rvalue_constant_expression (tree t) potential_rvalue_constant_expression (tree t)
{ {
return potential_constant_expression_1 (t, true, true, tf_none); return potential_constant_expression_1 (t, true, true, false, tf_none);
} }
/* Like above, but complain about non-constant expressions. */ /* Like above, but complain about non-constant expressions. */
...@@ -5838,7 +5852,7 @@ potential_rvalue_constant_expression (tree t) ...@@ -5838,7 +5852,7 @@ potential_rvalue_constant_expression (tree t)
bool bool
require_potential_constant_expression (tree t) require_potential_constant_expression (tree t)
{ {
return potential_constant_expression_1 (t, false, true, tf_warning_or_error); return potential_constant_expression_1 (t, false, true, false, tf_warning_or_error);
} }
/* Cross product of the above. */ /* Cross product of the above. */
...@@ -5846,7 +5860,38 @@ require_potential_constant_expression (tree t) ...@@ -5846,7 +5860,38 @@ require_potential_constant_expression (tree t)
bool bool
require_potential_rvalue_constant_expression (tree t) require_potential_rvalue_constant_expression (tree t)
{ {
return potential_constant_expression_1 (t, true, true, tf_warning_or_error); return potential_constant_expression_1 (t, true, true, false, tf_warning_or_error);
}
/* Like potential_constant_expression, but don't consider possible constexpr
substitution of the current function. That is, PARM_DECL qualifies under
potential_constant_expression, but not here.
This is basically what you can check when any actual constant values might
be value-dependent. */
bool
is_constant_expression (tree t)
{
return potential_constant_expression_1 (t, false, true, true, tf_none);
}
/* Like above, but complain about non-constant expressions. */
bool
require_constant_expression (tree t)
{
return potential_constant_expression_1 (t, false, true, true,
tf_warning_or_error);
}
/* Like is_constant_expression, but allow const variables that are not allowed
under constexpr rules. */
bool
is_static_init_expression (tree t)
{
return potential_constant_expression_1 (t, false, false, true, tf_none);
} }
/* Returns true if T is a potential constant expression that is not /* Returns true if T is a potential constant expression that is not
...@@ -5854,11 +5899,11 @@ require_potential_rvalue_constant_expression (tree t) ...@@ -5854,11 +5899,11 @@ require_potential_rvalue_constant_expression (tree t)
in a template. */ in a template. */
bool bool
potential_nondependent_constant_expression (tree t) is_nondependent_constant_expression (tree t)
{ {
return (!type_unknown_p (t) return (!type_unknown_p (t)
&& !BRACE_ENCLOSED_INITIALIZER_P (t) && !BRACE_ENCLOSED_INITIALIZER_P (t)
&& potential_constant_expression (t) && is_constant_expression (t)
&& !instantiation_dependent_expression_p (t)); && !instantiation_dependent_expression_p (t));
} }
...@@ -5866,11 +5911,11 @@ potential_nondependent_constant_expression (tree t) ...@@ -5866,11 +5911,11 @@ potential_nondependent_constant_expression (tree t)
instantiation-dependent. */ instantiation-dependent. */
bool bool
potential_nondependent_static_init_expression (tree t) is_nondependent_static_init_expression (tree t)
{ {
return (!type_unknown_p (t) return (!type_unknown_p (t)
&& !BRACE_ENCLOSED_INITIALIZER_P (t) && !BRACE_ENCLOSED_INITIALIZER_P (t)
&& potential_static_init_expression (t) && is_static_init_expression (t)
&& !instantiation_dependent_expression_p (t)); && !instantiation_dependent_expression_p (t));
} }
......
...@@ -7325,11 +7325,13 @@ extern bool is_valid_constexpr_fn (tree, bool); ...@@ -7325,11 +7325,13 @@ extern bool is_valid_constexpr_fn (tree, bool);
extern bool check_constexpr_ctor_body (tree, tree, bool); extern bool check_constexpr_ctor_body (tree, tree, bool);
extern tree ensure_literal_type_for_constexpr_object (tree); extern tree ensure_literal_type_for_constexpr_object (tree);
extern bool potential_constant_expression (tree); extern bool potential_constant_expression (tree);
extern bool potential_nondependent_constant_expression (tree); extern bool is_constant_expression (tree);
extern bool potential_nondependent_static_init_expression (tree); extern bool is_nondependent_constant_expression (tree);
extern bool potential_static_init_expression (tree); extern bool is_nondependent_static_init_expression (tree);
extern bool is_static_init_expression (tree);
extern bool potential_rvalue_constant_expression (tree); extern bool potential_rvalue_constant_expression (tree);
extern bool require_potential_constant_expression (tree); extern bool require_potential_constant_expression (tree);
extern bool require_constant_expression (tree);
extern bool require_potential_rvalue_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree);
extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree cxx_constant_value (tree, tree = NULL_TREE);
extern tree maybe_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE);
......
...@@ -261,13 +261,19 @@ build_must_not_throw_expr (tree body, tree cond) ...@@ -261,13 +261,19 @@ build_must_not_throw_expr (tree body, tree cond)
if (!flag_exceptions) if (!flag_exceptions)
return body; return body;
if (cond && !value_dependent_expression_p (cond)) if (!cond)
/* OK, unconditional. */;
else
{ {
cond = perform_implicit_conversion_flags (boolean_type_node, cond, tree conv = NULL_TREE;
tf_warning_or_error, if (!type_dependent_expression_p (cond))
LOOKUP_NORMAL); conv = perform_implicit_conversion_flags (boolean_type_node, cond,
cond = instantiate_non_dependent_expr (cond); tf_warning_or_error,
cond = cxx_constant_value (cond); LOOKUP_NORMAL);
if (tree inst = instantiate_non_dependent_or_null (conv))
cond = cxx_constant_value (inst);
else
require_constant_expression (cond);
if (integer_zerop (cond)) if (integer_zerop (cond))
return body; return body;
else if (integer_onep (cond)) else if (integer_onep (cond))
......
...@@ -5827,7 +5827,7 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain) ...@@ -5827,7 +5827,7 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
as two declarations of the same function, for example. */ as two declarations of the same function, for example. */
if (processing_template_decl if (processing_template_decl
&& potential_nondependent_constant_expression (expr)) && is_nondependent_constant_expression (expr))
{ {
processing_template_decl_sentinel s; processing_template_decl_sentinel s;
expr = instantiate_non_dependent_expr_internal (expr, complain); expr = instantiate_non_dependent_expr_internal (expr, complain);
...@@ -5851,7 +5851,7 @@ instantiate_non_dependent_or_null (tree expr) ...@@ -5851,7 +5851,7 @@ instantiate_non_dependent_or_null (tree expr)
return NULL_TREE; return NULL_TREE;
if (processing_template_decl) if (processing_template_decl)
{ {
if (!potential_nondependent_constant_expression (expr)) if (!is_nondependent_constant_expression (expr))
expr = NULL_TREE; expr = NULL_TREE;
else else
{ {
...@@ -6437,15 +6437,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) ...@@ -6437,15 +6437,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
&& has_value_dependent_address (expr)) && has_value_dependent_address (expr))
/* If we want the address and it's value-dependent, don't fold. */; /* If we want the address and it's value-dependent, don't fold. */;
else if (processing_template_decl else if (processing_template_decl
&& potential_nondependent_constant_expression (expr)) && is_nondependent_constant_expression (expr))
non_dep = true; non_dep = true;
if (error_operand_p (expr)) if (error_operand_p (expr))
return error_mark_node; return error_mark_node;
expr_type = TREE_TYPE (expr); expr_type = TREE_TYPE (expr);
if (TREE_CODE (type) == REFERENCE_TYPE)
expr = mark_lvalue_use (expr);
else
expr = mark_rvalue_use (expr);
/* If the argument is non-dependent, perform any conversions in /* If the argument is non-dependent, perform any conversions in
non-dependent context as well. */ non-dependent context as well. */
...@@ -6493,6 +6489,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) ...@@ -6493,6 +6489,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
} }
} }
if (TREE_CODE (type) == REFERENCE_TYPE)
expr = mark_lvalue_use (expr);
else
expr = mark_rvalue_use (expr);
/* HACK: Due to double coercion, we can get a /* HACK: Due to double coercion, we can get a
NOP_EXPR<REFERENCE_TYPE>(ADDR_EXPR<POINTER_TYPE> (arg)) here, NOP_EXPR<REFERENCE_TYPE>(ADDR_EXPR<POINTER_TYPE> (arg)) here,
which is the tree that we built on the first call (see which is the tree that we built on the first call (see
......
...@@ -735,7 +735,7 @@ finish_if_stmt_cond (tree cond, tree if_stmt) ...@@ -735,7 +735,7 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
{ {
cond = maybe_convert_cond (cond); cond = maybe_convert_cond (cond);
if (IF_STMT_CONSTEXPR_P (if_stmt) if (IF_STMT_CONSTEXPR_P (if_stmt)
&& require_potential_rvalue_constant_expression (cond) && is_constant_expression (cond)
&& !value_dependent_expression_p (cond)) && !value_dependent_expression_p (cond))
{ {
cond = instantiate_non_dependent_expr (cond); cond = instantiate_non_dependent_expr (cond);
......
...@@ -821,7 +821,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) ...@@ -821,7 +821,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|| (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl))) || (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
{ {
/* Diagnose a non-constant initializer for constexpr. */ /* Diagnose a non-constant initializer for constexpr. */
if (!require_potential_constant_expression (value)) if (!require_constant_expression (value))
value = error_mark_node; value = error_mark_node;
else else
value = cxx_constant_value (value, decl); value = cxx_constant_value (value, decl);
......
// { dg-do compile { target c++11 } }
template <int I> void f();
struct A { constexpr operator int() { return 24; } };
template <class T> constexpr void g(T t)
{
f<t>();
}
int main()
{
g(A());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment