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
