JumpDiagnostics.cpp revision 8f5e3dd32e443768d9dbbad7191e123e6733750c
15af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===// 25af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 35af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// The LLVM Compiler Infrastructure 45af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 55af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// This file is distributed under the University of Illinois Open Source 65af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// License. See LICENSE.TXT for details. 75af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 85af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===----------------------------------------------------------------------===// 95af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 105af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// This file implements the JumpScopeChecker class, which is used to diagnose 115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// jumps that enter a VLA scope in an invalid way. 125af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===----------------------------------------------------------------------===// 145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 155af280ce21af061f96b5b5b752746871e364ba99Chris Lattner#include "Sema.h" 165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner#include "clang/AST/Expr.h" 1716f0049415ec596504891259e2a83e19871c0d52Chris Lattner#include "clang/AST/StmtObjC.h" 18972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl#include "clang/AST/StmtCXX.h" 195af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerusing namespace clang; 205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 215af280ce21af061f96b5b5b752746871e364ba99Chris Lattnernamespace { 225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 235af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps 245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// into VLA and other protected scopes. For example, this rejects: 255af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// goto L; 265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// int a[n]; 275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// L: 285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// 295af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerclass JumpScopeChecker { 305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Sema &S; 311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// GotoScope - This is a record that we use to keep track of all of the 335af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// scopes that are introduced by VLAs and other things that scope jumps like 345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// gotos. This scope tree has nothing to do with the source scope tree, 355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// because you can have multiple VLA scopes per compound statement, and most 365af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// compound statements don't introduce any scopes. 375af280ce21af061f96b5b5b752746871e364ba99Chris Lattner struct GotoScope { 385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for 395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// the parent scope is the function body. 405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned ParentScope; 411eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// Diag - The diagnostic to emit if there is a jump into this scope. 435af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned Diag; 441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 455af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// Loc - Location to emit the diagnostic. 465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation Loc; 471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner GotoScope(unsigned parentScope, unsigned diag, SourceLocation L) 495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner : ParentScope(parentScope), Diag(diag), Loc(L) {} 505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner }; 511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::SmallVector<GotoScope, 48> Scopes; 535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; 545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::SmallVector<Stmt*, 16> Jumps; 555af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerpublic: 565af280ce21af061f96b5b5b752746871e364ba99Chris Lattner JumpScopeChecker(Stmt *Body, Sema &S); 575af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerprivate: 585af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void BuildScopeInformation(Stmt *S, unsigned ParentScope); 595af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void VerifyJumps(); 605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void CheckJump(Stmt *From, Stmt *To, 615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation DiagLoc, unsigned JumpDiag); 625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}; 635af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} // end anonymous namespace 645af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 655af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 665af280ce21af061f96b5b5b752746871e364ba99Chris LattnerJumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { 675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Add a scope entry for function scope. 685af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation())); 691eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 705af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Build information for the top level compound statement, so that we have a 715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // defined scope record for every "goto" and label. 725af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(Body, 0); 731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Check that all jumps we saw are kosher. 755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner VerifyJumps(); 765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 785af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a 795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// diagnostic that should be emitted if control goes over it. If not, return 0. 806d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattnerstatic unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { 815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { 825af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (VD->getType()->isVariablyModifiedType()) 835af280ce21af061f96b5b5b752746871e364ba99Chris Lattner return diag::note_protected_by_vla; 8440b598eea1310ec9ed554d56ce3e25b34c585458Argyrios Kyrtzidis if (VD->hasAttr<CleanupAttr>()) 855af280ce21af061f96b5b5b752746871e364ba99Chris Lattner return diag::note_protected_by_cleanup; 86be6d259a375bbec49659d54a302c4758058f2eefChris Lattner if (VD->hasAttr<BlocksAttr>()) 87be6d259a375bbec49659d54a302c4758058f2eefChris Lattner return diag::note_protected_by___block; 885abbd606200d53f68b57b770ac338c2e9a696abcDouglas Gregor // FIXME: In C++0x, we have to check more conditions than "did we 895abbd606200d53f68b57b770ac338c2e9a696abcDouglas Gregor // just give it an initializer?". See 6.7p3. 906d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit()) 916d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner return diag::note_protected_by_variable_init; 926d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner 935af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { 945af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (TD->getUnderlyingType()->isVariablyModifiedType()) 955af280ce21af061f96b5b5b752746871e364ba99Chris Lattner return diag::note_protected_by_vla_typedef; 965af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 985af280ce21af061f96b5b5b752746871e364ba99Chris Lattner return 0; 995af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 1005af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1015af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1025af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// BuildScopeInformation - The statements from CI to CE are known to form a 1035af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// coherent VLA scope with a specified parent node. Walk through the 1045af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively 1055af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// walking the AST as needed. 1065af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { 1071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1085af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If we found a label, remember that it is in ParentScope scope. 1095af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) { 1105af280ce21af061f96b5b5b752746871e364ba99Chris Lattner LabelAndGotoScopes[S] = ParentScope; 1115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) || 1125af280ce21af061f96b5b5b752746871e364ba99Chris Lattner isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) { 1135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Remember both what scope a goto is in as well as the fact that we have 1145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // it. This makes the second scan not have to walk the AST again. 1155af280ce21af061f96b5b5b752746871e364ba99Chris Lattner LabelAndGotoScopes[S] = ParentScope; 1165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Jumps.push_back(S); 1175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; 1205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner ++CI) { 1215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Stmt *SubStmt = *CI; 1225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (SubStmt == 0) continue; 1231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1246d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner bool isCPlusPlus = this->S.getLangOptions().CPlusPlus; 1255af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If this is a declstmt with a VLA definition, it defines a scope from here 1275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // to the end of the containing context. 1285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { 1296d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner // The decl statement creates a scope if any of the decls in it are VLAs 1306d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner // or have the cleanup attribute. 1315af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 1325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner I != E; ++I) { 1335af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If this decl causes a new scope, push and switch to it. 1346d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) { 1355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); 1365af280ce21af061f96b5b5b752746871e364ba99Chris Lattner ParentScope = Scopes.size()-1; 1375af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If the decl has an initializer, walk it with the potentially new 1405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // scope we just installed. 1415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (VarDecl *VD = dyn_cast<VarDecl>(*I)) 1425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (Expr *Init = VD->getInit()) 1435af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(Init, ParentScope); 1445af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1455af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 1465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1475af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Disallow jumps into any part of an @try statement by pushing a scope and 1495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // walking all sub-stmts in that scope. 1505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { 1515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Recursively walk the AST for the @try part. 1525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try, 1535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AT->getAtTryLoc())); 1545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (Stmt *TryPart = AT->getTryBody()) 1555af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(TryPart, Scopes.size()-1); 1565af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1575af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Jump from the catch to the finally or try is not valid. 1588f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { 1598f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor ObjCAtCatchStmt *AC = AT->getCatchStmt(I); 1605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope, 1615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::note_protected_by_objc_catch, 1625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AC->getAtCatchLoc())); 1631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // @catches are nested and it isn't 1645af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); 1655af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Jump from the finally to the try or catch is not valid. 1685af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { 1695af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope, 1705af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::note_protected_by_objc_finally, 1715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AF->getAtFinallyLoc())); 1725af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(AF, Scopes.size()-1); 1735af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 1765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 17846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Disallow jumps into the protected statement of an @synchronized, but 17946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // allow jumps into the object expression it protects. 18046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ 18146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Recursively walk the AST for the @synchronized object expr, it is 18246c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // evaluated in the normal scope. 18346c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner BuildScopeInformation(AS->getSynchExpr(), ParentScope); 1841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 18546c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Recursively walk the AST for the @synchronized part, protected by a new 18646c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // scope. 18746c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner Scopes.push_back(GotoScope(ParentScope, 18846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner diag::note_protected_by_objc_synchronized, 18946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner AS->getAtSynchronizedLoc())); 19046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); 19146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner continue; 19246c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner } 193972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 194972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // Disallow jumps into any part of a C++ try statement. This is pretty 195972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // much the same as for Obj-C. 196972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { 197972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try, 198972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl TS->getSourceRange().getBegin())); 199972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl if (Stmt *TryBlock = TS->getTryBlock()) 200972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl BuildScopeInformation(TryBlock, Scopes.size()-1); 201972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 202972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // Jump from the catch into the try is not allowed either. 2031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { 204972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl CXXCatchStmt *CS = TS->getHandler(I); 205972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl Scopes.push_back(GotoScope(ParentScope, 206972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl diag::note_protected_by_cxx_catch, 207972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl CS->getSourceRange().getBegin())); 208972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); 209972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl } 210972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 211972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl continue; 212972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl } 213972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 2145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Recursively walk the AST. 2155af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(SubStmt, ParentScope); 2165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 2185af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// VerifyJumps - Verify each element of the Jumps array to see if they are 2205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// valid, emitting diagnostics if not. 2215af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::VerifyJumps() { 2225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner while (!Jumps.empty()) { 2235af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Stmt *Jump = Jumps.pop_back_val(); 2241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // With a goto, 2265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { 2275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), 2285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::err_goto_into_protected_scope); 2295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 2305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { 2335af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (SwitchCase *SC = SS->getSwitchCaseList(); SC; 2345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SC = SC->getNextSwitchCase()) { 2355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); 2365af280ce21af061f96b5b5b752746871e364ba99Chris Lattner CheckJump(SS, SC, SC->getLocStart(), 2375af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::err_switch_into_protected_scope); 2385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 2405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned DiagnosticScope; 2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2445af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // We don't know where an indirect goto goes, require that it be at the 2455af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // top level of scoping. 2465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) { 2475af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(Jump) && 2485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner "Jump didn't get added to scopes?"); 2495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned GotoScope = LabelAndGotoScopes[IG]; 2505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (GotoScope == 0) continue; // indirect jump is ok. 2515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); 2525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner DiagnosticScope = GotoScope; 2535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } else { 2545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // We model &&Label as a jump for purposes of scope tracking. We actually 2555af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // don't care *where* the address of label is, but we require the *label 2565af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // itself* to be in scope 0. If it is nested inside of a VLA scope, then 2575af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // it is possible for an indirect goto to illegally enter the VLA scope by 2585af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // indirectly jumping to the label. 2595af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type"); 2605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel(); 2611eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(TheLabel) && 2635af280ce21af061f96b5b5b752746871e364ba99Chris Lattner "Referenced label didn't get added to scopes?"); 2645af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned LabelScope = LabelAndGotoScopes[TheLabel]; 2655af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (LabelScope == 0) continue; // Addr of label is ok. 2661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope); 2685af280ce21af061f96b5b5b752746871e364ba99Chris Lattner DiagnosticScope = LabelScope; 2695af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2705af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Report all the things that would be skipped over by this &&label or 2725af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // indirect goto. 2735af280ce21af061f96b5b5b752746871e364ba99Chris Lattner while (DiagnosticScope != 0) { 2745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag); 2755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner DiagnosticScope = Scopes[DiagnosticScope].ParentScope; 2765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2775af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2785af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 2795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2805af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// CheckJump - Validate that the specified jump statement is valid: that it is 2815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// jumping within or out of its current scope, not into a deeper one. 2825af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, 2835af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation DiagLoc, unsigned JumpDiag) { 2845af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); 2855af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned FromScope = LabelAndGotoScopes[From]; 2865af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2875af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); 2885af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned ToScope = LabelAndGotoScopes[To]; 2891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2905af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Common case: exactly the same scope, which is fine. 2915af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (FromScope == ToScope) return; 2921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2935af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // The only valid mismatch jump case happens when the jump is more deeply 2945af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // nested inside the jump target. Do a quick scan to see if the jump is valid 2955af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // because valid code is more common than invalid code. 2965af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned TestScope = Scopes[FromScope].ParentScope; 2975af280ce21af061f96b5b5b752746871e364ba99Chris Lattner while (TestScope != ~0U) { 2985af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If we found the jump target, then we're jumping out of our current scope, 2995af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // which is perfectly fine. 3005af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (TestScope == ToScope) return; 3011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3025af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Otherwise, scan up the hierarchy. 3035af280ce21af061f96b5b5b752746871e364ba99Chris Lattner TestScope = Scopes[TestScope].ParentScope; 3045af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 3051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3065af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If we get here, then we know we have invalid code. Diagnose the bad jump, 3075af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // and then emit a note at each VLA being jumped out of. 3085af280ce21af061f96b5b5b752746871e364ba99Chris Lattner S.Diag(DiagLoc, JumpDiag); 3095af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 3105af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Eliminate the common prefix of the jump and the target. Start by 3115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // linearizing both scopes, reversing them as we go. 3125af280ce21af061f96b5b5b752746871e364ba99Chris Lattner std::vector<unsigned> FromScopes, ToScopes; 3135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (TestScope = FromScope; TestScope != ~0U; 3145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner TestScope = Scopes[TestScope].ParentScope) 3155af280ce21af061f96b5b5b752746871e364ba99Chris Lattner FromScopes.push_back(TestScope); 3165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (TestScope = ToScope; TestScope != ~0U; 3175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner TestScope = Scopes[TestScope].ParentScope) 3185af280ce21af061f96b5b5b752746871e364ba99Chris Lattner ToScopes.push_back(TestScope); 3195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 3205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Remove any common entries (such as the top-level function scope). 3215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) { 3225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner FromScopes.pop_back(); 3235af280ce21af061f96b5b5b752746871e364ba99Chris Lattner ToScopes.pop_back(); 3245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 3251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Emit diagnostics for whatever is left in ToScopes. 3275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) 3285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag); 3295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 3305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 3315af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid Sema::DiagnoseInvalidJumps(Stmt *Body) { 3326490ae5003226cae28f980648948bea8b21a8638Douglas Gregor (void)JumpScopeChecker(Body, *this); 3335af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 334