diff options
author | Jason Merrill <jason@redhat.com> | 2018-09-08 12:00:02 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2018-09-08 12:00:02 -0400 |
commit | 3075affdbcb3232fe549fbeed87bd94114c14758 (patch) | |
tree | 86657620d81c1d04427d724399e476545acab7d9 /gcc | |
parent | 61856507f42eef2a1474d4b629ed7db641b48a4f (diff) | |
download | gcc-3075affdbcb3232fe549fbeed87bd94114c14758.zip gcc-3075affdbcb3232fe549fbeed87bd94114c14758.tar.gz gcc-3075affdbcb3232fe549fbeed87bd94114c14758.tar.bz2 |
PR c++/86678 - constexpr function with non-constant after return.
In this testcase, the call to f() can never be a constant
expression, but that's not a problem because it isn't always
reached by calls to g. We were wrongly rejecting this because
potential_constant_expression_1 lacked the jump tracking that
cxx_eval_constant_expression has. So this patch adds a simpler
version of that tracking.
* constexpr.c (potential_constant_expression_1): Add jump_target.
(breaks): Check for BREAK_STMT.
(continues): Check for CONTINUE_STMT.
From-SVN: r264171
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 66 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-return4.C | 10 |
3 files changed, 70 insertions, 13 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9ca0ef8..c0fa466 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2018-09-08 Jason Merrill <jason@redhat.com> + + PR c++/86678 - constexpr function with non-constant after return. + * constexpr.c (potential_constant_expression_1): Add jump_target. + (breaks): Check for BREAK_STMT. + (continues): Check for CONTINUE_STMT. + 2018-09-08 Marek Polacek <polacek@redhat.com> * cxx-pretty-print.c (cxx_pretty_printer::statement) <case diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6c26890..68cdd8d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3893,6 +3893,7 @@ breaks (tree *jump_target) return *jump_target && ((TREE_CODE (*jump_target) == LABEL_DECL && LABEL_DECL_BREAK (*jump_target)) + || TREE_CODE (*jump_target) == BREAK_STMT || TREE_CODE (*jump_target) == EXIT_EXPR); } @@ -3900,8 +3901,10 @@ static bool continues (tree *jump_target) { return *jump_target - && TREE_CODE (*jump_target) == LABEL_DECL - && LABEL_DECL_CONTINUE (*jump_target); + && ((TREE_CODE (*jump_target) == LABEL_DECL + && LABEL_DECL_CONTINUE (*jump_target)) + || TREE_CODE (*jump_target) == CONTINUE_STMT); + } static bool @@ -4123,7 +4126,7 @@ static tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, bool *non_constant_p, bool *overflow_p, - tree *jump_target) + tree *jump_target /* = NULL */) { constexpr_ctx new_ctx; tree r = t; @@ -4149,7 +4152,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return NULL_TREE; } } - if (t == error_mark_node) + if (error_operand_p (t)) { *non_constant_p = true; return t; @@ -5398,10 +5401,10 @@ check_automatic_or_tls (tree ref) static bool potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, - tsubst_flags_t flags) + tsubst_flags_t flags, tree *jump_target) { #define RECUR(T,RV) \ - potential_constant_expression_1 ((T), (RV), strict, now, flags) + potential_constant_expression_1 ((T), (RV), strict, now, flags, jump_target) enum { any = false, rval = true }; int i; @@ -5412,6 +5415,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, if (t == NULL_TREE) return true; location_t loc = cp_expr_loc_or_loc (t, input_location); + + if (*jump_target) + /* If we are jumping, ignore everything. This is simpler than the + cxx_eval_constant_expression handling because we only need to be + conservatively correct, and we don't necessarily have a constant value + available, so we don't bother with switch tracking. */ + return true; + if (TREE_THIS_VOLATILE (t) && !DECL_P (t)) { if (flags & tf_error) @@ -5449,13 +5460,21 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case USING_DECL: case USING_STMT: case PLACEHOLDER_EXPR: - case BREAK_STMT: - case CONTINUE_STMT: case REQUIRES_EXPR: case STATIC_ASSERT: case DEBUG_BEGIN_STMT: return true; + case RETURN_EXPR: + if (!RECUR (TREE_OPERAND (t, 0), any)) + return false; + /* FALLTHROUGH */ + + case BREAK_STMT: + case CONTINUE_STMT: + *jump_target = t; + return true; + case PARM_DECL: if (now) { @@ -5544,7 +5563,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, constexpr substitution might not use the value. */ bool sub_now = false; if (!potential_constant_expression_1 (x, rval, strict, - sub_now, flags)) + sub_now, flags, + jump_target)) return false; i = 1; } @@ -5578,7 +5598,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, substitution might not use the value of the argument. */ bool sub_now = false; if (!potential_constant_expression_1 (x, rv, strict, - sub_now, flags)) + sub_now, flags, jump_target)) return false; } return true; @@ -5753,6 +5773,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!RECUR (DO_BODY (t), any)) return false; + if (breaks (jump_target) || continues (jump_target)) + *jump_target = NULL_TREE; return true; case FOR_STMT: @@ -5764,6 +5786,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!RECUR (FOR_BODY (t), any)) return false; + if (breaks (jump_target) || continues (jump_target)) + *jump_target = NULL_TREE; return true; case RANGE_FOR_STMT: @@ -5773,6 +5797,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!RECUR (RANGE_FOR_BODY (t), any)) return false; + if (breaks (jump_target) || continues (jump_target)) + *jump_target = NULL_TREE; return true; case WHILE_STMT: @@ -5780,6 +5806,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!RECUR (WHILE_BODY (t), any)) return false; + if (breaks (jump_target) || continues (jump_target)) + *jump_target = NULL_TREE; return true; case SWITCH_STMT: @@ -5963,7 +5991,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case PAREN_EXPR: case NON_DEPENDENT_EXPR: /* For convenience. */ - case RETURN_EXPR: case LOOP_EXPR: case EXIT_EXPR: return RECUR (TREE_OPERAND (t, 0), want_rval); @@ -6173,7 +6200,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, 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, now, tf_none)) + want_rval, strict, now, + tf_none, jump_target)) return true; if (flags & tf_error) error_at (loc, "expression %qE is not a constant expression", t); @@ -6204,7 +6232,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, tree *target = &TREE_OPERAND (t, 0); /* Gotos representing break and continue are OK. */ if (breaks (target) || continues (target)) - return true; + { + *jump_target = *target; + return true; + } if (flags & tf_error) error_at (loc, "%<goto%> is not a constant expression"); return false; @@ -6224,6 +6255,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, #undef RECUR } +bool +potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, + tsubst_flags_t flags) +{ + tree target = NULL_TREE; + return potential_constant_expression_1 (t, want_rval, strict, now, + flags, &target); +} + /* The main entry point to the above. */ bool diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-return4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-return4.C new file mode 100644 index 0000000..8f29628 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-return4.C @@ -0,0 +1,10 @@ +// PR c++/86678 +// { dg-do compile { target c++14 } } + +constexpr bool always_true() { return true; } +int f() { return 1; } +constexpr int g() { + if (always_true()) + return 0; + return f(); +} |