diff options
author | Jennifer Yu <jennifer.yu@intel.com> | 2019-06-03 15:57:25 +0000 |
---|---|---|
committer | Jennifer Yu <jennifer.yu@intel.com> | 2019-06-03 15:57:25 +0000 |
commit | 508d30929fc3fe36eaac97265d19165cc9030602 (patch) | |
tree | 67656886021bbc211fd6a369b93a251af31f58e3 /lib/Sema | |
parent | 9786367305b6884bcb6b78ee286d49cba445dd81 (diff) | |
download | clang-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.cpp | 114 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAsm.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 16 |
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> |