summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorJennifer Yu <jennifer.yu@intel.com>2019-06-03 15:57:25 +0000
committerJennifer Yu <jennifer.yu@intel.com>2019-06-03 15:57:25 +0000
commit508d30929fc3fe36eaac97265d19165cc9030602 (patch)
tree67656886021bbc211fd6a369b93a251af31f58e3 /lib/Sema
parent9786367305b6884bcb6b78ee286d49cba445dd81 (diff)
downloadclang-508d30929fc3fe36eaac97265d19165cc9030602.tar.gz
Re-check in clang support gun asm goto after fixing tests.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362410 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/JumpDiagnostics.cpp114
-rw-r--r--lib/Sema/SemaStmtAsm.cpp48
-rw-r--r--lib/Sema/TreeTransform.h16
3 files changed, 124 insertions, 54 deletions
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 2234d6ba9b..c8743df90e 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -65,8 +65,10 @@ class JumpScopeChecker {
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
SmallVector<Stmt*, 16> Jumps;
- SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+ SmallVector<Stmt*, 4> IndirectJumps;
+ SmallVector<Stmt*, 4> AsmJumps;
SmallVector<LabelDecl*, 4> IndirectJumpTargets;
+ SmallVector<LabelDecl*, 4> AsmJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
@@ -76,10 +78,10 @@ private:
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
void VerifyJumps();
- void VerifyIndirectJumps();
+ void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
- void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
- LabelDecl *Target, unsigned TargetScope);
+ void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
+ unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
unsigned JumpDiag, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat);
@@ -103,7 +105,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
// Check that all jumps we saw are kosher.
VerifyJumps();
- VerifyIndirectJumps();
+ VerifyIndirectOrAsmJumps(false);
+ VerifyIndirectOrAsmJumps(true);
}
/// GetDeepestCommonScope - Finds the innermost scope enclosing the
@@ -316,7 +319,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
}
LabelAndGotoScopes[S] = ParentScope;
- IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
+ IndirectJumps.push_back(S);
break;
case Stmt::SwitchStmtClass:
@@ -339,6 +342,18 @@ 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()))
@@ -629,14 +644,13 @@ void JumpScopeChecker::VerifyJumps() {
}
}
-/// 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
+/// 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
/// 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.
@@ -648,36 +662,41 @@ 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::VerifyIndirectJumps() {
- if (IndirectJumps.empty()) return;
-
+void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
+ SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps;
+ if (GotoJumps.empty())
+ return;
+ SmallVector<LabelDecl *, 4> JumpTargets =
+ IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
// If there aren't any address-of-label expressions in this function,
// complain about the first indirect goto.
- if (IndirectJumpTargets.empty()) {
- S.Diag(IndirectJumps[0]->getGotoLoc(),
+ if (JumpTargets.empty()) {
+ assert(!IsAsmGoto &&"only indirect goto can get here");
+ S.Diag(GotoJumps[0]->getBeginLoc(),
diag::err_indirect_goto_without_addrlabel);
return;
}
-
// Collect a single representative of every scope containing an
- // indirect goto. For most code bases, this substantially cuts
+ // indirect or asm 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, IndirectGotoStmt*> JumpScope;
+ typedef std::pair<unsigned, Stmt*> JumpScope;
SmallVector<JumpScope, 32> JumpScopes;
{
- llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
- for (SmallVectorImpl<IndirectGotoStmt*>::iterator
- I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
- IndirectGotoStmt *IG = *I;
+ llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
+ for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(),
+ E = GotoJumps.end();
+ I != E; ++I) {
+ Stmt *IG = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
continue;
unsigned IGScope = LabelAndGotoScopes[IG];
- IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
+ Stmt *&Entry = JumpScopesMap[IGScope];
if (!Entry) Entry = IG;
}
JumpScopes.reserve(JumpScopesMap.size());
- for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
- I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
+ for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
+ E = JumpScopesMap.end();
+ I != E; ++I)
JumpScopes.push_back(*I);
}
@@ -685,8 +704,8 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// 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 = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
+ for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(),
+ E = JumpTargets.end();
I != E; ++I) {
LabelDecl *TheLabel = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
@@ -763,7 +782,7 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// Only diagnose if we didn't find something.
if (IsReachable) continue;
- DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
+ DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
}
}
}
@@ -784,12 +803,15 @@ static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
}
/// Produce primary diagnostic for an indirect jump statement.
-static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
- LabelDecl *Target, bool &Diagnosed) {
+static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
+ LabelDecl *Target, bool &Diagnosed) {
if (Diagnosed)
return;
- S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ 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;
Diagnosed = true;
}
@@ -803,10 +825,9 @@ void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
}
/// Diagnose an indirect jump which is known to cross scopes.
-void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
- unsigned JumpScope,
- LabelDecl *Target,
- unsigned TargetScope) {
+void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
+ LabelDecl *Target,
+ unsigned TargetScope) {
if (CHECK_PERMISSIVE(JumpScope == TargetScope))
return;
@@ -816,7 +837,7 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
// 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) {
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
}
@@ -827,15 +848,18 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
ToScopesCXX98Compat.push_back(I);
else if (Scopes[I].InDiag) {
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectOrAsmJumpStmt(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()) {
- S.Diag(Jump->getGotoLoc(),
- diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ 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;
NoteJumpIntoScopes(ToScopesCXX98Compat);
}
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 8c6012573c..ec8958c3c5 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -209,11 +209,12 @@ 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(); ++i) {
+ for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
StringRef Constraint = Constraints[i]->getString();
StringRef InOutReg = Target.getConstraintRegister(
Constraint, extractRegisterName(Exprs[i], Target));
@@ -241,6 +242,7 @@ 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 =
@@ -269,7 +271,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, RParenLoc);
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -330,7 +332,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, RParenLoc);
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
}
}
@@ -352,7 +354,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, RParenLoc);
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -451,14 +453,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
- NumClobbers, Clobbers, RParenLoc);
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
}
}
GCCAsmStmt *NS =
new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(),
- AsmString, NumClobbers, Clobbers, RParenLoc);
+ AsmString, NumClobbers, Clobbers, NumLabels,
+ RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
@@ -476,8 +479,10 @@ 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) {
@@ -660,10 +665,39 @@ 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 592787a587..9f5a5f6cac 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1381,10 +1381,11 @@ 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, RParenLoc);
+ AsmString, Clobbers, NumLabels, RParenLoc);
}
/// Build a new MS style inline asm statement.
@@ -7059,6 +7060,16 @@ 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;
@@ -7072,7 +7083,8 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
S->isVolatile(), S->getNumOutputs(),
S->getNumInputs(), Names.data(),
Constraints, Exprs, AsmString.get(),
- Clobbers, S->getRParenLoc());
+ Clobbers, S->getNumLabels(),
+ S->getRParenLoc());
}
template<typename Derived>