Skip to content

Commit 71bfdd1

Browse files
authored
[Clang] Add support for the C _Defer TS (#162848)
This implements WG14 N3734 (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3734.pdf), aka `_Defer`; it is currently only supported in C if `-fdefer-ts` is passed.
1 parent 3b04094 commit 71bfdd1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1667
-8
lines changed

clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
237237
return false;
238238
return true;
239239
}
240+
case Stmt::DeferStmtClass: {
241+
const auto *DefStmt1 = cast<DeferStmt>(Stmt1);
242+
const auto *DefStmt2 = cast<DeferStmt>(Stmt2);
243+
return isIdenticalStmt(Ctx, DefStmt1->getBody(), DefStmt2->getBody(),
244+
IgnoreSideEffects);
245+
}
240246
case Stmt::CompoundStmtClass: {
241247
const auto *CompStmt1 = cast<CompoundStmt>(Stmt1);
242248
const auto *CompStmt2 = cast<CompoundStmt>(Stmt2);

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ Resolutions to C++ Defect Reports
208208
C Language Changes
209209
------------------
210210

211+
- Implemented the ``defer`` draft Technical Specification
212+
(`WG14 N3734 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3734.pdf>`_); it is enabled in C mode by
213+
passing ``-fdefer-ts``. Note, the details of this feature are subject to change given that the Technical
214+
Specification is not yet ratified.
215+
211216
C2y Feature Support
212217
^^^^^^^^^^^^^^^^^^^
213218
- No longer triggering ``-Wstatic-in-inline`` in C2y mode; use of a static

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,6 +2561,7 @@ DEF_TRAVERSE_STMT(DefaultStmt, {})
25612561
DEF_TRAVERSE_STMT(DoStmt, {})
25622562
DEF_TRAVERSE_STMT(ForStmt, {})
25632563
DEF_TRAVERSE_STMT(GotoStmt, {})
2564+
DEF_TRAVERSE_STMT(DeferStmt, {})
25642565
DEF_TRAVERSE_STMT(IfStmt, {})
25652566
DEF_TRAVERSE_STMT(IndirectGotoStmt, {})
25662567
DEF_TRAVERSE_STMT(LabelStmt, {})

clang/include/clang/AST/Stmt.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,16 @@ class alignas(void *) Stmt {
317317
SourceLocation KeywordLoc;
318318
};
319319

320+
class DeferStmtBitfields {
321+
friend class DeferStmt;
322+
323+
LLVM_PREFERRED_TYPE(StmtBitfields)
324+
unsigned : NumStmtBits;
325+
326+
/// The location of the "defer".
327+
SourceLocation DeferLoc;
328+
};
329+
320330
//===--- Expression bitfields classes ---===//
321331

322332
class ExprBitfields {
@@ -1318,6 +1328,7 @@ class alignas(void *) Stmt {
13181328
LoopControlStmtBitfields LoopControlStmtBits;
13191329
ReturnStmtBitfields ReturnStmtBits;
13201330
SwitchCaseBitfields SwitchCaseBits;
1331+
DeferStmtBitfields DeferStmtBits;
13211332

13221333
// Expressions
13231334
ExprBitfields ExprBits;
@@ -3211,6 +3222,47 @@ class ReturnStmt final
32113222
}
32123223
};
32133224

3225+
/// DeferStmt - This represents a deferred statement.
3226+
class DeferStmt : public Stmt {
3227+
friend class ASTStmtReader;
3228+
3229+
/// The deferred statement.
3230+
Stmt *Body;
3231+
3232+
DeferStmt(EmptyShell Empty);
3233+
DeferStmt(SourceLocation DeferLoc, Stmt *Body);
3234+
3235+
public:
3236+
static DeferStmt *CreateEmpty(ASTContext &Context, EmptyShell Empty);
3237+
static DeferStmt *Create(ASTContext &Context, SourceLocation DeferLoc,
3238+
Stmt *Body);
3239+
3240+
SourceLocation getDeferLoc() const { return DeferStmtBits.DeferLoc; }
3241+
void setDeferLoc(SourceLocation DeferLoc) {
3242+
DeferStmtBits.DeferLoc = DeferLoc;
3243+
}
3244+
3245+
Stmt *getBody() { return Body; }
3246+
const Stmt *getBody() const { return Body; }
3247+
void setBody(Stmt *S) {
3248+
assert(S && "defer body must not be null");
3249+
Body = S;
3250+
}
3251+
3252+
SourceLocation getBeginLoc() const { return getDeferLoc(); }
3253+
SourceLocation getEndLoc() const { return Body->getEndLoc(); }
3254+
3255+
child_range children() { return child_range(&Body, &Body + 1); }
3256+
3257+
const_child_range children() const {
3258+
return const_child_range(&Body, &Body + 1);
3259+
}
3260+
3261+
static bool classof(const Stmt *S) {
3262+
return S->getStmtClass() == DeferStmtClass;
3263+
}
3264+
};
3265+
32143266
/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
32153267
class AsmStmt : public Stmt {
32163268
protected:

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ def err_address_of_label_outside_fn : Error<
350350
"use of address-of-label extension outside of a function body">;
351351
def err_asm_operand_wide_string_literal : Error<
352352
"cannot use %select{unicode|wide}0 string literal in 'asm'">;
353+
def err_defer_ts_labeled_stmt : Error<
354+
"substatement of defer must not be a label">;
353355

354356
def err_asm_expected_string : Error<
355357
"expected string literal %select{or parenthesized constant expression |}0in 'asm'">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6848,6 +6848,7 @@ def note_protected_by_objc_weak_init : Note<
68486848
"jump bypasses initialization of __weak variable">;
68496849
def note_protected_by_non_trivial_c_struct_init : Note<
68506850
"jump bypasses initialization of variable of non-trivial C struct type">;
6851+
def note_protected_by_defer_stmt : Note<"jump bypasses defer statement">;
68516852
def note_enters_block_captures_cxx_obj : Note<
68526853
"jump enters lifetime of block which captures a destructible C++ object">;
68536854
def note_enters_block_captures_strong : Note<
@@ -6861,6 +6862,7 @@ def note_enters_compound_literal_scope : Note<
68616862
"jump enters lifetime of a compound literal that is non-trivial to destruct">;
68626863
def note_enters_statement_expression : Note<
68636864
"jump enters a statement expression">;
6865+
def note_enters_defer_stmt : Note<"jump enters a defer statement">;
68646866

68656867
def note_exits_cleanup : Note<
68666868
"jump exits scope of variable with __attribute__((cleanup))">;
@@ -6906,6 +6908,16 @@ def note_exits_block_captures_non_trivial_c_struct : Note<
69066908
"to destroy">;
69076909
def note_exits_compound_literal_scope : Note<
69086910
"jump exits lifetime of a compound literal that is non-trivial to destruct">;
6911+
def note_exits_defer_stmt : Note<"jump exits a defer statement">;
6912+
def err_jump_out_of_defer_stmt : Error<
6913+
"cannot %enum_select<DeferJumpKind>{"
6914+
"%Break{break out of a}|"
6915+
"%Continue{continue loop outside of enclosing}|"
6916+
"%Return{return from a}|"
6917+
"%SEHLeave{__leave a}"
6918+
"}0 defer statement">;
6919+
def err_defer_invalid_sjlj : Error<
6920+
"cannot use %0 inside a defer statement">;
69096921

69106922
def err_func_returning_qualified_void : ExtWarn<
69116923
"function cannot return qualified void type %0">,
@@ -11020,6 +11032,8 @@ def err_switch_explicit_conversion : Error<
1102011032
def err_switch_incomplete_class_type : Error<
1102111033
"switch condition has incomplete class type %0">;
1102211034

11035+
// TODO: It ought to be possible to refactor these to be a single warning that
11036+
// uses %enum_select.
1102311037
def warn_empty_if_body : Warning<
1102411038
"if statement has empty body">, InGroup<EmptyBody>;
1102511039
def warn_empty_for_body : Warning<
@@ -11030,6 +11044,8 @@ def warn_empty_while_body : Warning<
1103011044
"while loop has empty body">, InGroup<EmptyBody>;
1103111045
def warn_empty_switch_body : Warning<
1103211046
"switch statement has empty body">, InGroup<EmptyBody>;
11047+
def warn_empty_defer_body : Warning<
11048+
"defer statement has empty body">, InGroup<EmptyBody>;
1103311049
def note_empty_body_on_separate_line : Note<
1103411050
"put the semicolon on a separate line to silence this warning">;
1103511051

clang/include/clang/Basic/IdentifierTable.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ enum TokenKey : unsigned {
7777
KEYNOZOS = 0x4000000,
7878
KEYHLSL = 0x8000000,
7979
KEYFIXEDPOINT = 0x10000000,
80-
KEYMAX = KEYFIXEDPOINT, // The maximum key
80+
KEYDEFERTS = 0x20000000,
81+
KEYMAX = KEYDEFERTS, // The maximum key
8182
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
8283
KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
8384
~KEYNOZOS // KEYNOMS18, KEYNOOPENCL, KEYNOZOS are excluded.

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ LANGOPT(NoSignedZero , 1, 0, Benign, "Permit Floating Point optimization wi
194194
LANGOPT(AllowRecip , 1, 0, Benign, "Permit Floating Point reciprocal")
195195
LANGOPT(ApproxFunc , 1, 0, Benign, "Permit Floating Point approximation")
196196
LANGOPT(NamedLoops , 1, 0, Benign, "Permit named break/continue")
197+
LANGOPT(DeferTS , 1, 0, Benign, "C '_Defer' Technical Specification")
197198

198199
ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 3, CX_None, NotCompatible, "Enable use of range reduction for complex arithmetics.")
199200

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def ForStmt : StmtNode<Stmt>;
1717
def GotoStmt : StmtNode<Stmt>;
1818
def IndirectGotoStmt : StmtNode<Stmt>;
1919
def ReturnStmt : StmtNode<Stmt>;
20+
def DeferStmt : StmtNode<Stmt>;
2021
def DeclStmt : StmtNode<Stmt>;
2122
def SwitchCase : StmtNode<Stmt, 1>;
2223
def CaseStmt : StmtNode<SwitchCase>;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
293293
// CHAR8SUPPORT - This is a keyword if 'char8_t' is a built-in type
294294
// KEYFIXEDPOINT - This is a keyword according to the N1169 fixed point
295295
// extension.
296+
// KEYDEFERTS - This is a keyword if the C '_Defer' TS is enabled
296297
// KEYZOS - This is a keyword in C/C++ on z/OS
297298
//
298299
KEYWORD(auto , KEYALL)
@@ -441,6 +442,9 @@ KEYWORD(_Float16 , KEYALL)
441442
C23_KEYWORD(typeof , KEYGNU)
442443
C23_KEYWORD(typeof_unqual , 0)
443444

445+
// '_Defer' TS
446+
KEYWORD(_Defer , KEYDEFERTS)
447+
444448
// ISO/IEC JTC1 SC22 WG14 N1169 Extension
445449
KEYWORD(_Accum , KEYFIXEDPOINT)
446450
KEYWORD(_Fract , KEYFIXEDPOINT)

0 commit comments

Comments
 (0)