diff options
author | Jason Merrill <jason@redhat.com> | 2017-09-28 15:39:45 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2017-09-28 15:39:45 -0400 |
commit | 281e6c1d8f1b4ca552d8ce2276ddecfcd6ffb15e (patch) | |
tree | 4ec4cc5dfce6282bcbc8d1adfbbb092073395b53 /gcc/cp/expr.c | |
parent | 5c263e84ab7e5df28a9055ae533c2d305f4b7b3d (diff) | |
download | gcc-281e6c1d8f1b4ca552d8ce2276ddecfcd6ffb15e.zip gcc-281e6c1d8f1b4ca552d8ce2276ddecfcd6ffb15e.tar.gz gcc-281e6c1d8f1b4ca552d8ce2276ddecfcd6ffb15e.tar.bz2 |
PR c++/56973, DR 696 - capture constant variables only as needed.
* expr.c (mark_use): Split out from mark_rvalue_use and
mark_lvalue_use. Handle lambda capture of constant variables.
(mark_lvalue_use_nonread): New.
* semantics.c (process_outer_var_ref): Don't capture a constant
variable until forced.
* pt.c (processing_nonlambda_template): New.
* call.c (build_this): Check it.
* decl2.c (grok_array_decl): Call mark_rvalue_use and
mark_lvalue_use_nonread.
* init.c (constant_value_1): Don't call mark_rvalue_use.
* typeck.c (build_static_cast): Handle lambda capture.
From-SVN: r253266
Diffstat (limited to 'gcc/cp/expr.c')
-rw-r--r-- | gcc/cp/expr.c | 107 |
1 files changed, 99 insertions, 8 deletions
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 8bd341b..f5c8e80 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -86,21 +86,105 @@ cplus_expand_constant (tree cst) return cst; } +/* We've seen an actual use of EXPR. Possibly replace an outer variable + reference inside with its constant value or a lambda capture. */ + +static tree +mark_use (tree expr, bool rvalue_p, bool read_p, + location_t loc /* = UNKNOWN_LOCATION */, + bool reject_builtin /* = true */) +{ +#define RECUR(t) mark_use ((t), rvalue_p, read_p, loc, reject_builtin) + + if (reject_builtin && reject_gcc_builtin (expr, loc)) + return error_mark_node; + + if (read_p) + mark_exp_read (expr); + + bool recurse_op[3] = { false, false, false }; + switch (TREE_CODE (expr)) + { + case VAR_DECL: + if (outer_automatic_var_p (expr) + && decl_constant_var_p (expr)) + { + if (rvalue_p) + { + tree t = maybe_constant_value (expr); + if (TREE_CONSTANT (t)) + { + expr = t; + break; + } + } + expr = process_outer_var_ref (expr, tf_warning_or_error, true); + expr = convert_from_reference (expr); + } + break; + case COMPONENT_REF: + recurse_op[0] = true; + break; + case COMPOUND_EXPR: + recurse_op[1] = true; + break; + case COND_EXPR: + recurse_op[2] = true; + if (TREE_OPERAND (expr, 1)) + recurse_op[1] = true; + break; + case INDIRECT_REF: + if (REFERENCE_REF_P (expr)) + { + /* Try to look through the reference. */ + tree ref = TREE_OPERAND (expr, 0); + tree r = mark_rvalue_use (ref, loc, reject_builtin); + if (r != ref) + { + expr = copy_node (expr); + TREE_OPERAND (expr, 0) = r; + } + } + break; + default: + break; + } + + bool changed = false; + tree ops[3]; + for (int i = 0; i < 3; ++i) + if (recurse_op[i]) + { + tree op = TREE_OPERAND (expr, i); + ops[i] = RECUR (op); + if (ops[i] != op) + changed = true; + } + + if (changed) + { + expr = copy_node (expr); + for (int i = 0; i < 3; ++i) + if (recurse_op[i]) + TREE_OPERAND (expr, i) = ops[i]; + } + + return expr; +#undef RECUR +} + /* Called whenever the expression EXPR is used in an rvalue context. When REJECT_BUILTIN is true the expression is checked to make sure it doesn't make it possible to obtain the address of a GCC built-in function with no library fallback (or any of its bits, such as in a conversion to bool). */ + tree -mark_rvalue_use (tree expr, +mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */, bool reject_builtin /* = true */) { - if (reject_builtin && reject_gcc_builtin (expr, loc)) - return error_mark_node; - - mark_exp_read (expr); - return expr; + return mark_use (e, true, true, loc, reject_builtin); } /* Called whenever an expression is used in an lvalue context. */ @@ -108,8 +192,15 @@ mark_rvalue_use (tree expr, tree mark_lvalue_use (tree expr) { - mark_exp_read (expr); - return expr; + return mark_use (expr, false, true, input_location, false); +} + +/* As above, but don't consider this use a read. */ + +tree +mark_lvalue_use_nonread (tree expr) +{ + return mark_use (expr, false, false, input_location, false); } /* Called whenever an expression is used in a type use context. */ |