based on n3734[1]

this feature mostly makes use of already-established logic, namely
push_cleanup used by the cleanup attribute, and the constraints put
in place for checking local jumps against statement expressions

the TS recommends providing 'defer' as a keyword alongside '_Defer',
however since clang is going to enable _Defer and stddefer.h for older c
standards by default as an extension, and i think we should too, i'm
unsure if having the -fdefer-ts flag has any benefit, as it would just
enable another spelling and nothing else, or did i missunderstand
anything that'd lead for it to be useful?

this time i've kept the changelog to the notes in patch 3/3 as it was
basically the same as here.

1: https://open-std.org/JTC1/SC22/WG14/www/docs/n3734.pdf

Anna (navi) Figueiredo Gomes (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                | 136 +++++++++++++-----
 gcc/c/c-parser.cc              |  39 +++++
 gcc/c/c-tree.h                 |   8 +-
 gcc/c/c-typeck.cc              |  56 ++++++--
 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, 594 insertions(+), 48 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 v5:
1:  da835e79572 ! 1:  0cef84aef53 c: handle expression nodes in push_cleanup
    @@ Commit message
     
         gcc/c/ChangeLog:
     
    -            * c-typeck.cc (push_cleanup): Adjust.
    +            * c-typeck.cc (push_cleanup): Handle EXPR_P nodes.
     
         Signed-off-by: Anna (navi) Figueiredo Gomes <[email protected]>
     
2:  b0fd9d8165a ! 2:  edcbef53584 c: introduce jump barriers for statement 
expressions
    @@ Commit message
         gcc/c/ChangeLog:
     
                 * c-decl.cc (struct c_jump_barrier): New structure.
    -            (struct c_spot_bindings): Adjust.
    -            (set_spot_bindings): Likewise.
    +            (struct c_spot_bindings): Extract out members to struct 
c_jump_barrier.
    +            (set_spot_bindings): Adjust member access for c_jump_barrier.
                 (c_binding_adjust_jump_barrier): New function.
    -            (c_bindings_start_stmt_expr): Adjust.
    +            (c_bindings_start_stmt_expr): Call 
c_binding_adjust_jump_barrier.
                 (c_bindings_end_stmt_expr): Likewise.
    -            (lookup_label_for_goto): Likewise.
    +            (lookup_label_for_goto): Adjust member access for 
c_jump_barrier.
                 (check_earlier_gotos): Likewise.
                 (c_release_switch_bindings): Likewise.
                 (c_check_switch_jump_warnings): Likewise.
3:  113bd001f17 ! 3:  476d6e8e0d2 c: implement the defer keyword
    @@ Metadata
     Author: Anna (navi) Figueiredo Gomes <[email protected]>
     
      ## Commit message ##
    -    c: implement the defer keyword
    +    c: implement defer
     
    -    based on the technical specification n3589[1], and set behind the
    -    command line flag '-fdefer-ts'
    +    based on the technical specification 25755[1] as an extension
    +
    +    _Defer is provided as a keyword if gnu extensions are enabled, and
    +    stddefer.h provided a macro for the 'defer' spelling
     
         deferred statements execute at the end of the scope they're added on,
         similar to the cleanup attribute, and they have much of the same
    @@ Commit message
         local jump shall jump over a defer statement, nor shall return, break,
         and continue, jump out of one
     
    -    1: https://open-std.org/JTC1/SC22/WG14/www/docs/n3589.pdf
    +    1: https://open-std.org/JTC1/SC22/WG14/www/docs/n3734.pdf
     
         gcc/ChangeLog:
     
    -            * doc/invoke.texi: Add -fdefer-ts documentation.
    -            * doc/standards.texi: Likewise.
    +            * Makefile.in:
    +            * doc/invoke.texi:
    +            * ginclude/stddefer.h: New file.
     
         gcc/c-family/ChangeLog:
     
    -            * c-common.cc: Add defer keyword.
    +            * c-common.cc: Add _Defer keywords.
                 * c-common.h (enum rid): Add RID_DEFER.
    -            (D_CXX11): Adjust.
    -            (D_EXT): Likewise.
    -            (D_EXT89): Likewise.
    -            (D_EXT11): Likewise.
    -            (D_ASM): Likewise.
    -            (D_OBJC): Likewise.
    -            (D_CXX_OBJC): Likewise.
    -            (D_CXXWARN): Likewise.
    -            (D_CXX_CONCEPTS): Likewise.
    -            (D_TRANSMEM): Likewise.
    -            (D_CXX_CHAR8_T): Likewise.
    -            (D_CXX20): Likewise.
    -            (D_CXX_COROUTINES): Likewise.
    -            (D_CXX_MODULES): Likewise.
    -            (D_DEFER): Add defer keyword mask.
                 * c-cppbuiltin.cc (c_cpp_builtins): Set __STDC_DEFER_TS25755__.
    -            * c.opt: Add -fdefer-ts flag.
     
         gcc/c/ChangeLog:
     
                 * c-decl.cc (struct c_spot_bindings): Add defer_blocks.
                 (struct c_scope): Add has_defer_block flag.
                 (set_spot_bindings): Clear defer_blocks.
    -            (c_binding_adjust_jump_barrier): Adjust for defer.
    +            (c_binding_adjust_jump_barrier): Handle deferred blocks.
                 (c_bindings_start_stmt_expr): Rename to 
c_bindings_start_jump_barrier.
    -            (c_bindings_start_jump_barrier): Adjust for defer.
    +            (c_bindings_start_jump_barrier): Handle deferred statements.
                 (c_bindings_end_stmt_expr): Rename to 
c_bindings_end_jump_barrier.
    -            (c_bindings_end_jump_barrier): Adjust for defer.
    +            (c_bindings_end_jump_barrier): Handle deferred statements.
                 (lookup_label_for_goto): Check defer contraints.
                 (check_earlier_gotos): Likewise.
                 (c_release_switch_bindings): Likewise.
    @@ Commit message
                 (c_bindings_end_jump_barrier): New function.
                 (c_begin_defer_block): New function.
                 (c_end_defer_block): New function.
    -            * c-typeck.cc (c_finish_return): Adjust.
    -            (c_finish_bc_stmt): Adjust.
    +            * c-typeck.cc (c_finish_return):
    +            (c_finish_bc_stmt): Check for IN_DEFER_STMT.
                 (c_begin_stmt_expr): Likewise.
                 (c_finish_stmt_expr): Likewise.
                 (c_begin_defer_block): New function.
    @@ Commit message
     
         Signed-off-by: Anna (navi) Figueiredo Gomes <[email protected]>
     
    +
    + ## Notes ##
    +    v6:
    +     * remove -fdefer-ts flag and 'defer' as a keyword
    +     * add stddefer.h containing a defer -> _Defer macro
    +    v5:
    +     * enable '_Defer' keyword when extensions are enabled
    +    v4:
    +     * remove constraint on local backwards jump, making behaviour the same
    +    as the cleanup attribute.
    +    v3:
    +     * remove the need of -std=c2y for -fdefer-ts to take effect
    +    v2:
    +     * added a test jumping into a defer block from above.
    +     * reworded the lookup_label_for_goto error message to mention the 
error
    +    is a jump into the defer block, instead of out.
    +     * moved the 'defer' keyword behind a -fdefer-ts flag, and added 
texinfo
    +    docs plus related failure test.
    +
    + ## gcc/Makefile.in ##
    +@@ gcc/Makefile.in: USER_H = $(srcdir)/ginclude/float.h \
    +    $(srcdir)/ginclude/stdatomic.h \
    +    $(srcdir)/ginclude/stdckdint.h \
    +    $(srcdir)/ginclude/stdcountof.h \
    ++   $(srcdir)/ginclude/stddefer.h \
    +    $(EXTRA_HEADERS)
    + 
    + USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
    +
      ## gcc/c-family/c-common.cc ##
     @@ gcc/c-family/c-common.cc: const struct c_common_resword 
c_common_reswords[] =
    -   { "continue",           RID_CONTINUE,   0 },
    -   { "decltype",         RID_DECLTYPE,   D_CXXONLY | D_CXX11 | D_CXXWARN },
    -   { "default",            RID_DEFAULT,    0 },
    -+  { "defer",              RID_DEFER,      D_DEFER | D_CONLY },
    -   { "delete",             RID_DELETE,     D_CXXONLY | D_CXXWARN },
    -   { "do",         RID_DO,         0 },
    -   { "double",             RID_DOUBLE,     0 },
    +   { "_Decimal64",       RID_DFLOAT64,  D_CONLY },
    +   { "_Decimal128",      RID_DFLOAT128, D_CONLY },
    +   { "_Decimal64x",      RID_DFLOAT64X, D_CONLY },
    ++  { "_Defer",           RID_DEFER,     D_CONLY | D_EXT },
    +   { "_Fract",           RID_FRACT,     D_CONLY | D_EXT },
    +   { "_Accum",           RID_ACCUM,     D_CONLY | D_EXT },
    +   { "_Sat",             RID_SAT,       D_CONLY | D_EXT },
     
      ## gcc/c-family/c-common.h ##
     @@ gcc/c-family/c-common.h: enum rid
    @@ gcc/c-family/c-common.h: enum rid
      
        /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
        RID_FLOAT16,
    -@@ gcc/c-family/c-common.h: extern machine_mode c_default_pointer_mode;
    - #define D_CXX20           0x8000  /* In C++, C++20 only.  */
    - #define D_CXX_COROUTINES 0x10000  /* In C++, only with coroutines.  */
    - #define D_CXX_MODULES     0x20000  /* In C++, only with modules.  */
    -+#define D_DEFER           0x40000 /* In C, only with -fdefer-ts */
    - 
    - #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
    - #define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
     
      ## gcc/c-family/c-cppbuiltin.cc ##
     @@ gcc/c-family/c-cppbuiltin.cc: c_cpp_builtins (cpp_reader *pfile)
        if (flag_iso)
          cpp_define (pfile, "__STRICT_ANSI__");
      
    -+  if (flag_defer_ts)
    ++  if (!flag_no_gnu_keywords)
     +    builtin_define_with_int_value ("__STDC_DEFER_TS25755__", 1);
     +
        if (!flag_signed_char)
          cpp_define (pfile, "__CHAR_UNSIGNED__");
      
     
    - ## gcc/c-family/c.opt ##
    -@@ gcc/c-family/c.opt: fdefault-inline
    - C++ ObjC++ Ignore
    - Does nothing.  Preserved for backward compatibility.
    - 
    -+fdefer-ts
    -+C Var(flag_defer_ts)
    -+Enables support for defer statements from ISO/DIS TS 25755 for ISO C2Y
    -+
    - fdiagnostics-show-template-tree
    - C++ ObjC++ Var(flag_diagnostics_show_template_tree) Init(0)
    - Print hierarchical comparisons when template types are mismatched.
    -
      ## gcc/c/c-decl.cc ##
     @@ gcc/c/c-decl.cc: struct GTY(()) c_spot_bindings {
           of the label or goto.  This lets us look at older or newer
    @@ gcc/c/c-decl.cc: c_check_switch_jump_warnings (struct c_spot_bindings 
*switch_bi
      
     
      ## gcc/c/c-parser.cc ##
    -@@ gcc/c/c-parser.cc: c_parse_init (void)
    -     mask |= D_C99;
    -   if (!flag_isoc23)
    -     mask |= D_C23;
    -+  if (!flag_defer_ts)
    -+    mask |= D_DEFER;
    -   if (flag_no_asm)
    -     {
    -       mask |= D_ASM | D_EXT;
     @@ gcc/c/c-parser.cc: static void c_parser_statement_after_labels 
(c_parser *, bool *, tree,
      static tree c_parser_c99_block_statement (c_parser *, bool *,
                                          location_t * = NULL);
    @@ gcc/c/c-typeck.cc: c_finish_stmt_expr (location_t loc, tree body)
         and popping new statement lists from the tree.  */
      
     
    - ## gcc/doc/invoke.texi ##
    -@@ gcc/doc/invoke.texi: in the following sections.
    - -fpermitted-flt-eval-methods=@var{standard}
    - -fplan9-extensions  -fsigned-bitfields  -funsigned-bitfields
    - -fsigned-char  -funsigned-char  -fstrict-flex-arrays[=@var{n}]
    ---fsso-struct=@var{endianness}}
    -+-fsso-struct=@var{endianness} -fdefer-ts}
    - 
    - @item C++ Language Options
    - @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
    -@@ gcc/doc/invoke.texi: the target (the default).  This option is not 
supported for C++.
    - @strong{Warning:} the @option{-fsso-struct} switch causes GCC to generate
    - code that is not binary compatible with code generated without it if the
    - specified endianness is not the native endianness of the target.
    -+
    -+@opindex fdefer-ts
    -+@item -fdefer-ts
    -+Enables support for the defer keyword, as specified by ISO/DIS TS 25755.
    - @end table
    - 
    - @node C++ Dialect Options
    -
    - ## gcc/doc/standards.texi ##
    -@@ gcc/doc/standards.texi: enabled with @option{-std=c23} or 
@option{-std=iso9899:2024}.
    - 
    - A further version of the C standard, known as @dfn{C2Y}, is under
    - development; experimental and incomplete support for this is enabled
    --with @option{-std=c2y}.
    -+with @option{-std=c2y}. GCC implements the defer technical specification,
    -+ISO/DIS TS 25755, enabled with @option{-fdefer-ts}.
    - 
    - By default, GCC provides some extensions to the C language that, on
    - rare occasions conflict with the C standard.  @xref{C
    + ## gcc/ginclude/stddefer.h (new) ##
    +@@
    ++/* Copyright (C) 1998-2025 Free Software Foundation, Inc.
    ++
    ++This file is part of GCC.
    ++
    ++GCC is free software; you can redistribute it and/or modify
    ++it under the terms of the GNU General Public License as published by
    ++the Free Software Foundation; either version 3, or (at your option)
    ++any later version.
    ++
    ++GCC is distributed in the hope that it will be useful,
    ++but WITHOUT ANY WARRANTY; without even the implied warranty of
    ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ++GNU General Public License for more details.
    ++
    ++Under Section 7 of GPL version 3, you are granted additional
    ++permissions described in the GCC Runtime Library Exception, version
    ++3.1, as published by the Free Software Foundation.
    ++
    ++You should have received a copy of the GNU General Public License and
    ++a copy of the GCC Runtime Library Exception along with this program;
    ++see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    ++<http://www.gnu.org/licenses/>.  */
    ++
    ++/*
    ++ * ISO C Standard:  7.16  Boolean type and values  <stddefer.h>
    ++ */
    ++
    ++#ifndef _STDDEFER_H_
    ++#define _STDDEFER_H_
    ++
    ++#ifndef __cplusplus
    ++
    ++#define __STDC_VERSION_STDDEFER_H__ 202602L
    ++#define defer     _Defer
    ++
    ++#endif /* __cplusplus */
    ++
    ++#endif    /* stddefer.h */
     
      ## gcc/testsuite/gcc.dg/defer-1.c (new) ##
     @@
     +/* { dg-do run } */
    -+/* { dg-options "-fdefer-ts" } */
    ++/* { dg-options "" } */
     +
    ++#include <stddefer.h>
     +#include <setjmp.h>
     +
     +#define assert(x) if (!(x)) __builtin_abort ()
     +
    -+#if __STDC_DEFER_TS25755__ != 1
    ++#if __STDC_DEFER_TS25755__ != 2
     +# error "missing defer flag"
     +#endif
     +
    @@ gcc/testsuite/gcc.dg/defer-1.c (new)
      ## gcc/testsuite/gcc.dg/defer-2.c (new) ##
     @@
     +/* { dg-do compile } */
    -+/* { dg-options "-fdefer-ts" } */
    ++/* { dg-options "-fdefer-kw" } */
    ++
    ++#include <stddefer.h>
     +
     +void a ()
     +{
    @@ gcc/testsuite/gcc.dg/defer-2.c (new)
      ## gcc/testsuite/gcc.dg/defer-3.c (new) ##
     @@
     +/* { dg-do run } */
    -+/* { dg-options "-fdefer-ts" } */
    ++/* { dg-options "" } */
    ++
    ++#include <stddefer.h>
     +
     +extern void exit(int);
     +extern void abort(void);
    @@ gcc/testsuite/gcc.dg/defer-3.c (new)
      ## gcc/testsuite/gcc.dg/defer-4.c (new) ##
     @@
     +/* { dg-do compile } */
    ++/* { dg-options "" } */
     +
     +int main(void)
     +{
    ++  _Defer;
     +  defer; /* { dg-error "'defer' undeclared" "undeclared identifier" } */
     +}
-- 
2.51.0

Reply via email to