Fix cleanup location for try_finally_expr. 59/138559/4
authorSlava Barinov <v.barinov@samsung.com>
Thu, 6 Jul 2017 13:14:58 +0000 (16:14 +0300)
committerSlava Barinov <v.barinov@samsung.com>
Thu, 3 Aug 2017 10:49:15 +0000 (13:49 +0300)
        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 <v.barinov@samsung.com>
20 files changed:
gcc/ChangeLog
gcc/c-family/c-semantics.c
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/constraint.cc
gcc/cp/error.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/fold-const.c
gcc/gimple.c
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/statement-list-end.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gcov/gcov-2.C
gcc/testsuite/g++.dg/parse/error26.C
gcc/testsuite/g++.dg/tm/inherit2.C
gcc/testsuite/g++.dg/tm/unsafe1.C
gcc/tree-eh.c
gcc/tree.c
gcc/tree.def

index 77528a5..8772afc 100644 (file)
@@ -1,3 +1,20 @@
+2017-07-06  Vyacheslav Barinov  <v.barinov@samsung.com>
+
+       * 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 <d.khalikov@partner.samsung.com>
 
         PR sanitizer/80414
index 4845a8b..bd4f379 100644 (file)
@@ -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.  */
index a7f94b3..3ccddab 100644 (file)
@@ -1,3 +1,10 @@
+2017-07-06  Vyacheslav Barinov  <v.barinov@samsung.com>
+
+       * 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  <jason@redhat.com>
 
        PR c++/79176 - lambda ICE with -flto -Os
index a6ac3c1..f9c4ead 100644 (file)
@@ -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;
 
index 09ae301..157f7dd 100644 (file)
@@ -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)
     {
index 93fe2ff..a852e71 100644 (file)
@@ -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, "({...})");
index 390f7d0..187fe0e 100644 (file)
@@ -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;
 }
 
index 744b461..db403c8 100644 (file)
@@ -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)));
 
index 9ef4951..46f1ac1 100644 (file)
@@ -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;
 }
 \f
 /* 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)
index b874c9f..9200a8b 100644 (file)
@@ -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,
 
index 7c5cead..22e053a 100644 (file)
@@ -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,
index 3ae4c95..e631179 100644 (file)
@@ -1,3 +1,7 @@
+2017-07-06  Vyacheslav Barinov  <v.barinov@samsung.com>
+
+       * g++.dg/ext/statement-list-end.C: New.
+
 2017-04-13  Denis Khalikov  <d.khalikov@partner.samsung.com>
 
         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 (file)
index 0000000..3381172
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple-lineno" } */
+/* { dg-require-effective-target c++11 } */
+
+#include <memory>
+void i ()
+{
+  std::unique_ptr<char> c(new char);
+}
+
+/* { dg-final { scan-tree-dump "9:1] std::unique_ptr<char>::~unique_ptr" "gimple" } } */
index 6d002f5..2b4cdd8 100644 (file)
@@ -20,9 +20,9 @@ private:
 
 void foo()
 {
-  C c;                                 /* count(2) */
+  C c;                                 /* count(1) */
   c.seti (1);                          /* count(1) */
-}
+}                                      /* count(1) */
 
 int main()
 {
index 1084e76..0897339 100644 (file)
@@ -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 }
 }
index 3b696a9..366f9b3 100644 (file)
@@ -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" }
 }
index 91dd7b1..e86b1bd 100644 (file)
@@ -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)
index db72156..7b6932c 100644 (file)
@@ -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);
     }
 
index 7ce14c9..8dbaadd 100644 (file)
@@ -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:
index 44130d7..20adf2e 100644 (file)
@@ -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.