From db1663e7932e2e1878c40273f0488dcead9656a8 Mon Sep 17 00:00:00 2001 From: Slava Barinov Date: Thu, 6 Jul 2017 16:14:58 +0300 Subject: [PATCH] Fix cleanup location for try_finally_expr. gcc/ * tree.def: Add STATEMENT_LIST_END tree code. * tree.c: Add STATEMENT_LIST_END handling as TS_COMMON. * gimplify.c (gimplify_expr): Use STATEMENT_LIST_END location to provide right information for try_finally_expr. * tree-eh.c (lower_try_finally_onedest): Set finally location * c-family/c-semantics.c (pop_stmt_list): Support single-statement lists extraction with STATEMENT_LIST_END in the end. * fold-const.c (operand_equal_p): Add STATEMENT_LIST_END support. gcc/cp/ * parser.c (cp_parser_compound_statement): Use STATEMENT_LIST_END to keep the location of closing brace. * pt.c: Handle STATEMENT_LIST_END. * constraint.cc (check_function_concept): Handle concept definitions with STATEMENT_LIST_END. * error.c (dump_expr): Add STATEMENT_LIST_END support. gcc/testsuite/ * g++.dg/ext/statement-list-end.C: New. Change-Id: Id22e953b97b52d0f2a2ba44065337a59639578db Signed-off-by: Slava Barinov --- gcc/ChangeLog | 17 +++++++++++++++++ gcc/c-family/c-semantics.c | 6 ++++++ gcc/cp/ChangeLog | 7 +++++++ gcc/cp/constexpr.c | 7 +++++++ gcc/cp/constraint.cc | 9 +++++++++ gcc/cp/error.c | 1 + gcc/cp/parser.c | 15 ++++++++++++--- gcc/cp/pt.c | 3 +++ gcc/fold-const.c | 26 +++++++++++++++----------- gcc/gimple.c | 1 + gcc/gimplify.c | 26 ++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/g++.dg/ext/statement-list-end.C | 11 +++++++++++ gcc/testsuite/g++.dg/gcov/gcov-2.C | 4 ++-- gcc/testsuite/g++.dg/parse/error26.C | 4 ++-- gcc/testsuite/g++.dg/tm/inherit2.C | 4 ++-- gcc/testsuite/g++.dg/tm/unsafe1.C | 4 ++-- gcc/tree-eh.c | 15 +++++++++++---- gcc/tree.c | 2 ++ gcc/tree.def | 4 ++++ 20 files changed, 144 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/statement-list-end.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 77528a5..8772afc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2017-07-06 Vyacheslav Barinov + + * tree.def: Add STATEMENT_LIST_END tree code. + * tree.c: Add STATEMENT_LIST_END handling as TS_COMMON. + * gimplify.c (gimplify_expr): Use STATEMENT_LIST_END location to + provide right information for try_finally_expr. + * tree-eh.c (lower_try_finally_onedest): Set finally location + accordingly to location of last statement in cleanup. + * gimple.c (DEFTREECODE): handle STATEMENT_LIST_END as appropriate + GIMPLE_SINGLE_RHS. + * cp/constraint.cc (check_function_concept): Handle concept + definitions with STATEMENT_LIST_END. + * cp/error.c (dump_expr): Add STATEMENT_LIST_END support. + * fold-const.c (operand_equal_p): Add STATEMENT_LIST_END support. + * c-family/c-semantics.c (pop_stmt_list): Support single-statement + lists extraction with STATEMENT_LIST_END in the end. + 2017-04-13 Denis Khalikov PR sanitizer/80414 diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c index 4845a8b..bd4f379 100644 --- a/gcc/c-family/c-semantics.c +++ b/gcc/c-family/c-semantics.c @@ -66,6 +66,12 @@ pop_stmt_list (tree t) if (TREE_SIDE_EFFECTS (t)) { tree_stmt_iterator i = tsi_start (t); + if (i.ptr->next && i.ptr->next->stmt && + TREE_CODE(i.ptr->next->stmt) == STATEMENT_LIST_END) + { + tree_stmt_iterator i = tsi_last (t); + tsi_delink (&i); + } /* If the statement list contained exactly one statement, then extract it immediately. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a7f94b3..3ccddab 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-07-06 Vyacheslav Barinov + + * parser.c (cp_parser_compound_statement): Use STATEMENT_LIST_END + to keep the location of closing brace. + * pt.c: Handle STATEMENT_LIST_END. + * constexpr.c (cxx_eval_constant_expression): Likewise. + 2017-01-26 Jason Merrill PR c++/79176 - lambda ICE with -flto -Os diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index a6ac3c1..f9c4ead 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -441,6 +441,7 @@ check_constexpr_ctor_body_1 (tree last, tree list) case USING_STMT: case STATIC_ASSERT: + case STATEMENT_LIST_END: return true; default: @@ -555,6 +556,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body) body = BIND_EXPR_BODY (body); goto found; + case STATEMENT_LIST_END: + break; + default: gcc_unreachable (); } @@ -666,6 +670,7 @@ constexpr_fn_retval (tree body) return constexpr_fn_retval (BIND_EXPR_BODY (body)); case USING_STMT: + case STATEMENT_LIST_END: return NULL_TREE; default: @@ -4109,6 +4114,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case EMPTY_CLASS_EXPR: + case STATEMENT_LIST_END: /* This is good enough for a function argument that might not get used, and they can't do anything with it, so just return it. */ return t; @@ -5292,6 +5298,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case TYPE_DECL: case TAG_DEFN: + case STATEMENT_LIST_END: /* We can see these in statement-expressions. */ return true; diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 09ae301..157f7dd 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-objc.h" #include "cp-objcp-common.h" #include "tree-inline.h" +#include "tree-iterator.h" #include "decl.h" #include "toplev.h" #include "type-utils.h" @@ -2509,6 +2510,14 @@ check_function_concept (tree fn) if (TREE_CODE (body) == CLEANUP_POINT_EXPR) body = TREE_OPERAND (body, 0); + // We need to cut the STATEMENT_LIST_END before the check. + if (TREE_CODE (body) == STATEMENT_LIST && + TREE_CODE (STATEMENT_LIST_TAIL (body)->stmt) == STATEMENT_LIST_END) + { + tree_stmt_iterator i = tsi_last (body); + tsi_delink(&i); + } + /* Check that the definition is written correctly. */ if (TREE_CODE (body) != RETURN_EXPR) { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 93fe2ffb..a852e71 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2597,6 +2597,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) case STMT_EXPR: case EXPR_STMT: case STATEMENT_LIST: + case STATEMENT_LIST_END: /* We don't yet have a way of dumping statements in a human-readable format. */ pp_string (pp, "({...})"); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 390f7d0..187fe0e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10770,11 +10770,20 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, cp_parser_label_declaration (parser); /* Parse an (optional) statement-seq. */ cp_parser_statement_seq_opt (parser, in_statement_expr); + /* Consume the `}' and keep location, if there is a `}' and compound_stmt is + not empty. */ + cp_token *token = cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + if (token && + TREE_CODE(compound_stmt) == STATEMENT_LIST && + STATEMENT_LIST_HEAD (compound_stmt) && + STATEMENT_LIST_TAIL (compound_stmt)) + { + tree brace_stmt = build0(STATEMENT_LIST_END, void_type_node); + SET_EXPR_LOCATION(brace_stmt, token->location); + add_stmt(brace_stmt); + } /* Finish the compound-statement. */ finish_compound_stmt (compound_stmt); - /* Consume the `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); - return compound_stmt; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 744b461..db403c8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15870,6 +15870,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RETURN (build2_loc (EXPR_LOCATION (t), ANNOTATE_EXPR, TREE_TYPE (tmp), tmp, RECUR (TREE_OPERAND (t, 1)))); + case STATEMENT_LIST_END: + RETURN (t); + default: gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t))); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 9ef4951..46f1ac1 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -186,7 +186,7 @@ div_if_zero_remainder (const_tree arg1, const_tree arg2) SIGNED, &quo)) return wide_int_to_tree (TREE_TYPE (arg1), quo); - return NULL_TREE; + return NULL_TREE; } /* This is nonzero if we should defer warnings about undefined @@ -1984,7 +1984,7 @@ fold_convert_const_real_from_real (tree type, const_tree arg1) and the operand is a signaling NaN. */ if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))) && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1))) - return NULL_TREE; + return NULL_TREE; real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1)); t = build_real (type, value); @@ -2750,7 +2750,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) || TREE_TYPE (arg1) == error_mark_node) return 0; - /* Similar, if either does not have a type (like a released SSA name), + /* Similar, if either does not have a type (like a released SSA name), they aren't equal. */ if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1)) return 0; @@ -3144,6 +3144,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) case DOT_PROD_EXPR: return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); + case STATEMENT_LIST_END: + return 1; + /* All STATEMENT_LIST_END are equal */ + default: return 0; } @@ -3250,10 +3254,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) Double check this so we won't get false positives for GENERIC. */ || (c0->index - && (TREE_CODE (c0->index) != INTEGER_CST + && (TREE_CODE (c0->index) != INTEGER_CST || !compare_tree_int (c0->index, i))) || (c1->index - && (TREE_CODE (c1->index) != INTEGER_CST + && (TREE_CODE (c1->index) != INTEGER_CST || !compare_tree_int (c1->index, i)))) return 0; } @@ -5441,7 +5445,7 @@ unextend (tree c, int p, int unsignedp, tree mask) A || ~B or A && ~B - LOC is the location of the resulting expression. OP is the inner + LOC is the location of the resulting expression. OP is the inner logical operation; the left-hand side in the examples above, while CMPOP is the right-hand side. RHS_ONLY is used to prevent us from accidentally removing a condition that guards another, as in @@ -7163,7 +7167,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off) if (NULL_TREE == i_type || TYPE_PRECISION (i_type) != total_bytes) return 0; - + value = TREE_FIXED_CST (expr); i_value = double_int_to_tree (i_type, value.data); @@ -8176,7 +8180,7 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type, side-effects. */ && simple_operand_p_2 (TREE_OPERAND (arg1, 0))) { - tem = fold_build2_loc (loc, ncode, type, + tem = fold_build2_loc (loc, ncode, type, arg0, TREE_OPERAND (arg1, 0)); return fold_build2_loc (loc, icode, type, tem, TREE_OPERAND (arg1, 1)); @@ -10405,7 +10409,7 @@ fold_binary_loc (location_t loc, case TRUNC_DIV_EXPR: /* Fall through */ - + case FLOOR_DIV_EXPR: /* Simplify A / (B << N) where A and B are positive and B is a power of 2, to A >> (N + log2(B)). */ @@ -10659,10 +10663,10 @@ fold_binary_loc (location_t loc, l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1)); - + n0 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l0); n1 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l1); - + if ((operand_equal_p (n0, a0, 0) && operand_equal_p (n1, a1, 0)) || (operand_equal_p (n0, a1, 0) diff --git a/gcc/gimple.c b/gcc/gimple.c index b874c9f..9200a8b 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -2051,6 +2051,7 @@ get_gimple_rhs_num_ops (enum tree_code code) || (SYM) == ADDR_EXPR \ || (SYM) == WITH_SIZE_EXPR \ || (SYM) == SSA_NAME) ? GIMPLE_SINGLE_RHS \ + : ((SYM) == STATEMENT_LIST_END) ? GIMPLE_SINGLE_RHS \ : GIMPLE_INVALID_RHS), #define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 7c5cead..22e053a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -998,6 +998,11 @@ voidify_wrapper_expr (tree wrapper, tree temp) case STATEMENT_LIST: { tree_stmt_iterator i = tsi_last (*p); + if (TREE_CODE(*tsi_stmt_ptr (i)) == STATEMENT_LIST_END) + { + tsi_delink(&i); + i = tsi_last (*p); + } TREE_SIDE_EFFECTS (*p) = 1; TREE_TYPE (*p) = void_type_node; p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i); @@ -10722,6 +10727,19 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, end of gimplify_expr. */ input_location = UNKNOWN_LOCATION; eval = cleanup = NULL; + location_t finally_loc = 0; + /* The cleanup location can be extracted from STATEMENT_LIST_END + location added especially for this purpose. */ + if (TREE_OPERAND (*expr_p, 0) && + TREE_CODE (TREE_OPERAND (*expr_p, 0)) == STATEMENT_LIST) + { + const tree_statement_list_node* last_node = + STATEMENT_LIST_TAIL(TREE_OPERAND (*expr_p, 0)); + if (last_node && + last_node->stmt && + TREE_CODE (last_node->stmt) == STATEMENT_LIST_END) + finally_loc = EXPR_LOCATION(last_node->stmt); + } gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval); gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup); /* Don't create bogus GIMPLE_TRY with empty cleanup. */ @@ -10742,6 +10760,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (TREE_CODE (*expr_p) == TRY_CATCH_EXPR) gimple_try_set_catch_is_cleanup (try_, TRY_CATCH_IS_CLEANUP (*expr_p)); + + gimple *last_in_seq = gimple_seq_last_stmt (cleanup); + gimple_set_location(last_in_seq, finally_loc); + gimplify_seq_add_stmt (pre_p, try_); ret = GS_ALL_DONE; break; @@ -10803,6 +10825,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = gimplify_statement_list (expr_p, pre_p); break; + case STATEMENT_LIST_END: + ret = GS_ALL_DONE; + break; + case WITH_SIZE_EXPR: { gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3ae4c95..e631179 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-07-06 Vyacheslav Barinov + + * g++.dg/ext/statement-list-end.C: New. + 2017-04-13 Denis Khalikov PR sanitizer/80414 diff --git a/gcc/testsuite/g++.dg/ext/statement-list-end.C b/gcc/testsuite/g++.dg/ext/statement-list-end.C new file mode 100644 index 0000000..3381172 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/statement-list-end.C @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-fdump-tree-gimple-lineno" } */ +/* { dg-require-effective-target c++11 } */ + +#include +void i () +{ + std::unique_ptr c(new char); +} + +/* { dg-final { scan-tree-dump "9:1] std::unique_ptr::~unique_ptr" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gcov/gcov-2.C b/gcc/testsuite/g++.dg/gcov/gcov-2.C index 6d002f5..2b4cdd8 100644 --- a/gcc/testsuite/g++.dg/gcov/gcov-2.C +++ b/gcc/testsuite/g++.dg/gcov/gcov-2.C @@ -20,9 +20,9 @@ private: void foo() { - C c; /* count(2) */ + C c; /* count(1) */ c.seti (1); /* count(1) */ -} +} /* count(1) */ int main() { diff --git a/gcc/testsuite/g++.dg/parse/error26.C b/gcc/testsuite/g++.dg/parse/error26.C index 1084e76..0897339 100644 --- a/gcc/testsuite/g++.dg/parse/error26.C +++ b/gcc/testsuite/g++.dg/parse/error26.C @@ -4,11 +4,11 @@ void foo() { if (({int c[2];})) ; // { dg-error "7:ISO C.. forbids" "7" } - // { dg-error "17:could not convert" "17" { target *-*-* } 6 } + // { dg-error "18:could not convert" "18" { target *-*-* } .-1 } } void bar() { if (({})); // { dg-error "7:ISO C.. forbids" "7" } - // { dg-error "11:could not convert" "11" { target *-*-* } 12 } + // { dg-error "11:could not convert" "11" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/g++.dg/tm/inherit2.C b/gcc/testsuite/g++.dg/tm/inherit2.C index 3b696a9..366f9b3 100644 --- a/gcc/testsuite/g++.dg/tm/inherit2.C +++ b/gcc/testsuite/g++.dg/tm/inherit2.C @@ -26,8 +26,8 @@ int main() B b; // ok D1 d1; // ok B& b1 = d1; - D2 x; // { dg-error "" "destructor of D2 is not transaction-safe" } + D2 x; b1.f(); // ok, calls D1::f() delete b2; // undefined behavior: calls unsafe destructor of D2 - } + } // { dg-error "" "destructor of D2 is not transaction-safe" } } diff --git a/gcc/testsuite/g++.dg/tm/unsafe1.C b/gcc/testsuite/g++.dg/tm/unsafe1.C index 91dd7b1..e86b1bd 100644 --- a/gcc/testsuite/g++.dg/tm/unsafe1.C +++ b/gcc/testsuite/g++.dg/tm/unsafe1.C @@ -5,8 +5,8 @@ struct S { virtual ~S(); }; int f() transaction_safe { - S s; // { dg-error "unsafe" "invocation of unsafe destructor" } -} + S s; +} // { dg-error "unsafe" "invocation of unsafe destructor" } int g(int x) { // is transaction-safe if (x <= 0) diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index db72156..7b6932c 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1134,10 +1134,16 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) gimple_stmt_iterator gsi; tree finally_label; location_t loc = gimple_location (tf->try_finally_expr); + location_t finally_loc; finally = gimple_try_cleanup (tf->top_p); tf->top_p_seq = gimple_try_eval (tf->top_p); + /* The location of the finally is either the last stmt in the finally + block or the location of the TRY_FINALLY itself. */ + x = gimple_seq_last_stmt (finally); + finally_loc = x ? gimple_location (x) : loc; + /* Since there's only one destination, and the destination edge can only either be EH or non-EH, that implies that all of our incoming edges are of the same type. Therefore we can lower EH_ELSE immediately. */ @@ -1158,7 +1164,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION) { tree block = gimple_block (stmt); - gimple_set_location (stmt, gimple_location (tf->try_finally_expr)); + gimple_set_location (stmt, finally_loc); gimple_set_block (stmt, block); } } @@ -1181,7 +1187,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) return; } - finally_label = create_artificial_label (loc); + finally_label = create_artificial_label (finally_loc); label_stmt = gimple_build_label (finally_label); gimple_seq_add_stmt (&tf->top_p_seq, label_stmt); @@ -1413,11 +1419,12 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) x = gimple_build_assign (finally_tmp, build_int_cst (integer_type_node, fallthru_index)); + gimple_set_location (x, finally_loc); gimple_seq_add_stmt (&tf->top_p_seq, x); tmp = build_int_cst (integer_type_node, fallthru_index); last_case = build_case_label (tmp, NULL, - create_artificial_label (tf_loc)); + create_artificial_label (finally_loc)); case_label_vec.quick_push (last_case); last_case_index++; @@ -1426,7 +1433,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) tmp = lower_try_finally_fallthru_label (tf); x = gimple_build_goto (tmp); - gimple_set_location (x, tf_loc); + gimple_set_location (x, finally_loc); gimple_seq_add_stmt (&switch_body, x); } diff --git a/gcc/tree.c b/gcc/tree.c index 7ce14c9..8dbaadd 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -470,6 +470,7 @@ tree_node_structure_for_code (enum tree_code code) case SSA_NAME: return TS_SSA_NAME; case PLACEHOLDER_EXPR: return TS_COMMON; case STATEMENT_LIST: return TS_STATEMENT_LIST; + case STATEMENT_LIST_END: return TS_COMMON; case BLOCK: return TS_BLOCK; case CONSTRUCTOR: return TS_CONSTRUCTOR; case TREE_BINFO: return TS_BINFO; @@ -825,6 +826,7 @@ tree_code_size (enum tree_code code) case TREE_LIST: return sizeof (struct tree_list); case ERROR_MARK: + case STATEMENT_LIST_END: case PLACEHOLDER_EXPR: return sizeof (struct tree_common); case TREE_VEC: diff --git a/gcc/tree.def b/gcc/tree.def index 44130d7..20adf2e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -976,6 +976,10 @@ DEFTREECODE (POLYNOMIAL_CHREC, "polynomial_chrec", tcc_expression, 3) Use the interface in tree-iterator.h to access this node. */ DEFTREECODE (STATEMENT_LIST, "statement_list", tcc_exceptional, 0) +/* Used to keep STATEMENT_LIST end location. + The only useful field is location, which points to the closing brace. */ +DEFTREECODE (STATEMENT_LIST_END, "statement_list_end", tcc_expression, 0) + /* Predicate assertion. Artificial expression generated by the optimizers to keep track of predicate values. This expression may only appear on the RHS of assignments. -- 2.7.4