Same behaviour as v6, _Defer as a c extension matchin clang's
implementation, but addressing pinksia's review on v5.
navi (3):
c: handle expression nodes in push_cleanup
c: introduce jump barriers for statement expressions
c: implement defer
gcc/Makefile.in | 1 +
gcc/c-family/c-common.cc | 1 +
gcc/c-family/c-common.h | 1 +
gcc/c-family/c-cppbuiltin.cc | 3 +
gcc/c/c-decl.cc | 190 ++++++++++++++++--------
gcc/c/c-parser.cc | 39 +++++
gcc/c/c-tree.h | 8 +-
gcc/c/c-typeck.cc | 60 ++++++--
gcc/ginclude/stddefer.h | 38 +++++
gcc/testsuite/gcc.dg/defer-1.c | 256 +++++++++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/defer-2.c | 78 ++++++++++
gcc/testsuite/gcc.dg/defer-3.c | 17 +++
gcc/testsuite/gcc.dg/defer-4.c | 8 ++
13 files changed, 629 insertions(+), 71 deletions(-)
create mode 100644 gcc/ginclude/stddefer.h
create mode 100644 gcc/testsuite/gcc.dg/defer-1.c
create mode 100644 gcc/testsuite/gcc.dg/defer-2.c
create mode 100644 gcc/testsuite/gcc.dg/defer-3.c
create mode 100644 gcc/testsuite/gcc.dg/defer-4.c
Range-diff against v6:
-: ----------- > 1: 3aecc7ff96a c: handle expression nodes in push_cleanup
1: edcbef53584 ! 2: 3383d769fb2 c: introduce jump barriers for statement
expressions
@@ gcc/c/c-decl.cc: set_spot_bindings (struct c_spot_bindings *p, bool
defining)
/* Update spot bindings P as we pop out of SCOPE. Return true if we
@@ gcc/c/c-decl.cc: finish_underspecified_init (tree name, unsigned int
prev_state)
+ in_underspecified_init = (prev_state & (1u << 1)) >> 1;
+ }
- /* Adjust the bindings for the start of a statement expression. */
-
+-/* Adjust the bindings for the start of a statement expression. */
++
++/* Push or pop the jump barrier count of a statement expression. */
++
+static void
+c_binding_adjust_jump_barrier (struct c_spot_bindings *binding, bool
start)
+{
-+ struct c_jump_barrier *barrier = &binding->stmt_exprs;
-+ barrier->count += start ? 1 : -1;
++ struct c_jump_barrier *barrier = defer
++ ? &binding->defer_blocks
++ : &binding->stmt_exprs;
++
++ if (start)
++ barrier->count++;
++ else
++ barrier->count--;
++
+ if (barrier->count < 0)
+ {
+ barrier->count = 0;
@@ gcc/c/c-decl.cc: finish_underspecified_init (tree name, unsigned int
prev_state)
+ }
+}
+
++/* Adjust the bindings for the start of a statement expression or defer
block. */
+
void
c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings)
- {
@@ gcc/c/c-decl.cc: c_bindings_start_stmt_expr (struct c_spot_bindings*
switch_bindings)
if (TREE_CODE (b->decl) != LABEL_DECL)
continue;
@@ gcc/c/c-decl.cc: c_bindings_start_stmt_expr (struct c_spot_bindings*
switch_bind
+ c_binding_adjust_jump_barrier (switch_bindings, true);
}
- /* Adjust the bindings for the end of a statement expression. */
+-/* Adjust the bindings for the end of a statement expression. */
++/* Adjust the bindings for the end of a statement expression or defer
block. */
+
+ void
+ c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings)
@@ gcc/c/c-decl.cc: c_bindings_end_stmt_expr (struct c_spot_bindings
*switch_bindings)
if (TREE_CODE (b->decl) != LABEL_DECL)
continue;
2: 476d6e8e0d2 ! 3: c43bf8c8fce c: implement defer
@@ Commit message
gcc/ChangeLog:
* Makefile.in:
- * doc/invoke.texi:
* ginclude/stddefer.h: New file.
gcc/c-family/ChangeLog:
@@ gcc/c-family/c-common.cc: const struct c_common_resword
c_common_reswords[] =
## gcc/c-family/c-common.h ##
@@ gcc/c-family/c-common.h: enum rid
- RID_BUILTIN_HAS_ATTRIBUTE, RID_BUILTIN_ASSOC_BARRIER,
RID_BUILTIN_STDC,
- RID_BUILTIN_COUNTED_BY_REF,
+ RID_BUILTIN_COUNTED_BY_REF, RID_BUILTIN_BSWAPG,
+ RID_BUILTIN_BITREVERSEG,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, RID_DFLOAT64X,
+ RID_DEFER,
@@ gcc/c/c-decl.cc: struct GTY(()) c_spot_bindings {
@@ gcc/c/c-decl.cc: struct GTY((chain_next ("%h.outer"))) c_scope {
decl_jump_unsafe would return true for any of the bindings. This
is used to avoid looping over all the bindings unnecessarily. */
- BOOL_BITFIELD has_jump_unsafe_decl : 1;
+ bool has_jump_unsafe_decl : 1;
+
+ /* True if this scope has any deferred statement. This is used to
+ * check invalid goto jumps. */
-+ BOOL_BITFIELD has_defer_block : 1;
++ bool has_defer_block : 1;
};
/* The scope currently in effect. */
@@ gcc/c/c-decl.cc: set_spot_bindings (struct c_spot_bindings *p, bool
defining)
/* Update spot bindings P as we pop out of SCOPE. Return true if we
@@ gcc/c/c-decl.cc: finish_underspecified_init (tree name, unsigned int
prev_state)
- /* Adjust the bindings for the start of a statement expression. */
+ }
+
+
+-/* Push or pop the jump barrier count of a statement expression. */
++/* Push or pop the jump barrier count of a statement expression or defer
block. */
static void
-c_binding_adjust_jump_barrier (struct c_spot_bindings *binding, bool
start)
+c_binding_adjust_jump_barrier (struct c_spot_bindings *binding,
+ bool defer, bool start)
{
-- struct c_jump_barrier *barrier = &binding->stmt_exprs;
-+ struct c_jump_barrier *barrier = defer
-+ ? &binding->defer_blocks
-+ : &binding->stmt_exprs;
- barrier->count += start ? 1 : -1;
- if (barrier->count < 0)
- {
+ struct c_jump_barrier *barrier = defer
+ ? &binding->defer_blocks
@@ gcc/c/c-decl.cc: c_binding_adjust_jump_barrier (struct c_spot_bindings
*binding, bool start)
- }
+ /* Adjust the bindings for the start of a statement expression or defer
block. */
void
-c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings)
@@ gcc/c/c-decl.cc: c_bindings_start_stmt_expr (struct c_spot_bindings*
switch_bind
+ }
}
- /* Adjust the bindings for the end of a statement expression. */
+ /* Adjust the bindings for the end of a statement expression or defer
block. */
void
-c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings)
@@ gcc/c/c-typeck.cc: c_finish_stmt_expr (location_t loc, tree body)
}
-
+
++/* Starts a new deferred block to be executed on scope exit. */
++
+tree
+c_begin_defer_block (void)
+{
@@ gcc/c/c-typeck.cc: c_finish_stmt_expr (location_t loc, tree body)
+ return c_begin_compound_stmt (true);
+}
+
++/* Ends a deferred block. */
++
+tree
+c_end_defer_block (location_t loc, tree body)
+{
--
2.54.0