summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp85
1 files changed, 65 insertions, 20 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
index fd75c02..6b9eb2a 100644
--- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
@@ -72,10 +72,10 @@ public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
void BuildScopeInformation(Decl *D, unsigned &ParentScope);
- void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
+ void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
unsigned &ParentScope);
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
-
+
void VerifyJumps();
void VerifyIndirectJumps();
void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
@@ -166,7 +166,7 @@ static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) {
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope
// is ill-formed unless the variable has scalar type, class type with
- // a trivial default constructor and a trivial destructor, a
+ // a trivial default constructor and a trivial destructor, a
// cv-qualified version of one of these types, or an array of one of
// the preceding types and is declared without an initializer.
@@ -218,7 +218,7 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
D->getLocation()));
ParentScope = Scopes.size()-1;
}
-
+
// If the decl has an initializer, walk it with the potentially new
// scope we just installed.
if (VarDecl *VD = dyn_cast<VarDecl>(D))
@@ -227,8 +227,8 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
}
/// \brief Build scope information for a captured block literal variables.
-void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
- const BlockDecl *BDecl,
+void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
+ const BlockDecl *BDecl,
unsigned &ParentScope) {
// exclude captured __block variables; there's no destructor
// associated with the block literal for them.
@@ -257,7 +257,7 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
SourceLocation Loc = D->getLocation();
if (Loc.isInvalid())
Loc = BDecl->getLocation();
- Scopes.push_back(GotoScope(ParentScope,
+ Scopes.push_back(GotoScope(ParentScope,
Diags.first, Diags.second, Loc));
ParentScope = Scopes.size()-1;
}
@@ -272,11 +272,11 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
// propagate out into the enclosing scope. Otherwise we have to worry
// about block literals, which have the lifetime of their enclosing statement.
unsigned independentParentScope = origParentScope;
- unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
+ unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
? origParentScope : independentParentScope);
bool SkipFirstSubStmt = false;
-
+
// If we found a label, remember that it is in ParentScope scope.
switch (S->getStmtClass()) {
case Stmt::AddrLabelExprClass:
@@ -307,7 +307,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
SkipFirstSubStmt = true;
}
// Fall through
-
+
case Stmt::GotoStmtClass:
// 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.
@@ -332,9 +332,39 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(),
+ BuildScopeInformation(CS->getHandlerBlock(),
+ (newParentScope = Scopes.size()-1));
+ }
+ return;
+ }
+
+ case Stmt::SEHTryStmtClass: {
+ SEHTryStmt *TS = cast<SEHTryStmt>(S);
+ unsigned newParentScope;
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_seh_try,
+ diag::note_exits_seh_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
+
+ // Jump from __except or __finally into the __try are not allowed either.
+ if (SEHExceptStmt *Except = TS->getExceptHandler()) {
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_seh_except,
+ diag::note_exits_seh_except,
+ Except->getSourceRange().getBegin()));
+ BuildScopeInformation(Except->getBlock(),
+ (newParentScope = Scopes.size()-1));
+ } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) {
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_seh_finally,
+ diag::note_exits_seh_finally,
+ Finally->getSourceRange().getBegin()));
+ BuildScopeInformation(Finally->getBlock(),
(newParentScope = Scopes.size()-1));
}
+
return;
}
@@ -347,7 +377,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
SkipFirstSubStmt = false;
continue;
}
-
+
Stmt *SubStmt = *CI;
if (!SubStmt) continue;
@@ -398,7 +428,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
diag::note_exits_objc_catch,
AC->getAtCatchLoc()));
// @catches are nested and it isn't
- BuildScopeInformation(AC->getCatchBody(),
+ BuildScopeInformation(AC->getCatchBody(),
(newParentScope = Scopes.size()-1));
}
@@ -413,11 +443,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
continue;
}
-
+
unsigned newParentScope;
// Disallow jumps into the protected statement of an @synchronized, but
// allow jumps into the object expression it protects.
- if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
+ if (ObjCAtSynchronizedStmt *AS =
+ dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)) {
// Recursively walk the AST for the @synchronized object expr, it is
// evaluated in the normal scope.
BuildScopeInformation(AS->getSynchExpr(), ParentScope);
@@ -428,20 +459,22 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
diag::note_protected_by_objc_synchronized,
diag::note_exits_objc_synchronized,
AS->getAtSynchronizedLoc()));
- BuildScopeInformation(AS->getSynchBody(),
+ BuildScopeInformation(AS->getSynchBody(),
(newParentScope = Scopes.size()-1));
continue;
}
// Disallow jumps into the protected statement of an @autoreleasepool.
- if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
- // Recursively walk the AST for the @autoreleasepool part, protected by a new
- // scope.
+ if (ObjCAutoreleasePoolStmt *AS =
+ dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)) {
+ // Recursively walk the AST for the @autoreleasepool part, protected by a
+ // new scope.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_autoreleasepool,
diag::note_exits_objc_autoreleasepool,
AS->getAtLoc()));
- BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1));
+ BuildScopeInformation(AS->getSubStmt(),
+ (newParentScope = Scopes.size() - 1));
continue;
}
@@ -756,6 +789,18 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
// Common case: exactly the same scope, which is fine.
if (FromScope == ToScope) return;
+ // Warn on gotos out of __finally blocks.
+ if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) {
+ // If FromScope > ToScope, FromScope is more nested and the jump goes to a
+ // less nested scope. Check if it crosses a __finally along the way.
+ for (unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) {
+ if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) {
+ S.Diag(From->getLocStart(), diag::warn_jump_out_of_seh_finally);
+ break;
+ }
+ }
+ }
+
unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
// It's okay to jump out from a nested scope.
OpenPOWER on IntegriCloud