Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
02b4dd0
[AArch64] Restrict TBI to ignore top 4 bits for Darwin targets.
aemerson Nov 21, 2025
6dafa09
Add a _regexp-break-add and some more tests for the b alias. (#171236)
jimingham Dec 11, 2025
3abaed8
[TableGen] Replace reachable assertion with error in *ByHwMode
arichardson Dec 11, 2025
c5470e0
[RISC-V][MC] Fix tied operand register class mismatch in P-extension
arichardson Dec 11, 2025
62aaa3a
[compiler-rt] follow-up to 166837, rename COMPILER_RT_FORCE_TEST_BUIL…
w2yehia Dec 11, 2025
16e6055
Revert "[SelectionDAG] Salvage debuginfo when combining load and sext…
rastogishubham Dec 11, 2025
ba73d60
[RISCV] Use sew and vec_policy for Rivos vector instruction operands.…
topperc Dec 11, 2025
76ae530
[PPC] XFAIL ppc/fixtfti_test.c and ppc/fixunstfti_test.c and track th…
Dec 11, 2025
1f07f7c
[flang][cuda] Add support for allocate with device source (#171743)
clementval Dec 11, 2025
3fdce79
[libunwind] fix building on Haiku i386 (#171586)
brad0 Dec 11, 2025
2614af0
[Tooling] Fix misleading progress report when files have multiple com…
zeyi2 Dec 11, 2025
fa92475
[RISCV] Add an OperandType for ordering for atomic pseudos. (#171744)
topperc Dec 11, 2025
18b6137
[NFC] isOSGlibc: musl is not glibc. (#171734)
hvdijk Dec 11, 2025
e795b8b
[RISCV] Use GPR instead of ixlenimm for sextshamt in PseudoMaskedAMOM…
topperc Dec 11, 2025
3b04094
[RISCV] Add Xsfmm vlte and vste intrinsics to getTgtMemIntrinsics. (#…
topperc Dec 11, 2025
71bfdd1
[Clang] Add support for the C `_Defer` TS (#162848)
Sirraide Dec 11, 2025
426cedc
[LoongArch] Add support for the ud macro instruction (#171583)
heiher Dec 11, 2025
4f9d5a8
[RISCV] Generate Xqcilsm LWMI/SWMI load/store multiple instructions (…
svs-quic Dec 11, 2025
cb4b6ad
[CIR] Add the ability to detect if SwitchOp covers all the cases (#17…
badumbatish Dec 11, 2025
4882029
[ValueTracking] Enhance overflow computation for unsigned mul (#171568)
Adar-Dagan Dec 11, 2025
c9648d7
[Verifier] Make sure all constexprs in instructions are visited (#171…
nikic Dec 11, 2025
6a25e45
[ConstantFolding] Support ptrtoaddr in ConstantFoldCompareInstOperand…
nikic Dec 11, 2025
39a723e
[Linalg] Add *Conv2D* matchers (#168362)
Abhishek-Varma Dec 11, 2025
2ce17ba
[InstCombine][CmpInstAnalysis] Use consistent spelling and function n…
wermos Dec 11, 2025
aa31efc
[libclc] use clc functions in clspv/shared/vstore_half.cl (#171770)
rjodinchr Dec 11, 2025
b7c0452
[PowerPC][AIX] Specify correct ABI alignment for double (#144673)
nikic Dec 11, 2025
6ad0c7c
[NFC][RISCV] Unify all zvfbfa vl patterns and sd node patterns (#171072)
4vtomat Dec 11, 2025
794551d
[RISCV][llvm] Support PSRA, PSRAI, PSRL, PSRLI codegen for P extensio…
4vtomat Dec 11, 2025
f57abf5
[SPIRV] Promote scalar arguments to vector for `OpExtInst` in `genera…
jmmartinez Dec 11, 2025
15df9e7
[AMDGPU][SDAG] Add missing cases for SI_INDIRECT_SRC/DST (#170323)
jmmartinez Dec 11, 2025
2c1decb
[libc++] Don't instantiate __split_buffer with an allocator reference…
ldionne Dec 11, 2025
db06ebb
[AArch64][NFC] Add isTRNMask improvements to isZIPMask (#171532)
ginsbach Dec 11, 2025
59b13d6
[libc++] Add `__find_end` optimizations back (#171374)
philnik777 Dec 11, 2025
6573f62
[X86] LowerATOMIC_STORE - on 32-bit targets see if i64 values were or…
RKSimon Dec 11, 2025
4d335cb
[AArch64] Fix scheduling info for Armv8.4-a LDAPUR* instructions (#17…
c-rhodes Dec 11, 2025
df6c27e
[libc++] Make std::allocator always trivially default constructible (…
philnik777 Dec 11, 2025
57cf1ff
[libc++] Remove initializer_list specific optimization in __tree (#16…
philnik777 Dec 11, 2025
d15ff59
[libc++] Merge the segmented iterator code for {copy,move}_backward (…
philnik777 Dec 11, 2025
86f8445
[LifetimeSafety] Infer [[clang::lifetimebound]] annotation (#171081)
kashika0112 Dec 11, 2025
33fcfb3
[flang][TBAA] refine TARGET/POINTER encoding (#170908)
tblah Dec 11, 2025
c029788
Revert "[AMDGPU][SDAG] Add missing cases for SI_INDIRECT_SRC/DST (#17…
jmmartinez Dec 11, 2025
0b522d9
Revert "[lldb] fix failing tests due to CI diagnostics rendering (#17…
charles-zablit Dec 11, 2025
4f5071f
InstCombine: Add baseline test for #64697 fmul reassociation (#171725)
arsenm Dec 11, 2025
f8d1f53
[mlir][scf] Add value bound for computed upper bound of forall loop (…
Groverkss Dec 11, 2025
8af88a4
[MLIR][NVVM] Update PMEvent lowering to intrinsics (#171649)
durga4github Dec 11, 2025
fbc121c
[BOLT][BTI] Add MCPlusBuilder::insertBTI (#167329)
bgergely0 Dec 11, 2025
481ce81
IR: Stop requiring nsz to reassociate fmul (#171726)
arsenm Dec 11, 2025
d0767e9
[JITLink] Add TLS support for SystemZ (#171559)
anoopkg6 Dec 11, 2025
c89d87a
[lldb][test] Fix toolchain-msvc.test for native ARM64 MSVC environmen…
omjavaid Dec 11, 2025
10845d2
merge main into amd-staging
z1-cciauto Dec 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions bolt/include/bolt/Core/MCPlusBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,19 @@ class MCPlusBuilder {
llvm_unreachable("not implemented");
}

/// Checks if the indirect call / jump is accepted by the landing pad at the
/// start of the target BasicBlock.
virtual bool isCallCoveredByBTI(MCInst &Call, MCInst &Pad) const {
llvm_unreachable("not implemented");
return false;
}

/// Inserts a BTI landing pad to the start of the BB, that matches the
/// indirect call inst used to call the BB.
virtual void insertBTI(BinaryBasicBlock &BB, MCInst &Call) const {
llvm_unreachable("not implemented");
}

/// Store \p Target absolute address to \p RegName
virtual InstructionListType materializeAddress(const MCSymbol *Target,
MCContext *Ctx,
Expand Down
75 changes: 75 additions & 0 deletions bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2806,6 +2806,81 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
Inst.addOperand(MCOperand::createImm(HintNum));
}

bool isCallCoveredByBTI(MCInst &Call, MCInst &Pad) const override {
assert((isIndirectCall(Call) || isIndirectBranch(Call)) &&
"Not an indirect call or branch.");

// A BLR can be accepted by a BTI c.
if (isIndirectCall(Call))
return isBTILandingPad(Pad, true, false) ||
isBTILandingPad(Pad, true, true);

// A BR can be accepted by a BTI j or BTI c (and BTI jc) IF the operand is
// x16 or x17. If the operand is not x16 or x17, it can be accepted by a BTI
// j or BTI jc (and not BTI c).
if (isIndirectBranch(Call)) {
assert(Call.getNumOperands() == 1 &&
"Indirect branch needs to have 1 operand.");
assert(Call.getOperand(0).isReg() &&
"Indirect branch does not have a register operand.");
MCPhysReg Reg = Call.getOperand(0).getReg();
if (Reg == AArch64::X16 || Reg == AArch64::X17)
return isBTILandingPad(Pad, true, false) ||
isBTILandingPad(Pad, false, true) ||
isBTILandingPad(Pad, true, true);
return isBTILandingPad(Pad, false, true) ||
isBTILandingPad(Pad, true, true);
}
return false;
}

void insertBTI(BinaryBasicBlock &BB, MCInst &Call) const override {
auto II = BB.getFirstNonPseudo();
// Only check the first instruction for non-empty BasicBlocks
bool Empty = (II == BB.end());
if (!Empty && isCallCoveredByBTI(Call, *II))
return;
// A BLR can be accepted by a BTI c.
if (isIndirectCall(Call)) {
// if we have a BTI j at the start, extend it to a BTI jc,
// otherwise insert a new BTI c.
if (!Empty && isBTILandingPad(*II, false, true)) {
updateBTIVariant(*II, true, true);
} else {
MCInst BTIInst;
createBTI(BTIInst, true, false);
BB.insertInstruction(II, BTIInst);
}
}

// A BR can be accepted by a BTI j or BTI c (and BTI jc) IF the operand is
// x16 or x17. If the operand is not x16 or x17, it can be accepted by a
// BTI j or BTI jc (and not BTI c).
if (isIndirectBranch(Call)) {
assert(Call.getNumOperands() == 1 &&
"Indirect branch needs to have 1 operand.");
assert(Call.getOperand(0).isReg() &&
"Indirect branch does not have a register operand.");
MCPhysReg Reg = Call.getOperand(0).getReg();
if (Reg == AArch64::X16 || Reg == AArch64::X17) {
// Add a new BTI c
MCInst BTIInst;
createBTI(BTIInst, true, false);
BB.insertInstruction(II, BTIInst);
} else {
// If BB starts with a BTI c, extend it to BTI jc,
// otherwise insert a new BTI j.
if (!Empty && isBTILandingPad(*II, true, false)) {
updateBTIVariant(*II, true, true);
} else {
MCInst BTIInst;
createBTI(BTIInst, false, true);
BB.insertInstruction(II, BTIInst);
}
}
}
}

InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,
MCPhysReg RegName,
int64_t Addend = 0) const override {
Expand Down
116 changes: 116 additions & 0 deletions bolt/unittests/Core/MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,122 @@ TEST_P(MCPlusBuilderTester, AArch64_BTI) {
ASSERT_TRUE(BC->MIB->isImplicitBTIC(*II));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_empty) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X16);
BC->MIB->insertBTI(*BB, CallInst);
// Check that BTI c is added to the empty block.
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, false));
}
TEST_P(MCPlusBuilderTester, AArch64_insertBTI_0) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst Inst = MCInstBuilder(AArch64::RET).addReg(AArch64::LR);
BB->addInstruction(Inst);
// BR x16 needs BTI c or BTI j. We prefer adding a BTI c.
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X16);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, false));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_1) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst BTIc;
BC->MIB->createBTI(BTIc, true, false);
BB->addInstruction(BTIc);
// BR x16 needs BTI c or BTI j. We have a BTI c, no change is needed.
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X16);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, false));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_2) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst BTIc;
BC->MIB->createBTI(BTIc, true, false);
BB->addInstruction(BTIc);
// BR x5 needs BTI j
// we have BTI c -> extend it to BTI jc.
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X5);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, true));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_3) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst Inst = MCInstBuilder(AArch64::RET).addReg(AArch64::LR);
BB->addInstruction(Inst);
// BR x5 needs BTI j
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X5);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, false, true));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_4) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst Inst = MCInstBuilder(AArch64::RET).addReg(AArch64::LR);
BB->addInstruction(Inst);
// BLR needs BTI c, regardless of the register used.
MCInst CallInst = MCInstBuilder(AArch64::BLR).addReg(AArch64::X5);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, false));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_5) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst BTIj;
BC->MIB->createBTI(BTIj, false, true);
BB->addInstruction(BTIj);
// BLR needs BTI c, regardless of the register used.
// We have a BTI j -> extend it to BTI jc.
MCInst CallInst = MCInstBuilder(AArch64::BLR).addReg(AArch64::X5);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, true));
}

TEST_P(MCPlusBuilderTester, AArch64_insertBTI_6) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst Paciasp =
MCInstBuilder(AArch64::PACIASP).addReg(AArch64::LR).addReg(AArch64::SP);
BB->addInstruction(Paciasp);
// PACI(AB)SP are implicit BTI c, no change needed.
MCInst CallInst = MCInstBuilder(AArch64::BR).addReg(AArch64::X17);
BC->MIB->insertBTI(*BB, CallInst);
auto II = BB->begin();
ASSERT_TRUE(BC->MIB->isBTILandingPad(*II, true, false));
ASSERT_TRUE(BC->MIB->isPSignOnLR(*II));
}

TEST_P(MCPlusBuilderTester, AArch64_CmpJNE) {
if (GetParam() != Triple::aarch64)
GTEST_SKIP();
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
return false;
return true;
}
case Stmt::DeferStmtClass: {
const auto *DefStmt1 = cast<DeferStmt>(Stmt1);
const auto *DefStmt2 = cast<DeferStmt>(Stmt2);
return isIdenticalStmt(Ctx, DefStmt1->getBody(), DefStmt2->getBody(),
IgnoreSideEffects);
}
case Stmt::CompoundStmtClass: {
const auto *CompStmt1 = cast<CompoundStmt>(Stmt1);
const auto *CompStmt2 = cast<CompoundStmt>(Stmt2);
Expand Down
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ Resolutions to C++ Defect Reports
C Language Changes
------------------

- Implemented the ``defer`` draft Technical Specification
(`WG14 N3734 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3734.pdf>`_); it is enabled in C mode by
passing ``-fdefer-ts``. Note, the details of this feature are subject to change given that the Technical
Specification is not yet ratified.

C2y Feature Support
^^^^^^^^^^^^^^^^^^^
- No longer triggering ``-Wstatic-in-inline`` in C2y mode; use of a static
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2561,6 +2561,7 @@ DEF_TRAVERSE_STMT(DefaultStmt, {})
DEF_TRAVERSE_STMT(DoStmt, {})
DEF_TRAVERSE_STMT(ForStmt, {})
DEF_TRAVERSE_STMT(GotoStmt, {})
DEF_TRAVERSE_STMT(DeferStmt, {})
DEF_TRAVERSE_STMT(IfStmt, {})
DEF_TRAVERSE_STMT(IndirectGotoStmt, {})
DEF_TRAVERSE_STMT(LabelStmt, {})
Expand Down
52 changes: 52 additions & 0 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@ class alignas(void *) Stmt {
SourceLocation KeywordLoc;
};

class DeferStmtBitfields {
friend class DeferStmt;

LLVM_PREFERRED_TYPE(StmtBitfields)
unsigned : NumStmtBits;

/// The location of the "defer".
SourceLocation DeferLoc;
};

//===--- Expression bitfields classes ---===//

class ExprBitfields {
Expand Down Expand Up @@ -1318,6 +1328,7 @@ class alignas(void *) Stmt {
LoopControlStmtBitfields LoopControlStmtBits;
ReturnStmtBitfields ReturnStmtBits;
SwitchCaseBitfields SwitchCaseBits;
DeferStmtBitfields DeferStmtBits;

// Expressions
ExprBitfields ExprBits;
Expand Down Expand Up @@ -3211,6 +3222,47 @@ class ReturnStmt final
}
};

/// DeferStmt - This represents a deferred statement.
class DeferStmt : public Stmt {
friend class ASTStmtReader;

/// The deferred statement.
Stmt *Body;

DeferStmt(EmptyShell Empty);
DeferStmt(SourceLocation DeferLoc, Stmt *Body);

public:
static DeferStmt *CreateEmpty(ASTContext &Context, EmptyShell Empty);
static DeferStmt *Create(ASTContext &Context, SourceLocation DeferLoc,
Stmt *Body);

SourceLocation getDeferLoc() const { return DeferStmtBits.DeferLoc; }
void setDeferLoc(SourceLocation DeferLoc) {
DeferStmtBits.DeferLoc = DeferLoc;
}

Stmt *getBody() { return Body; }
const Stmt *getBody() const { return Body; }
void setBody(Stmt *S) {
assert(S && "defer body must not be null");
Body = S;
}

SourceLocation getBeginLoc() const { return getDeferLoc(); }
SourceLocation getEndLoc() const { return Body->getEndLoc(); }

child_range children() { return child_range(&Body, &Body + 1); }

const_child_range children() const {
return const_child_range(&Body, &Body + 1);
}

static bool classof(const Stmt *S) {
return S->getStmtClass() == DeferStmtClass;
}
};

/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
class AsmStmt : public Stmt {
protected:
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ def err_address_of_label_outside_fn : Error<
"use of address-of-label extension outside of a function body">;
def err_asm_operand_wide_string_literal : Error<
"cannot use %select{unicode|wide}0 string literal in 'asm'">;
def err_defer_ts_labeled_stmt : Error<
"substatement of defer must not be a label">;

def err_asm_expected_string : Error<
"expected string literal %select{or parenthesized constant expression |}0in 'asm'">;
Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -6844,6 +6844,7 @@ def note_protected_by_objc_weak_init : Note<
"jump bypasses initialization of __weak variable">;
def note_protected_by_non_trivial_c_struct_init : Note<
"jump bypasses initialization of variable of non-trivial C struct type">;
def note_protected_by_defer_stmt : Note<"jump bypasses defer statement">;
def note_enters_block_captures_cxx_obj : Note<
"jump enters lifetime of block which captures a destructible C++ object">;
def note_enters_block_captures_strong : Note<
Expand All @@ -6857,6 +6858,7 @@ def note_enters_compound_literal_scope : Note<
"jump enters lifetime of a compound literal that is non-trivial to destruct">;
def note_enters_statement_expression : Note<
"jump enters a statement expression">;
def note_enters_defer_stmt : Note<"jump enters a defer statement">;

def note_exits_cleanup : Note<
"jump exits scope of variable with __attribute__((cleanup))">;
Expand Down Expand Up @@ -6902,6 +6904,16 @@ def note_exits_block_captures_non_trivial_c_struct : Note<
"to destroy">;
def note_exits_compound_literal_scope : Note<
"jump exits lifetime of a compound literal that is non-trivial to destruct">;
def note_exits_defer_stmt : Note<"jump exits a defer statement">;
def err_jump_out_of_defer_stmt : Error<
"cannot %enum_select<DeferJumpKind>{"
"%Break{break out of a}|"
"%Continue{continue loop outside of enclosing}|"
"%Return{return from a}|"
"%SEHLeave{__leave a}"
"}0 defer statement">;
def err_defer_invalid_sjlj : Error<
"cannot use %0 inside a defer statement">;

def err_func_returning_qualified_void : ExtWarn<
"function cannot return qualified void type %0">,
Expand Down Expand Up @@ -11016,6 +11028,8 @@ def err_switch_explicit_conversion : Error<
def err_switch_incomplete_class_type : Error<
"switch condition has incomplete class type %0">;

// TODO: It ought to be possible to refactor these to be a single warning that
// uses %enum_select.
def warn_empty_if_body : Warning<
"if statement has empty body">, InGroup<EmptyBody>;
def warn_empty_for_body : Warning<
Expand All @@ -11026,6 +11040,8 @@ def warn_empty_while_body : Warning<
"while loop has empty body">, InGroup<EmptyBody>;
def warn_empty_switch_body : Warning<
"switch statement has empty body">, InGroup<EmptyBody>;
def warn_empty_defer_body : Warning<
"defer statement has empty body">, InGroup<EmptyBody>;
def note_empty_body_on_separate_line : Note<
"put the semicolon on a separate line to silence this warning">;

Expand Down
Loading