summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Keane <erich.keane@intel.com>2019-05-30 15:38:02 +0000
committerErich Keane <erich.keane@intel.com>2019-05-30 15:38:02 +0000
commita85622d923a899272c7acbd19210ba2f7bb88ab9 (patch)
treecc34c8f4a412b46b55a0c8cd922d0ff50f8f95ad
parent3fe47eab4520a5fdfe3b83aa88ef6a9f46bc5330 (diff)
downloadclang-a85622d923a899272c7acbd19210ba2f7bb88ab9.tar.gz
Revert "clang support gnu asm goto."
This reverts commit 954ec09aed4f2be04bb5f4e10dbb4ea8bd19ef9a. Reverting due to test failures as requested by Jennifer Yu. Conflicts: clang/test/CodeGen/asm-goto.c git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362106 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Stmt.h51
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td10
-rw-r--r--include/clang/Sema/Sema.h1
-rw-r--r--lib/AST/ASTImporter.cpp10
-rw-r--r--lib/AST/Stmt.cpp29
-rw-r--r--lib/AST/StmtPrinter.cpp20
-rw-r--r--lib/AST/StmtProfile.cpp3
-rw-r--r--lib/Analysis/CFG.cpp74
-rw-r--r--lib/CodeGen/CGStmt.cpp126
-rw-r--r--lib/Parse/ParseStmtAsm.cpp68
-rw-r--r--lib/Sema/JumpDiagnostics.cpp114
-rw-r--r--lib/Sema/SemaStmtAsm.cpp48
-rw-r--r--lib/Sema/TreeTransform.h16
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp7
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp4
-rw-r--r--test/Analysis/asm-goto.cpp52
-rw-r--r--test/CodeGen/asm-goto.c19
-rw-r--r--test/CodeGen/asm.c12
-rw-r--r--test/CodeGen/inline-asm-mixed-style.c10
-rw-r--r--test/Coverage/c-language-features.inc4
-rw-r--r--test/PCH/asm.h6
-rw-r--r--test/Parser/asm.c50
-rw-r--r--test/Parser/asm.cpp51
-rw-r--r--test/Sema/asm-goto.cpp45
-rw-r--r--test/Sema/asm.c21
-rw-r--r--test/Sema/inline-asm-validate-tmpl.cpp10
-rw-r--r--test/Sema/scope-check.c16
28 files changed, 148 insertions, 733 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index fe5d802688..77b2173fcb 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -46,7 +46,6 @@ class Attr;
class CapturedDecl;
class Decl;
class Expr;
-class AddrLabelExpr;
class LabelDecl;
class ODRHash;
class PrinterHelper;
@@ -2817,15 +2816,13 @@ class GCCAsmStmt : public AsmStmt {
StringLiteral **Constraints = nullptr;
StringLiteral **Clobbers = nullptr;
IdentifierInfo **Names = nullptr;
- unsigned NumLabels = 0;
public:
GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
bool isvolatile, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, unsigned numlabels,
- SourceLocation rparenloc);
+ StringLiteral **clobbers, SourceLocation rparenloc);
/// Build an empty inline-assembly statement.
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {}
@@ -2950,51 +2947,6 @@ public:
return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
}
- //===--- Labels ---===//
-
- bool isAsmGoto() const {
- return NumLabels > 0;
- }
-
- unsigned getNumLabels() const {
- return NumLabels;
- }
-
- IdentifierInfo *getLabelIdentifier(unsigned i) const {
- return Names[i + NumInputs];
- }
-
- AddrLabelExpr *getLabelExpr(unsigned i) const;
- StringRef getLabelName(unsigned i) const;
- using labels_iterator = CastIterator<AddrLabelExpr>;
- using const_labels_iterator = ConstCastIterator<AddrLabelExpr>;
- using labels_range = llvm::iterator_range<labels_iterator>;
- using labels_const_range = llvm::iterator_range<const_labels_iterator>;
-
- labels_iterator begin_labels() {
- return &Exprs[0] + NumInputs;
- }
-
- labels_iterator end_labels() {
- return &Exprs[0] + NumInputs + NumLabels;
- }
-
- labels_range labels() {
- return labels_range(begin_labels(), end_labels());
- }
-
- const_labels_iterator begin_labels() const {
- return &Exprs[0] + NumInputs;
- }
-
- const_labels_iterator end_labels() const {
- return &Exprs[0] + NumInputs + NumLabels;
- }
-
- labels_const_range labels() const {
- return labels_const_range(begin_labels(), end_labels());
- }
-
private:
void setOutputsAndInputsAndClobbers(const ASTContext &C,
IdentifierInfo **Names,
@@ -3002,7 +2954,6 @@ private:
Stmt **Exprs,
unsigned NumOutputs,
unsigned NumInputs,
- unsigned NumLabels,
StringLiteral **Clobbers,
unsigned NumClobbers);
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 15a5ecf177..fb281a5be8 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -27,8 +27,8 @@ def err_msasm_unable_to_create_target : Error<
"MS-style inline assembly is not available: %0">;
def err_gnu_inline_asm_disabled : Error<
"GNU-style inline assembly is disabled">;
-def err_asm_goto_cannot_have_output : Error<
- "'asm goto' cannot have output constraints">;
+def err_asm_goto_not_supported_yet : Error<
+ "'asm goto' constructs are not supported yet">;
}
let CategoryName = "Parse Issue" in {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c5a7b93cec..1beb7fda9b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5070,12 +5070,12 @@ def warn_cxx98_compat_switch_into_protected_scope : Warning<
def err_indirect_goto_without_addrlabel : Error<
"indirect goto in function with no address-of-label expressions">;
def err_indirect_goto_in_protected_scope : Error<
- "cannot jump from this %select{indirect|asm}0 goto statement to one of its possible targets">;
+ "cannot jump from this indirect goto statement to one of its possible targets">;
def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning<
- "jump from this %select{indirect|asm}0 goto statement to one of its possible targets "
+ "jump from this indirect goto statement to one of its possible targets "
"is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def note_indirect_goto_target : Note<
- "possible target of %select{indirect|asm}0 goto statement">;
+ "possible target of indirect goto statement">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
def note_protected_by_variable_nontriv_destructor : Note<
@@ -7503,10 +7503,6 @@ let CategoryName = "Inline Assembly Issue" in {
"use constraint modifier \"%0\"">;
def note_asm_input_duplicate_first : Note<
"constraint '%0' is already present here">;
- def error_duplicate_asm_operand_name : Error<
- "duplicate use of asm operand name \"%0\"">;
- def note_duplicate_asm_operand_name : Note<
- "asm operand name \"%0\" first referenced here">;
}
def error_inoutput_conflict_with_clobber : Error<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index d25d7decf3..d7486ec1c2 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3971,7 +3971,6 @@ public:
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg Constraints, MultiExprArg Exprs,
Expr *AsmString, MultiExprArg Clobbers,
- unsigned NumLabels,
SourceLocation RParenLoc);
void FillInlineAsmIdentifierInfo(Expr *Res,
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 1f1ec1d687..2e4c304b3d 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -5592,17 +5592,12 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
return InputOrErr.takeError();
}
- SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() +
- S->getNumLabels());
+ SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs());
if (Error Err = ImportContainerChecked(S->outputs(), Exprs))
return std::move(Err);
- if (Error Err =
- ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs()))
- return std::move(Err);
-
if (Error Err = ImportArrayChecked(
- S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs()))
+ S->inputs(), Exprs.begin() + S->getNumOutputs()))
return std::move(Err);
ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc());
@@ -5628,7 +5623,6 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
*AsmStrOrErr,
S->getNumClobbers(),
Clobbers.data(),
- S->getNumLabels(),
*RParenLocOrErr);
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 0a4d403106..68a5a2d6ab 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -444,14 +444,6 @@ void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
Exprs[i + NumOutputs] = E;
}
-AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const {
- return cast<AddrLabelExpr>(Exprs[i + NumInputs]);
-}
-
-StringRef GCCAsmStmt::getLabelName(unsigned i) const {
- return getLabelExpr(i)->getLabel()->getName();
-}
-
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
@@ -464,16 +456,13 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
Stmt **Exprs,
unsigned NumOutputs,
unsigned NumInputs,
- unsigned NumLabels,
StringLiteral **Clobbers,
unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
this->NumClobbers = NumClobbers;
- this->NumLabels = NumLabels;
- assert(!(NumOutputs && NumLabels) && "asm goto cannot have outputs");
- unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
+ unsigned NumExprs = NumOutputs + NumInputs;
C.Deallocate(this->Names);
this->Names = new (C) IdentifierInfo*[NumExprs];
@@ -509,10 +498,6 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
if (getInputName(i) == SymbolicName)
return getNumOutputs() + NumPlusOperands + i;
- for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
- if (getLabelName(i) == SymbolicName)
- return i + getNumInputs();
-
// Not found.
return -1;
}
@@ -630,8 +615,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
while (CurPtr != StrEnd && isDigit(*CurPtr))
N = N*10 + ((*CurPtr++)-'0');
- unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
- getNumInputs() + getNumLabels();
+ unsigned NumOperands =
+ getNumOutputs() + getNumPlusOperands() + getNumInputs();
if (N >= NumOperands) {
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_operand_number;
@@ -744,12 +729,10 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
unsigned numinputs, IdentifierInfo **names,
StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, unsigned numlabels,
- SourceLocation rparenloc)
+ StringLiteral **clobbers, SourceLocation rparenloc)
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
- numinputs, numclobbers),
- RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
- unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
+ numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
+ unsigned NumExprs = NumOutputs + NumInputs;
Names = new (C) IdentifierInfo*[NumExprs];
std::copy(names, names + NumExprs, Names);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 563095f89b..7fe0be5217 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -414,15 +414,12 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
if (Node->isVolatile())
OS << "volatile ";
- if (Node->isAsmGoto())
- OS << "goto ";
-
OS << "(";
VisitStringLiteral(Node->getAsmString());
// Outputs
if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
- Node->getNumClobbers() != 0 || Node->getNumLabels() != 0)
+ Node->getNumClobbers() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
@@ -442,8 +439,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
}
// Inputs
- if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 ||
- Node->getNumLabels() != 0)
+ if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
@@ -463,7 +459,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
}
// Clobbers
- if (Node->getNumClobbers() != 0 || Node->getNumLabels())
+ if (Node->getNumClobbers() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
@@ -473,16 +469,6 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
VisitStringLiteral(Node->getClobberStringLiteral(i));
}
- // Labels
- if (Node->getNumLabels() != 0)
- OS << " : ";
-
- for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) {
- if (i != 0)
- OS << ", ";
- OS << Node->getLabelName(i);
- }
-
OS << ");";
if (Policy.IncludeNewlines) OS << NL;
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index c5da5bfda9..93bdcac8b5 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -321,9 +321,6 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
ID.AddInteger(S->getNumClobbers());
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
VisitStringLiteral(S->getClobberStringLiteral(I));
- ID.AddInteger(S->getNumLabels());
- for (auto *L : S->labels())
- VisitDecl(L->getLabel());
}
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index b53bfcca37..1d83359341 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -549,7 +549,6 @@ private:
CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc);
CFGBlock *VisitForStmt(ForStmt *F);
CFGBlock *VisitGotoStmt(GotoStmt *G);
- CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
CFGBlock *VisitIfStmt(IfStmt *I);
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
@@ -1479,38 +1478,22 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
E = BackpatchBlocks.end(); I != E; ++I ) {
CFGBlock *B = I->block;
- if (auto *G = dyn_cast<GotoStmt>(B->getTerminator())) {
- LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
- // If there is no target for the goto, then we are looking at an
- // incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end())
- continue;
- JumpTarget JT = LI->second;
- prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
- JT.scopePosition);
- prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
- JT.scopePosition);
- const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
- B, I->scopePosition, JT.scopePosition);
- appendScopeBegin(JT.block, VD, G);
- addSuccessor(B, JT.block);
- };
- if (auto *G = dyn_cast<GCCAsmStmt>(B->getTerminator())) {
- CFGBlock *Successor = (I+1)->block;
- for (auto *L : G->labels()) {
- LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
- // If there is no target for the goto, then we are looking at an
- // incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end())
- continue;
- JumpTarget JT = LI->second;
- // Successor has been added, so skip it.
- if (JT.block == Successor)
- continue;
- addSuccessor(B, JT.block);
- }
- I++;
- }
+ const GotoStmt *G = cast<GotoStmt>(B->getTerminator());
+ LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
+
+ // If there is no target for the goto, then we are looking at an
+ // incomplete AST. Handle this by not registering a successor.
+ if (LI == LabelMap.end()) continue;
+
+ JumpTarget JT = LI->second;
+ prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
+ JT.scopePosition);
+ prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
+ JT.scopePosition);
+ const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
+ B, I->scopePosition, JT.scopePosition);
+ appendScopeBegin(JT.block, VD, G);
+ addSuccessor(B, JT.block);
}
// Add successors to the Indirect Goto Dispatch block (if we have one).
@@ -2159,9 +2142,6 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::GotoStmtClass:
return VisitGotoStmt(cast<GotoStmt>(S));
- case Stmt::GCCAsmStmtClass:
- return VisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
-
case Stmt::IfStmtClass:
return VisitIfStmt(cast<IfStmt>(S));
@@ -3166,28 +3146,6 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
return Block;
}
-CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
- // Goto is a control-flow statement. Thus we stop processing the current
- // block and create a new one.
-
- if (!G->isAsmGoto())
- return VisitStmt(G, asc);
-
- if (Block) {
- Succ = Block;
- if (badCFG)
- return nullptr;
- }
- Block = createBlock();
- Block->setTerminator(G);
- // We will backpatch this block later for all the labels.
- BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
- // Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is
- // used to avoid adding "Succ" again.
- BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
- return Block;
-}
-
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
CFGBlock *LoopSuccessor = nullptr;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 5c24db7092..c617b198d7 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1896,55 +1896,6 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
}
-static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
- bool ReadOnly, bool ReadNone, const AsmStmt &S,
- const std::vector<llvm::Type *> &ResultRegTypes,
- CodeGenFunction &CGF,
- std::vector<llvm::Value *> &RegResults) {
- Result.addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoUnwind);
- // Attach readnone and readonly attributes.
- if (!HasSideEffect) {
- if (ReadNone)
- Result.addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::ReadNone);
- else if (ReadOnly)
- Result.addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::ReadOnly);
- }
-
- // Slap the source location of the inline asm into a !srcloc metadata on the
- // call.
- if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
- Result.setMetadata("srcloc",
- getAsmSrcLocInfo(gccAsmStmt->getAsmString(), CGF));
- else {
- // At least put the line number on MS inline asm blobs.
- llvm::Constant *Loc = llvm::ConstantInt::get(CGF.Int32Ty,
- S.getAsmLoc().getRawEncoding());
- Result.setMetadata("srcloc",
- llvm::MDNode::get(CGF.getLLVMContext(),
- llvm::ConstantAsMetadata::get(Loc)));
- }
-
- if (CGF.getLangOpts().assumeFunctionsAreConvergent())
- // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
- // convergent (meaning, they may call an intrinsically convergent op, such
- // as bar.sync, and so can't have certain optimizations applied around
- // them).
- Result.addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::Convergent);
- // Extract all of the register value results from the asm.
- if (ResultRegTypes.size() == 1) {
- RegResults.push_back(&Result);
- } else {
- for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
- llvm::Value *Tmp = CGF.Builder.CreateExtractValue(&Result, i, "asmresult");
- RegResults.push_back(Tmp);
- }
- }
-}
-
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Assemble the final asm string.
std::string AsmString = S.generateAsmString(getContext());
@@ -2187,29 +2138,6 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
Constraints += InOutConstraints;
- // Labels
- SmallVector<llvm::BasicBlock *, 16> Transfer;
- llvm::BasicBlock *Fallthrough = nullptr;
- bool IsGCCAsmGoto = false;
- if (const auto *GS = dyn_cast<GCCAsmStmt>(&S)) {
- IsGCCAsmGoto = GS->isAsmGoto();
- if (IsGCCAsmGoto) {
- for (auto *E : GS->labels()) {
- JumpDest Dest = getJumpDestForLabel(E->getLabel());
- Transfer.push_back(Dest.getBlock());
- llvm::BlockAddress *BA =
- llvm::BlockAddress::get(CurFn, Dest.getBlock());
- Args.push_back(BA);
- ArgTypes.push_back(BA->getType());
- if (!Constraints.empty())
- Constraints += ',';
- Constraints += 'X';
- }
- StringRef Name = "asm.fallthrough";
- Fallthrough = createBasicBlock(Name);
- }
- }
-
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
StringRef Clobber = S.getClobber(i);
@@ -2252,18 +2180,52 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::InlineAsm *IA =
llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
/* IsAlignStack */ false, AsmDialect);
+ llvm::CallInst *Result =
+ Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind);
+
+ // Attach readnone and readonly attributes.
+ if (!HasSideEffect) {
+ if (ReadNone)
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::ReadNone);
+ else if (ReadOnly)
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::ReadOnly);
+ }
+
+ // Slap the source location of the inline asm into a !srcloc metadata on the
+ // call.
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
+ Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
+ *this));
+ } else {
+ // At least put the line number on MS inline asm blobs.
+ auto Loc = llvm::ConstantInt::get(Int32Ty, S.getAsmLoc().getRawEncoding());
+ Result->setMetadata("srcloc",
+ llvm::MDNode::get(getLLVMContext(),
+ llvm::ConstantAsMetadata::get(Loc)));
+ }
+
+ if (getLangOpts().assumeFunctionsAreConvergent()) {
+ // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
+ // convergent (meaning, they may call an intrinsically convergent op, such
+ // as bar.sync, and so can't have certain optimizations applied around
+ // them).
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::Convergent);
+ }
+
+ // Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
- if (IsGCCAsmGoto) {
- llvm::CallBrInst *Result =
- Builder.CreateCallBr(IA, Fallthrough, Transfer, Args);
- UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, ReadOnly,
- ReadNone, S, ResultRegTypes, *this, RegResults);
- EmitBlock(Fallthrough);
+ if (ResultRegTypes.size() == 1) {
+ RegResults.push_back(Result);
} else {
- llvm::CallInst *Result =
- Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
- UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, ReadOnly,
- ReadNone, S, ResultRegTypes, *this, RegResults);
+ for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
+ llvm::Value *Tmp = Builder.CreateExtractValue(Result, i, "asmresult");
+ RegResults.push_back(Tmp);
+ }
}
assert(RegResults.size() == ResultRegTypes.size());
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index 75f3ac396e..c63808a472 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -710,12 +710,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
// Remember if this was a volatile asm.
bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
- // Remember if this was a goto asm.
- bool isGotoAsm = false;
+ // TODO: support "asm goto" constructs (PR#9295).
if (Tok.is(tok::kw_goto)) {
- isGotoAsm = true;
- ConsumeToken();
+ Diag(Tok, diag::err_asm_goto_not_supported_yet);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return StmtError();
}
if (Tok.isNot(tok::l_paren)) {
@@ -753,8 +753,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
/*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
Constraints, Exprs, AsmString.get(),
- Clobbers, /*NumLabels*/ 0,
- T.getCloseLocation());
+ Clobbers, T.getCloseLocation());
}
// Parse Outputs, if present.
@@ -764,12 +763,6 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
AteExtraColon = Tok.is(tok::coloncolon);
ConsumeToken();
- if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) {
- Diag(Tok, diag::err_asm_goto_cannot_have_output);
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
-
if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
return StmtError();
}
@@ -796,15 +789,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
unsigned NumInputs = Names.size() - NumOutputs;
// Parse the clobbers, if present.
- if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
- if (AteExtraColon)
- AteExtraColon = false;
- else {
- AteExtraColon = Tok.is(tok::coloncolon);
+ if (AteExtraColon || Tok.is(tok::colon)) {
+ if (!AteExtraColon)
ConsumeToken();
- }
+
// Parse the asm-string list for clobbers if present.
- if (!AteExtraColon && isTokenStringLiteral()) {
+ if (Tok.isNot(tok::r_paren)) {
while (1) {
ExprResult Clobber(ParseAsmStringLiteral());
@@ -818,49 +808,11 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
}
}
- if (!isGotoAsm && (Tok.isNot(tok::r_paren) || AteExtraColon)) {
- Diag(Tok, diag::err_expected) << tok::r_paren;
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
-
- // Parse the goto label, if present.
- unsigned NumLabels = 0;
- if (AteExtraColon || Tok.is(tok::colon)) {
- if (!AteExtraColon)
- ConsumeToken();
- while (true) {
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
- LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
- Tok.getLocation());
- Names.push_back(Tok.getIdentifierInfo());
- if (!LD) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
- ExprResult Res =
- Actions.ActOnAddrLabel(Tok.getLocation(), Tok.getLocation(), LD);
- Exprs.push_back(Res.get());
- NumLabels++;
- ConsumeToken();
- if (!TryConsumeToken(tok::comma))
- break;
- }
- } else if (isGotoAsm) {
- Diag(Tok, diag::err_expected) << tok::colon;
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
T.consumeClose();
return Actions.ActOnGCCAsmStmt(
AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
- Constraints, Exprs, AsmString.get(), Clobbers, NumLabels,
- T.getCloseLocation());
+ Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
}
/// ParseAsmOperands - Parse the asm-operands production as used by
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index c8743df90e..2234d6ba9b 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -65,10 +65,8 @@ class JumpScopeChecker {
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
SmallVector<Stmt*, 16> Jumps;
- SmallVector<Stmt*, 4> IndirectJumps;
- SmallVector<Stmt*, 4> AsmJumps;
+ SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
SmallVector<LabelDecl*, 4> IndirectJumpTargets;
- SmallVector<LabelDecl*, 4> AsmJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
@@ -78,10 +76,10 @@ private:
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
void VerifyJumps();
- void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
+ void VerifyIndirectJumps();
void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
- void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
- unsigned TargetScope);
+ void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
+ LabelDecl *Target, unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
unsigned JumpDiag, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat);
@@ -105,8 +103,7 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
// Check that all jumps we saw are kosher.
VerifyJumps();
- VerifyIndirectOrAsmJumps(false);
- VerifyIndirectOrAsmJumps(true);
+ VerifyIndirectJumps();
}
/// GetDeepestCommonScope - Finds the innermost scope enclosing the
@@ -319,7 +316,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
}
LabelAndGotoScopes[S] = ParentScope;
- IndirectJumps.push_back(S);
+ IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
break;
case Stmt::SwitchStmtClass:
@@ -342,18 +339,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
Jumps.push_back(S);
break;
- case Stmt::GCCAsmStmtClass:
- if (auto *GS = dyn_cast<GCCAsmStmt>(S))
- if (GS->isAsmGoto()) {
- // Remember both what scope a goto is in as well as the fact that we
- // have it. This makes the second scan not have to walk the AST again.
- LabelAndGotoScopes[S] = ParentScope;
- AsmJumps.push_back(GS);
- for (auto *E : GS->labels())
- AsmJumpTargets.push_back(E->getLabel());
- }
- break;
-
case Stmt::IfStmtClass: {
IfStmt *IS = cast<IfStmt>(S);
if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck()))
@@ -644,13 +629,14 @@ void JumpScopeChecker::VerifyJumps() {
}
}
-/// VerifyIndirectOrAsmJumps - Verify whether any possible indirect goto or
-/// asm goto jump might cross a protection boundary. Unlike direct jumps,
-/// indirect or asm goto jumps count cleanups as protection boundaries:
-/// since there's no way to know where the jump is going, we can't implicitly
-/// run the right cleanups the way we can with direct jumps.
-/// Thus, an indirect/asm jump is "trivial" if it bypasses no
-/// initializations and no teardowns. More formally, an indirect/asm jump
+/// VerifyIndirectJumps - Verify whether any possible indirect jump
+/// might cross a protection boundary. Unlike direct jumps, indirect
+/// jumps count cleanups as protection boundaries: since there's no
+/// way to know where the jump is going, we can't implicitly run the
+/// right cleanups the way we can with direct jumps.
+///
+/// Thus, an indirect jump is "trivial" if it bypasses no
+/// initializations and no teardowns. More formally, an indirect jump
/// from A to B is trivial if the path out from A to DCA(A,B) is
/// trivial and the path in from DCA(A,B) to B is trivial, where
/// DCA(A,B) is the deepest common ancestor of A and B.
@@ -662,41 +648,36 @@ void JumpScopeChecker::VerifyJumps() {
/// Under these definitions, this function checks that the indirect
/// jump between A and B is trivial for every indirect goto statement A
/// and every label B whose address was taken in the function.
-void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
- SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps;
- if (GotoJumps.empty())
- return;
- SmallVector<LabelDecl *, 4> JumpTargets =
- IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
+void JumpScopeChecker::VerifyIndirectJumps() {
+ if (IndirectJumps.empty()) return;
+
// If there aren't any address-of-label expressions in this function,
// complain about the first indirect goto.
- if (JumpTargets.empty()) {
- assert(!IsAsmGoto &&"only indirect goto can get here");
- S.Diag(GotoJumps[0]->getBeginLoc(),
+ if (IndirectJumpTargets.empty()) {
+ S.Diag(IndirectJumps[0]->getGotoLoc(),
diag::err_indirect_goto_without_addrlabel);
return;
}
+
// Collect a single representative of every scope containing an
- // indirect or asm goto. For most code bases, this substantially cuts
+ // indirect goto. For most code bases, this substantially cuts
// down on the number of jump sites we'll have to consider later.
- typedef std::pair<unsigned, Stmt*> JumpScope;
+ typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
SmallVector<JumpScope, 32> JumpScopes;
{
- llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
- for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(),
- E = GotoJumps.end();
- I != E; ++I) {
- Stmt *IG = *I;
+ llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
+ for (SmallVectorImpl<IndirectGotoStmt*>::iterator
+ I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
+ IndirectGotoStmt *IG = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
continue;
unsigned IGScope = LabelAndGotoScopes[IG];
- Stmt *&Entry = JumpScopesMap[IGScope];
+ IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
if (!Entry) Entry = IG;
}
JumpScopes.reserve(JumpScopesMap.size());
- for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
- E = JumpScopesMap.end();
- I != E; ++I)
+ for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
+ I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
JumpScopes.push_back(*I);
}
@@ -704,8 +685,8 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
// label whose address was taken somewhere in the function.
// For most code bases, there will be only one such scope.
llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
- for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(),
- E = JumpTargets.end();
+ for (SmallVectorImpl<LabelDecl*>::iterator
+ I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
I != E; ++I) {
LabelDecl *TheLabel = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
@@ -782,7 +763,7 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
// Only diagnose if we didn't find something.
if (IsReachable) continue;
- DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
+ DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
}
}
}
@@ -803,15 +784,12 @@ static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
}
/// Produce primary diagnostic for an indirect jump statement.
-static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
- LabelDecl *Target, bool &Diagnosed) {
+static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
+ LabelDecl *Target, bool &Diagnosed) {
if (Diagnosed)
return;
- bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
- S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
- << IsAsmGoto;
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
- << IsAsmGoto;
+ S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
Diagnosed = true;
}
@@ -825,9 +803,10 @@ void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
}
/// Diagnose an indirect jump which is known to cross scopes.
-void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
- LabelDecl *Target,
- unsigned TargetScope) {
+void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
+ unsigned JumpScope,
+ LabelDecl *Target,
+ unsigned TargetScope) {
if (CHECK_PERMISSIVE(JumpScope == TargetScope))
return;
@@ -837,7 +816,7 @@ void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
// Walk out the scope chain until we reach the common ancestor.
for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
if (Scopes[I].OutDiag) {
- DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
}
@@ -848,18 +827,15 @@ void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
ToScopesCXX98Compat.push_back(I);
else if (Scopes[I].InDiag) {
- DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
}
// Diagnose this jump if it would be ill-formed in C++98.
if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
- bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
- S.Diag(Jump->getBeginLoc(),
- diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
- << IsAsmGoto;
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
- << IsAsmGoto;
+ S.Diag(Jump->getGotoLoc(),
+ diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
NoteJumpIntoScopes(ToScopesCXX98Compat);
}
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index ec8958c3c5..8c6012573c 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -209,12 +209,11 @@ static StringRef extractRegisterName(const Expr *Expression,
static SourceLocation
getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
StringLiteral **Clobbers, int NumClobbers,
- unsigned NumLabels,
const TargetInfo &Target, ASTContext &Cont) {
llvm::StringSet<> InOutVars;
// Collect all the input and output registers from the extended asm
// statement in order to check for conflicts with the clobber list
- for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
+ for (unsigned int i = 0; i < Exprs.size(); ++i) {
StringRef Constraint = Constraints[i]->getString();
StringRef InOutReg = Target.getConstraintRegister(
Constraint, extractRegisterName(Exprs[i], Target));
@@ -242,7 +241,6 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg constraints, MultiExprArg Exprs,
Expr *asmString, MultiExprArg clobbers,
- unsigned NumLabels,
SourceLocation RParenLoc) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
@@ -271,7 +269,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
- NumClobbers, Clobbers, NumLabels, RParenLoc);
+ NumClobbers, Clobbers, RParenLoc);
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -332,7 +330,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
- NumClobbers, Clobbers, NumLabels, RParenLoc);
+ NumClobbers, Clobbers, RParenLoc);
}
}
@@ -354,7 +352,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
- NumClobbers, Clobbers, NumLabels, RParenLoc);
+ NumClobbers, Clobbers, RParenLoc);
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -453,15 +451,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
- NumClobbers, Clobbers, NumLabels, RParenLoc);
+ NumClobbers, Clobbers, RParenLoc);
}
}
GCCAsmStmt *NS =
new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(),
- AsmString, NumClobbers, Clobbers, NumLabels,
- RParenLoc);
+ AsmString, NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
@@ -479,10 +476,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Look for the correct constraint index.
unsigned ConstraintIdx = Piece.getOperandNo();
- // Labels are the last in the Exprs list.
- if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs())
- continue;
unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
+
// Look for the (ConstraintIdx - NumOperands + 1)th constraint with
// modifier '+'.
if (ConstraintIdx >= NumOperands) {
@@ -665,39 +660,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check for conflicts between clobber list and input or output lists
SourceLocation ConstraintLoc =
getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers,
- NumLabels,
Context.getTargetInfo(), Context);
if (ConstraintLoc.isValid())
targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber);
- // Check for duplicate asm operand name between input, output and label lists.
- typedef std::pair<StringRef , Expr *> NamedOperand;
- SmallVector<NamedOperand, 4> NamedOperandList;
- for (unsigned i = 0, e = NumOutputs + NumInputs + NumLabels; i != e; ++i)
- if (Names[i])
- NamedOperandList.emplace_back(
- std::make_pair(Names[i]->getName(), Exprs[i]));
- // Sort NamedOperandList.
- std::stable_sort(NamedOperandList.begin(), NamedOperandList.end(),
- [](const NamedOperand &LHS, const NamedOperand &RHS) {
- return LHS.first < RHS.first;
- });
- // Find adjacent duplicate operand.
- SmallVector<NamedOperand, 4>::iterator Found =
- std::adjacent_find(begin(NamedOperandList), end(NamedOperandList),
- [](const NamedOperand &LHS, const NamedOperand &RHS) {
- return LHS.first == RHS.first;
- });
- if (Found != NamedOperandList.end()) {
- Diag((Found + 1)->second->getBeginLoc(),
- diag::error_duplicate_asm_operand_name)
- << (Found + 1)->first;
- Diag(Found->second->getBeginLoc(), diag::note_duplicate_asm_operand_name)
- << Found->first;
- return StmtError();
- }
- if (NS->isAsmGoto())
- setFunctionHasBranchIntoScope();
return NS;
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 609a3cfcfc..6620885f23 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1373,11 +1373,10 @@ public:
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg Constraints, MultiExprArg Exprs,
Expr *AsmString, MultiExprArg Clobbers,
- unsigned NumLabels,
SourceLocation RParenLoc) {
return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs,
- AsmString, Clobbers, NumLabels, RParenLoc);
+ AsmString, Clobbers, RParenLoc);
}
/// Build a new MS style inline asm statement.
@@ -7052,16 +7051,6 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
Exprs.push_back(Result.get());
}
- // Go through the Labels.
- for (unsigned I = 0, E = S->getNumLabels(); I != E; ++I) {
- Names.push_back(S->getLabelIdentifier(I));
-
- ExprResult Result = getDerived().TransformExpr(S->getLabelExpr(I));
- if (Result.isInvalid())
- return StmtError();
- ExprsChanged |= Result.get() != S->getLabelExpr(I);
- Exprs.push_back(Result.get());
- }
if (!getDerived().AlwaysRebuild() && !ExprsChanged)
return S;
@@ -7075,8 +7064,7 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
S->isVolatile(), S->getNumOutputs(),
S->getNumInputs(), Names.data(),
Constraints, Exprs, AsmString.get(),
- Clobbers, S->getNumLabels(),
- S->getRParenLoc());
+ Clobbers, S->getRParenLoc());
}
template<typename Derived>
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 52aa3d961d..4d879b46e1 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -370,14 +370,12 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitAsmStmt(S);
- S->NumLabels = Record.readInt();
S->setRParenLoc(ReadSourceLocation());
S->setAsmString(cast_or_null<StringLiteral>(Record.readSubStmt()));
unsigned NumOutputs = S->getNumOutputs();
unsigned NumInputs = S->getNumInputs();
unsigned NumClobbers = S->getNumClobbers();
- unsigned NumLabels = S->getNumLabels();
// Outputs and inputs
SmallVector<IdentifierInfo *, 16> Names;
@@ -394,14 +392,9 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
for (unsigned I = 0; I != NumClobbers; ++I)
Clobbers.push_back(cast_or_null<StringLiteral>(Record.readSubStmt()));
- // Labels
- for (unsigned I = 0, N = NumLabels; I != N; ++I)
- Exprs.push_back(Record.readSubStmt());
-
S->setOutputsAndInputsAndClobbers(Record.getContext(),
Names.data(), Constraints.data(),
Exprs.data(), NumOutputs, NumInputs,
- NumLabels,
Clobbers.data(), NumClobbers);
}
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 776aab6bf5..b0a35cf2f5 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -283,7 +283,6 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitAsmStmt(S);
- Record.push_back(S->getNumLabels());
Record.AddSourceLocation(S->getRParenLoc());
Record.AddStmt(S->getAsmString());
@@ -305,9 +304,6 @@ void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
Record.AddStmt(S->getClobberStringLiteral(I));
- // Labels
- for (auto *E : S->labels()) Record.AddStmt(E);
-
Code = serialization::STMT_GCCASM;
}
diff --git a/test/Analysis/asm-goto.cpp b/test/Analysis/asm-goto.cpp
deleted file mode 100644
index 3d4babc57b..0000000000
--- a/test/Analysis/asm-goto.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
-
-int foo(int cond)
-{
-label_true:
- asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
- return 0;
-loop:
- return 0;
-}
-
-// CHECK-LABEL: loop
-// CHECK-NEXT: 0
-// CHECK-NEXT: return
-// CHECK-NEXT: Preds (1): B3
-// CHECK-NEXT: Succs (1): B0
-
-// CHECK-LABEL: label_true
-// CHECK-NEXT: asm goto
-// CHECK-NEXT: Preds (2): B3 B4
-// CHECK-NEXT: Succs (3): B2 B3 B1
-
-
-int bar(int cond)
-{
- asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::L1, L2);
- return 0;
-L1:
-L2:
- return 0;
-}
-
-// CHECK: [B4]
-// CHECK-NEXT: asm goto
-// CHECK-NEXT: Preds (1): B5
-// CHECK-NEXT: Succs (3): B3 B2 B1
-
-int zoo(int n)
-{
-A5:
-A1:
- asm goto("testl %0, %0; jne %l1;" :: "r"(n)::A1, A2, A3, A4, A5);
-A2:
-A3:
-A4:
- return 0;
-}
-
-// CHECK-LABEL: A1
-// CHECK-NEXT: asm goto
-// CHECK-NEXT: Preds (2): B5 B4
-// CHECK-NEXT: Succs (5): B3 B4 B2 B1 B5
diff --git a/test/CodeGen/asm-goto.c b/test/CodeGen/asm-goto.c
deleted file mode 100644
index 99e97f2a41..0000000000
--- a/test/CodeGen/asm-goto.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -triple x86_64 -O0 -emit-llvm %s -o - | FileCheck %s
-
-int foo(int cond)
-{
- // CHECK: callbr void asm sideeffect
- // CHECK: to label %asm.fallthrough [label %label_true, label %loop], !srcloc !2
- // CHECK: asm.fallthrough:
- asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
- asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
- // CHECK: callbr void asm sideeffect
- // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop], !srcloc !3
- // CHECK: asm.fallthrough1:
- return 0;
-loop:
- return 0;
-label_true:
- return 1;
-}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index 7de79639bf..038d346e99 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -262,15 +262,3 @@ void t31(int len) {
// CHECK: @t31
// CHECK: call void asm sideeffect "", "=*%rm,=*rm,0,1,~{dirflag},~{fpsr},~{flags}"
}
-
-// CHECK: @t32
-int t32(int cond)
-{
- asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
- // CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,X,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@t32, %label_true), i8* blockaddress(@t32, %loop)) #1
- return 0;
-loop:
- return 0;
-label_true:
- return 1;
-}
diff --git a/test/CodeGen/inline-asm-mixed-style.c b/test/CodeGen/inline-asm-mixed-style.c
index a9e111cd5d..6b830d9fa7 100644
--- a/test/CodeGen/inline-asm-mixed-style.c
+++ b/test/CodeGen/inline-asm-mixed-style.c
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -fsyntax-only -verify %s -DCHECK_ASM_GOTO
// RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -O0 -emit-llvm -S %s -o - | FileCheck %s
// REQUIRES: x86-registered-target
@@ -19,11 +20,10 @@ void f() {
// CHECK: movl %ebx, %eax
// CHECK: movl %ecx, %edx
- __asm volatile goto ("movl %ecx, %edx");
- // CHECK: movl %ecx, %edx
+#ifdef CHECK_ASM_GOTO
+ __asm volatile goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}}
__asm mov eax, ebx
- __asm goto ("movl %ecx, %edx");
- // CHECK: movl %ebx, %eax
- // CHECK: movl %ecx, %edx
+ __asm goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}}
+#endif
}
diff --git a/test/Coverage/c-language-features.inc b/test/Coverage/c-language-features.inc
index ea3b96f600..356687907d 100644
--- a/test/Coverage/c-language-features.inc
+++ b/test/Coverage/c-language-features.inc
@@ -71,9 +71,7 @@ theif:
}
asm ("nop");
- int cond;
- asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true);
-label_true:
+
return;
}
diff --git a/test/PCH/asm.h b/test/PCH/asm.h
index 5a7268eff6..a568058d58 100644
--- a/test/PCH/asm.h
+++ b/test/PCH/asm.h
@@ -1,14 +1,10 @@
// Header for the PCH test asm.c
void f() {
- int i,cond;
+ int i;
asm ("foo\n" : : "a" (i + 2));
asm ("foo\n" : [symbolic_name] "=a" (i) : "[symbolic_name]" (i));
- asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
-label_true:
-loop:
- return;
}
void clobbers() {
diff --git a/test/Parser/asm.c b/test/Parser/asm.c
index 489b545ebe..637f9d7ed4 100644
--- a/test/Parser/asm.c
+++ b/test/Parser/asm.c
@@ -21,56 +21,6 @@ void f2() {
}
-int a, b, c, d, e, f, g, h, i, j, k, l;
-
-void
-fgoto1 (void)
-{
- __asm__ volatile goto (""
- :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d),
- [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h),
- [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l)
- ::lab1,lab2);
-lab1: return;
-lab2: return;
-}
-
-void
-fgoto2 (void)
-{
- __asm__ volatile goto (""
- :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d),
- [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h),
- [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l)
- :: lab);
- lab: return;
-}
-
-int zoo ()
-{
- int x,cond,*e;
- // expected-error@+1 {{expected ')'}}
- asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a)
- // expected-error@+1 {{'asm goto' cannot have output constraints}}
- asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a);
- // expected-error@+1 {{expected identifie}}
- asm goto ("decl %0;" :: "m"(x) : "memory" : );
- // expected-error@+1 {{expected ':'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" );
- // expected-error@+1 {{use of undeclared label 'x'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" :x);
- // expected-error@+1 {{use of undeclared label 'b'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" :b);
- // expected-error@+1 {{invalid operand number in inline asm string}}
- asm goto ("testl %0, %0; jne %l3;" :: "r"(cond)::label_true, loop);
- // expected-error@+1 {{unknown symbolic operand name in inline assembly string}}
- asm goto ("decl %0; jnz %l[b]" :: "m"(x) : "memory" : a);
-a:
-label_true:
-loop:
- return 0;
-}
-
// rdar://5952468
__asm ; // expected-error {{expected '(' after 'asm'}}
diff --git a/test/Parser/asm.cpp b/test/Parser/asm.cpp
index 9c4d62a255..9f64dfea47 100644
--- a/test/Parser/asm.cpp
+++ b/test/Parser/asm.cpp
@@ -7,54 +7,3 @@ int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in
int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
-
-int zoo ()
-{
- int x,cond,*e;
- // expected-error@+1 {{expected ')'}}
- asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a)
- // expected-error@+1 {{'asm goto' cannot have output constraints}}
- asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a);
- // expected-error@+1 {{expected identifie}}
- asm goto ("decl %0;" :: "m"(x) : "memory" : );
- // expected-error@+1 {{expected ':'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" );
- // expected-error@+1 {{use of undeclared label 'x'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" :x);
- // expected-error@+1 {{use of undeclared label 'b'}}
- asm goto ("decl %0;" :: "m"(x) : "memory" :b);
- // expected-error@+1 {{invalid operand number in inline asm string}}
- asm goto ("testl %0, %0; jne %l3;" :: "r"(cond)::label_true, loop);
- // expected-error@+1 {{unknown symbolic operand name in inline assembly string}}
- asm goto ("decl %0; jnz %l[b]" :: "m"(x) : "memory" : a);
-label_true:
-loop:
-a:
- return 0;
-}
-
-
-int a, b, c, d, e, f, g, h, i, j, k, l;
-
-void
-fgoto1 (void)
-{
- __asm__ volatile goto (""
- :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d),
- [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h),
- [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l)
- ::lab1,lab2);
-lab1: return;
-lab2: return;
-}
-
-void
-fgoto2 (void)
-{
- __asm__ volatile goto (""
- :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d),
- [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h),
- [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l)
- :: lab);
- lab: return;
-}
diff --git a/test/Sema/asm-goto.cpp b/test/Sema/asm-goto.cpp
deleted file mode 100644
index f61a8096b8..0000000000
--- a/test/Sema/asm-goto.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clang_cc1 %s -triple i386-pc-linux-gnu -verify -fsyntax-only
-
-struct NonTrivial {
- ~NonTrivial();
- int f(int);
-private:
- int k;
-};
-void JumpDiagnostics(int n) {
-// expected-error@+1 {{cannot jump from this goto statement to its label}}
- goto DirectJump;
-// expected-note@+1 {{jump bypasses variable with a non-trivial destructor}}
- NonTrivial tnp1;
-
-DirectJump:
-// expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}}
- asm goto("jmp %l0;" ::::Later);
-// expected-note@+1 {{jump bypasses variable with a non-trivial destructor}}
- NonTrivial tnp2;
-// expected-note@+1 {{possible target of asm goto statement}}
-Later:
- return;
-}
-
-struct S { ~S(); };
-void foo(int a) {
- if (a) {
-FOO:
-// expected-note@+2 {{jump exits scope of variable with non-trivial destructor}}
-// expected-note@+1 {{jump exits scope of variable with non-trivial destructor}}
- S s;
- void *p = &&BAR;
-// expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}}
- asm goto("jmp %l0;" ::::BAR);
-// expected-error@+1 {{cannot jump from this indirect goto statement to one of its possible targets}}
- goto *p;
- p = &&FOO;
- goto *p;
- return;
- }
-// expected-note@+2 {{possible target of asm goto statement}}
-// expected-note@+1 {{possible target of indirect goto statement}}
-BAR:
- return;
-}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 29a55c610d..67da197426 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -295,24 +295,3 @@ int test17(int t0)
return r0 + r1;
}
-void test18()
-{
- // expected-error@+2 {{duplicate use of asm operand name "lab"}}
- // expected-note@+1 {{asm operand name "lab" first referenced here}}
- asm goto ("" : : : : lab, lab, lab2, lab);
- // expected-error@+2 {{duplicate use of asm operand name "lab"}}
- // expected-note@+1 {{asm operand name "lab" first referenced here}}
- asm goto ("xorw %[lab], %[lab]; je %l[lab]" : : [lab] "i" (0) : : lab);
-lab:;
-lab2:;
- int x,x1;
- // expected-error@+2 {{duplicate use of asm operand name "lab"}}
- // expected-note@+1 {{asm operand name "lab" first referenced here}}
- asm ("" : [lab] "=r" (x),[lab] "+r" (x) : [lab1] "r" (x));
- // expected-error@+2 {{duplicate use of asm operand name "lab"}}
- // expected-note@+1 {{asm operand name "lab" first referenced here}}
- asm ("" : [lab] "=r" (x1) : [lab] "r" (x));
- // expected-error@+1 {{invalid operand number in inline asm string}}
- asm ("jne %l0":::);
- asm goto ("jne %l0"::::lab);
-}
diff --git a/test/Sema/inline-asm-validate-tmpl.cpp b/test/Sema/inline-asm-validate-tmpl.cpp
index 9e234caa9c..cf7eac3d83 100644
--- a/test/Sema/inline-asm-validate-tmpl.cpp
+++ b/test/Sema/inline-asm-validate-tmpl.cpp
@@ -23,13 +23,3 @@ template <int N> void testc(int value)
asm("rol %1, %0" :"=r"(value): "I"(N + 1));
}
int foo() { testc<2>(10); }
-
-// these should compile without error
-template <int N> bool testd()
-{
- __asm goto ("" : : : : lab);
- return true;
-lab:
- return false;
-}
-bool foox() { return testd<0> (); }
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
index 0622450e2e..fa37d10d07 100644
--- a/test/Sema/scope-check.c
+++ b/test/Sema/scope-check.c
@@ -232,19 +232,3 @@ void test15(int n, void *pc) {
// rdar://9024687
int test16(int [sizeof &&z]); // expected-error {{use of address-of-label extension outside of a function body}}
-
-//Asm goto:
-int test16(int n)
-{
- // expected-error@+2 {{cannot jump from this asm goto statement to one of its possible targets}}
- // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}}
- asm volatile goto("testl %0, %0; jne %l1;" :: "r"(n)::label_true, loop);
- // expected-note@+2 {{jump bypasses initialization of variable length array}}
- // expected-note@+1 {{possible target of asm goto statement}}
- return ({int a[n];label_true: 2;});
- // expected-note@+1 {{jump bypasses initialization of variable length array}}
- int b[n];
-// expected-note@+1 {{possible target of asm goto statement}}
-loop:
- return 0;
-}