From a0ab7ccd216184853052cec1bce7900cbdeed0b4 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 29 Aug 2017 15:40:14 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 8 ++ gcc/cp/constexpr.c | 95 ++++++++++++++------ gcc/cp/cp-tree.h | 8 +- gcc/cp/except.c | 18 ++-- gcc/cp/pt.c | 15 ++-- gcc/cp/semantics.c | 2 +- gcc/cp/typeck2.c | 2 +- gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C | 15 ++++ 8 files changed, 120 insertions(+), 43 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 308e13abba7..f91f6bebcb6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2017-08-29 Jason Merrill + * 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. * init.c (get_nsdmi): Remember NSDMI instantiations. * parser.c (inject_this_parameter): Be more picky about diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 29ba2c3dac2..8cfc5a455c1 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1181,7 +1181,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, return t; } - if (!potential_constant_expression (new_call)) + if (!is_constant_expression (new_call)) { if (!*non_constant_p && !ctx->quiet) error ("%q+E is not a constant expression", new_call); @@ -4861,7 +4861,7 @@ maybe_constant_value (tree t, tree decl) { tree r; - if (!potential_nondependent_constant_expression (t)) + if (!is_nondependent_constant_expression (t)) { if (TREE_OVERFLOW_P (t)) { @@ -4929,7 +4929,7 @@ fold_non_dependent_expr (tree t) as two declarations of the same function, for example. */ if (processing_template_decl) { - if (potential_nondependent_constant_expression (t)) + if (is_nondependent_constant_expression (t)) { processing_template_decl_sentinel s; t = instantiate_non_dependent_expr_internal (t, tf_none); @@ -4982,7 +4982,7 @@ maybe_constant_init (tree t, tree decl) t = TREE_OPERAND (t, 1); if (TREE_CODE (t) == TARGET_EXPR) 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. */; else if (CONSTANT_CLASS_P (t)) /* No evaluation needed. */; @@ -5025,7 +5025,9 @@ check_automatic_or_tls (tree ref) /* Return true if T denotes a potentially constant expression. Issue 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 @@ -5041,10 +5043,12 @@ check_automatic_or_tls (tree ref) not evaluated are not considered. */ 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) { -#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 }; int i; tree tmp; @@ -5087,7 +5091,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case USERDEF_LITERAL: /* We can see a FIELD_DECL in a pointer-to-member expression. */ case FIELD_DECL: - case PARM_DECL: case RESULT_DECL: case USING_DECL: case USING_STMT: @@ -5098,6 +5101,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case STATIC_ASSERT: 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 CALL_EXPR: /* -- 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, tree x = get_nth_callarg (t, 0); if (is_this_parameter (x)) 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; i = 1; } @@ -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 is a reference, so accept lvalue constants too. */ 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 true; @@ -5759,7 +5779,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, return RECUR (TREE_OPERAND (t, 1), want_rval); for (i = 1; i < 3; ++i) if (potential_constant_expression_1 (TREE_OPERAND (t, i), - want_rval, strict, tf_none)) + want_rval, strict, now, tf_none)) return true; if (flags & tf_error) 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, bool potential_constant_expression (tree t) { - return potential_constant_expression_1 (t, false, true, tf_none); -} - -bool -potential_static_init_expression (tree t) -{ - return potential_constant_expression_1 (t, false, false, tf_none); + return potential_constant_expression_1 (t, false, true, false, tf_none); } /* As above, but require a constant rvalue. */ @@ -5830,7 +5844,7 @@ potential_static_init_expression (tree t) bool 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. */ @@ -5838,7 +5852,7 @@ potential_rvalue_constant_expression (tree t) bool 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. */ @@ -5846,7 +5860,38 @@ require_potential_constant_expression (tree t) bool 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 @@ -5854,11 +5899,11 @@ require_potential_rvalue_constant_expression (tree t) in a template. */ bool -potential_nondependent_constant_expression (tree t) +is_nondependent_constant_expression (tree t) { return (!type_unknown_p (t) && !BRACE_ENCLOSED_INITIALIZER_P (t) - && potential_constant_expression (t) + && is_constant_expression (t) && !instantiation_dependent_expression_p (t)); } @@ -5866,11 +5911,11 @@ potential_nondependent_constant_expression (tree t) instantiation-dependent. */ bool -potential_nondependent_static_init_expression (tree t) +is_nondependent_static_init_expression (tree t) { return (!type_unknown_p (t) && !BRACE_ENCLOSED_INITIALIZER_P (t) - && potential_static_init_expression (t) + && is_static_init_expression (t) && !instantiation_dependent_expression_p (t)); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 17e7aad08f6..f0eafb3c277 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7325,11 +7325,13 @@ extern bool is_valid_constexpr_fn (tree, bool); extern bool check_constexpr_ctor_body (tree, tree, bool); extern tree ensure_literal_type_for_constexpr_object (tree); extern bool potential_constant_expression (tree); -extern bool potential_nondependent_constant_expression (tree); -extern bool potential_nondependent_static_init_expression (tree); -extern bool potential_static_init_expression (tree); +extern bool is_constant_expression (tree); +extern bool is_nondependent_constant_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 require_potential_constant_expression (tree); +extern bool require_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree); extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index b25b91b97be..2ee7e97ea23 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -261,13 +261,19 @@ build_must_not_throw_expr (tree body, tree cond) if (!flag_exceptions) return body; - if (cond && !value_dependent_expression_p (cond)) + if (!cond) + /* OK, unconditional. */; + else { - cond = perform_implicit_conversion_flags (boolean_type_node, cond, - tf_warning_or_error, - LOOKUP_NORMAL); - cond = instantiate_non_dependent_expr (cond); - cond = cxx_constant_value (cond); + tree conv = NULL_TREE; + if (!type_dependent_expression_p (cond)) + conv = perform_implicit_conversion_flags (boolean_type_node, cond, + tf_warning_or_error, + 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)) return body; else if (integer_onep (cond)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index eec89dbce5b..e34fe21cb15 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5827,7 +5827,7 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain) as two declarations of the same function, for example. */ if (processing_template_decl - && potential_nondependent_constant_expression (expr)) + && is_nondependent_constant_expression (expr)) { processing_template_decl_sentinel s; expr = instantiate_non_dependent_expr_internal (expr, complain); @@ -5851,7 +5851,7 @@ instantiate_non_dependent_or_null (tree expr) return NULL_TREE; if (processing_template_decl) { - if (!potential_nondependent_constant_expression (expr)) + if (!is_nondependent_constant_expression (expr)) expr = NULL_TREE; else { @@ -6437,15 +6437,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) && has_value_dependent_address (expr)) /* If we want the address and it's value-dependent, don't fold. */; else if (processing_template_decl - && potential_nondependent_constant_expression (expr)) + && is_nondependent_constant_expression (expr)) non_dep = true; if (error_operand_p (expr)) return error_mark_node; 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 non-dependent context as well. */ @@ -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 NOP_EXPR(ADDR_EXPR (arg)) here, which is the tree that we built on the first call (see diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 14e680f39f5..86ce9ce9461 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -735,7 +735,7 @@ finish_if_stmt_cond (tree cond, tree if_stmt) { cond = maybe_convert_cond (cond); if (IF_STMT_CONSTEXPR_P (if_stmt) - && require_potential_rvalue_constant_expression (cond) + && is_constant_expression (cond) && !value_dependent_expression_p (cond)) { cond = instantiate_non_dependent_expr (cond); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 06c079e41be..e9aca395911 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -821,7 +821,7 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) || (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl))) { /* Diagnose a non-constant initializer for constexpr. */ - if (!require_potential_constant_expression (value)) + if (!require_constant_expression (value)) value = error_mark_node; else value = cxx_constant_value (value, decl); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C new file mode 100644 index 00000000000..c64fb3d2fa0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +template void f(); + +struct A { constexpr operator int() { return 24; } }; + +template constexpr void g(T t) +{ + f(); +} + +int main() +{ + g(A()); +} -- 2.30.2