Hi,

This is the third (and final) patch which extends the original change proposal, submitted on June 1, and titled "Add 'force-dwarf-lexical-blocks' command line option".

This patch extends the proposed functionality to C++.

Attached are the proposed ChangeLog additions (for this patch only), named according to the directory each one belongs to.

All check-c and check-c++ tests have been run for unix target.
The testsuites showed identical results, with and without setting the proposed -fforce-dwarf-lexical-blocks command line option.

Please let me know, if the proposed additions will be accepted.

Best regards,
Andrei Herman
Mentor Graphics Corporation
Israel branch
>From 824e75eb563e82c04fe1621c64430d87cdb0f348 Mon Sep 17 00:00:00 2001
From: Andrei Herman <andrei_her...@codesourcery.com>
Date: Tue, 17 Jun 2014 17:59:07 +0300
Subject: [PATCH 3/3]         Support flag_force_dwarf_blocks in C++.

        * c-semantics.c (push_block_info): Allow BIND_EXPR for STATEMENT_LIST.

        * cp-objcp-common.c (cxx_block_may_fallthru): Return false for break
        or continue, when flag_force_dwarf_blocks.

        * cp-tree.h (pop_scope_for_labels): New.

        * name-lookup.c (keep_current_level): New.
        (kept_level_p): When flag_force_dwarf_blocks, avoid creating duplicate
        blocks.

        * name-lookup.h (keep_current_level): New.

        * parser.c (cp_parser_statement): Add last_label and pass it when
        calling cp_parser_label_for_labeled_statement, to create a label scope
        for the first label of a statement.  Close forced scopes at current
        level, after labeled compound statements that don't fall through.
        (cp_parser_force_block_for_label): New.
        (pop_scope_for_labels): New.
        (cp_parser_label_for_labeled_statement): Add parameter.  Create a label
        scope for the first label of a statement.
        (cp_parser_compound_statement): Force a block for compound statement.
        (cp_parser_implicitly_scoped_statement): Likewise for if-then, if-else,
        switch and do statements.
        (cp_parser_already_scoped_statement): Likewise for for/while bodies.

        * semantics.c (do_poplevel): Close any forced scopes in given level.
        (build_data_member_initialization): Allow BIND_EXP.

Signed-off-by: Andrei Herman <andrei_her...@codesourcery.com>
---
 gcc/c-family/c-semantics.c |   11 ++++-
 gcc/cp/cp-objcp-common.c   |    5 ++
 gcc/cp/cp-tree.h           |    1 +
 gcc/cp/name-lookup.c       |   12 +++++-
 gcc/cp/name-lookup.h       |    1 +
 gcc/cp/parser.c            |  104 ++++++++++++++++++++++++++++++++++++++++----
 gcc/cp/semantics.c         |    5 ++
 7 files changed, 127 insertions(+), 12 deletions(-)

diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index ec3045f..8c8497f 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -35,8 +35,15 @@ along with GCC; see the file COPYING3.  If not see
 void
 push_block_info (tree block, location_t loc, bool is_label)
 {
-  if (TREE_CODE(block) != STATEMENT_LIST)
+  switch (TREE_CODE (block)) {
+  case BIND_EXPR:
+    block = BIND_EXPR_BODY (block);
+    /* Fall through.  */
+  case STATEMENT_LIST:
+    break;
+  default:
     return;
+  }
 
   block_loc tl;
   tl = (block_loc) ggc_internal_cleared_alloc (sizeof(struct block_loc_s));
@@ -70,7 +77,7 @@ check_pop_block_info(tree block, location_t loc)
       if (block == cur_block_info->block && loc == cur_block_info->loc
           && !cur_block_info->is_label)
         {
-          block_list_stack->pop();
+          block_list_stack->pop ();
         }
     }
 }
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 78dddef..fcfd959 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -238,6 +238,11 @@ cxx_block_may_fallthru (const_tree stmt)
       return false;
 
     default:
+      if (flag_force_dwarf_blocks) {
+        if (TREE_CODE (stmt) == BREAK_STMT ||
+            TREE_CODE (stmt) == CONTINUE_STMT)
+          return false;
+      }
       return true;
     }
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7d29c2c..4953ad9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5501,6 +5501,7 @@ extern bool maybe_clone_body                      (tree);
 extern tree cp_convert_range_for (tree, tree, tree, bool);
 extern bool parsing_nsdmi (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
+extern void pop_scope_for_labels (tree);
 
 /* in pt.c */
 extern bool check_template_shadow              (tree);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 2baeeb7..5538c63 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -1745,7 +1745,8 @@ local_bindings_p (void)
 bool
 kept_level_p (void)
 {
-  return (current_binding_level->blocks != NULL_TREE
+  return ((!flag_force_dwarf_blocks
+           && current_binding_level->blocks != NULL_TREE)
          || current_binding_level->keep
          || current_binding_level->kind == sk_cleanup
          || current_binding_level->names != NULL_TREE
@@ -1778,6 +1779,15 @@ keep_next_level (bool keep)
   keep_next_level_flag = keep;
 }
 
+/* Same as keep_next_level, but works on the current (already
+   created) binding level. */
+
+void
+keep_current_level (bool keep)
+{
+  current_binding_level->keep = keep;
+}
+
 /* Return the list of declarations of the current level.
    Note that this list is in reverse order unless/until
    you nreverse it; and when you do nreverse it, you must
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 40e0338..058a6fc 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -303,6 +303,7 @@ extern void push_to_top_level (void);
 extern void pop_from_top_level (void);
 extern void pop_everything (void);
 extern void keep_next_level (bool);
+extern void keep_current_level (bool);
 extern bool is_ancestor (tree, tree);
 extern tree push_scope (tree);
 extern void pop_scope (tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c4440af..439db55 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1978,7 +1978,7 @@ static void cp_parser_lambda_body
 static void cp_parser_statement
   (cp_parser *, tree, bool, bool *);
 static void cp_parser_label_for_labeled_statement
-(cp_parser *, tree);
+  (cp_parser *, tree, bool);
 static tree cp_parser_expression_statement
   (cp_parser *, tree);
 static tree cp_parser_compound_statement
@@ -9341,6 +9341,7 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
   tree statement, std_attrs = NULL_TREE;
   cp_token *token;
   location_t statement_location, attrs_location;
+  bool label_last = false;
 
  restart:
   if (if_p != NULL)
@@ -9379,7 +9380,8 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
          /* Looks like a labeled-statement with a case label.
             Parse the label, and then use tail recursion to parse
             the statement.  */
-         cp_parser_label_for_labeled_statement (parser, std_attrs);
+         cp_parser_label_for_labeled_statement (parser, std_attrs, label_last);
+          label_last = true;
          goto restart;
 
        case RID_IF:
@@ -9461,13 +9463,22 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
             Parse the label, and then use tail recursion to parse
             the statement.  */
 
-         cp_parser_label_for_labeled_statement (parser, std_attrs);
+         cp_parser_label_for_labeled_statement (parser, std_attrs, label_last);
+          label_last = true;
          goto restart;
        }
     }
   /* Anything that starts with a `{' must be a compound-statement.  */
   else if (token->type == CPP_OPEN_BRACE)
-    statement = cp_parser_compound_statement (parser, NULL, false, false);
+    {
+      statement = cp_parser_compound_statement (parser, NULL, false, false);
+      /* When a label is followed by a compound-statement which does
+         not fall-through (ends with some form of 'jump' statement),
+         close the forced scope(s) at current level.  */
+      if (flag_force_dwarf_blocks && label_last
+          && !block_may_fallthru (statement))
+        pop_scope_for_labels (0);
+    }
   /* CPP_PRAGMA is a #pragma inside a function body, which constitutes
      a statement all its own.  */
   else if (token->type == CPP_PRAGMA)
@@ -9480,7 +9491,10 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
       if (in_compound)
        cp_parser_pragma (parser, pragma_compound);
       else if (!cp_parser_pragma (parser, pragma_stmt))
-       goto restart;
+        {
+          label_last = false;
+          goto restart;
+        }
       return;
     }
   else if (token->type == CPP_EOF)
@@ -9528,6 +9542,54 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
                "attributes at the beginning of statement are ignored");
 }
 
+/* Force creation of a new scope for a label.  If not followed by a compound
+   statement, make it a block (otherwise, the compound statement will create
+   the block).  Push the created scope onto the block_info stack, so we can
+   identify it as a label scope.  */
+
+static void
+cp_parser_force_block_for_label (cp_parser* parser, tree label)
+{
+  if (!flag_force_dwarf_blocks
+      || label == NULL_TREE || label == error_mark_node)
+    return;
+
+  if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+    keep_next_level (true);
+  tree block = begin_compound_stmt (0);
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  push_block_info (block, loc, true);
+}
+
+/* If current scope is a label scope, pop it from block info stack
+   and close it's compound statement.  When called from do_poplevel, a target
+   STMT_LIST may differ from the current statement list.  This may happen at
+   the end of a scope in which some cleanups may have been left behind.
+   These will be removed here.  */
+
+void
+pop_scope_for_labels (tree stmt_list)
+{
+  while (block_list_stack && !block_list_stack->is_empty ())
+    {
+      if (cur_stmt_list == cur_block_info->block && cur_block_info->is_label)
+        {
+          location_t loc;
+          tree block = pop_block_info (loc);
+          finish_compound_stmt (block);
+        }
+      else
+        /* In case we are looking for a target scope,
+           remove outstanding cleanups.  */
+        if (stmt_list && stmt_list != cur_stmt_list)
+          {
+            add_stmt (pop_stmt_list (cur_stmt_list));
+          }
+        else
+          break;
+    }
+}
+
 /* Parse the label for a labeled-statement, i.e.
 
    identifier :
@@ -9542,10 +9604,12 @@ cp_parser_statement (cp_parser* parser, tree 
in_statement_expr,
    have to return the label.  */
 
 static void
-cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
+cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes,
+                                       bool label_last)
 {
   cp_token *token;
   tree label = NULL_TREE;
+  tree case_label = NULL_TREE;
   bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
 
   /* The next token should be an identifier.  */
@@ -9588,7 +9652,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, 
tree attributes)
          expr_hi = NULL_TREE;
 
        if (parser->in_switch_statement_p)
-         finish_case_label (token->location, expr, expr_hi);
+          case_label = finish_case_label (token->location, expr, expr_hi);
        else
          error_at (token->location,
                    "case label %qE not within a switch statement",
@@ -9601,14 +9665,14 @@ cp_parser_label_for_labeled_statement (cp_parser* 
parser, tree attributes)
       cp_lexer_consume_token (parser->lexer);
 
       if (parser->in_switch_statement_p)
-       finish_case_label (token->location, NULL_TREE, NULL_TREE);
+       case_label = finish_case_label (token->location, NULL_TREE, NULL_TREE);
       else
        error_at (token->location, "case label not within a switch statement");
       break;
 
     default:
       /* Anything else must be an ordinary label.  */
-      label = finish_label_stmt (cp_parser_identifier (parser));
+      case_label = label = finish_label_stmt (cp_parser_identifier (parser));
       break;
     }
 
@@ -9639,6 +9703,19 @@ cp_parser_label_for_labeled_statement (cp_parser* 
parser, tree attributes)
   if (attributes != NULL_TREE)
     cplus_decl_attributes (&label, attributes, 0);
 
+  if (flag_force_dwarf_blocks && case_label)
+    {
+      if (!label_last)
+        cp_parser_force_block_for_label (parser, case_label);
+      else
+        /* The first label may not have seen the open brace
+           and therefor set the keep flag in current scope.
+           If we see it now, we should clear the flag, as the
+           next compound statement will create the block.  */
+        if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+          keep_current_level (false);
+    }
+
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
 }
 
@@ -9734,6 +9811,8 @@ cp_parser_compound_statement (cp_parser *parser, tree 
in_statement_expr,
     pedwarn (input_location, OPT_Wpedantic,
             "compound-statement in constexpr function");
   /* Begin the compound-statement.  */
+  if (flag_force_dwarf_blocks)
+    keep_next_level (true);
   compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
   /* If the next keyword is `__label__' we have a label declaration.  */
   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL))
@@ -10757,6 +10836,9 @@ cp_parser_jump_statement (cp_parser* parser)
       break;
     }
 
+  if (flag_force_dwarf_blocks)
+    pop_scope_for_labels (0);
+
   return statement;
 }
 
@@ -10818,6 +10900,8 @@ cp_parser_implicitly_scoped_statement (cp_parser* 
parser, bool *if_p)
   else
     {
       /* Create a compound-statement.  */
+      if (flag_force_dwarf_blocks)
+        keep_next_level (true);
       statement = begin_compound_stmt (0);
       /* Parse the dependent-statement.  */
       cp_parser_statement (parser, NULL_TREE, false, if_p);
@@ -10837,6 +10921,8 @@ cp_parser_implicitly_scoped_statement (cp_parser* 
parser, bool *if_p)
 static void
 cp_parser_already_scoped_statement (cp_parser* parser)
 {
+  if (flag_force_dwarf_blocks)
+    keep_current_level (true);
   /* If the token is a `{', then we must take special action.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
     cp_parser_statement (parser, NULL_TREE, false, NULL);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index edab330..1cee21a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -451,6 +451,9 @@ do_poplevel (tree stmt_list)
 {
   tree block = NULL;
 
+  if (flag_force_dwarf_blocks && stmts_are_full_exprs_p ())
+    pop_scope_for_labels (stmt_list);
+
   if (stmts_are_full_exprs_p ())
     block = poplevel (kept_level_p (), 1, 0);
 
@@ -7585,6 +7588,8 @@ build_data_member_initialization (tree t, 
vec<constructor_elt, va_gc> **vec)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == EXPR_STMT)
     t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == BIND_EXPR)
+    t = BIND_EXPR_BODY (t);
   if (t == error_mark_node)
     return false;
   if (TREE_CODE (t) == STATEMENT_LIST)
-- 
1.7.1

2014-06-17  Andrei Herman  <andrei_her...@codesourcery.com>

        * c-semantics.c (push_block_info): Allow BIND_EXPR for STATEMENT_LIST.
2014-06-17  Andrei Herman  <andrei_her...@codesourcery.com>

        * cp-tree.h (pop_scope_for_labels): New.

        * parser.c (cp_parser_statement): Add last_label and pass it when
        calling cp_parser_label_for_labeled_statement, to create a label scope
        for the first label of a statement.  Close forced scopes at current
        level, after labeled compound statements that don't fall through.
        (cp_parser_force_block_for_label): New.
        (pop_scope_for_labels): New.
        (cp_parser_label_for_labeled_statement): Add parameter.  Create a label
        scope for the first label of a statement.
        (cp_parser_compound_statement): Force a block for compound statement.
        (cp_parser_implicitly_scoped_statement): Likewise for if-then, if-else,
        switch and do statements.
        (cp_parser_already_scoped_statement): Likewise for for/while bodies.

        * semantics.c (do_poplevel): Close any forced scopes in given level.
        (build_data_member_initialization): Allow BIND_EXP.

        * name-lookup.h (keep_current_level): New.

        * name-lookup.c (keep_current_level): New.
        (kept_level_p): When flag_force_dwarf_blocks, avoid creating duplicate
        blocks.

        * cp-objcp-common.c (cxx_block_may_fallthru): Return false for break
        or continue, when flag_force_dwarf_blocks.

Reply via email to