diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Stmt.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/JumpDiagnostics.cpp | 21 |
3 files changed, 31 insertions, 3 deletions
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 4f46b35040..09d889e923 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -669,8 +669,12 @@ Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } // IndirectGotoStmt -Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); } -const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); } +LabelStmt *IndirectGotoStmt::getConstantTarget() { + if (AddrLabelExpr *E = + dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) + return E->getLabel(); + return 0; +} Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; } Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 008c07514e..4de505abdf 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -297,6 +297,11 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { + if (const LabelStmt *Target = S.getConstantTarget()) { + EmitBranchThroughCleanup(getJumpDestForLabel(Target)); + return; + } + // Ensure that we have an i8* for our PHI node. llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()), llvm::Type::getInt8PtrTy(VMContext), diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index b23f615af7..bbe7bd5b28 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -186,6 +186,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { break; case Stmt::IndirectGotoStmtClass: + // "goto *&&lbl;" is a special case which we treat as equivalent + // to a normal goto. In addition, we don't calculate scope in the + // operand (to avoid recording the address-of-label use), which + // works only because of the restricted set of expressions which + // we detect as constant targets. + if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { + LabelAndGotoScopes[S] = ParentScope; + Jumps.push_back(S); + return; + } + LabelAndGotoScopes[S] = ParentScope; IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); break; @@ -341,6 +352,14 @@ void JumpScopeChecker::VerifyJumps() { continue; } + // We only get indirect gotos here when they have a constant target. + if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { + LabelStmt *Target = IGS->getConstantTarget(); + CheckJump(IGS, Target, IGS->getGotoLoc(), + diag::err_goto_into_protected_scope); + continue; + } + SwitchStmt *SS = cast<SwitchStmt>(Jump); for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { @@ -497,7 +516,7 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, unsigned TargetScope) { assert(JumpScope != TargetScope); - S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope); + S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target); unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); |