JumpDiagnostics.cpp revision 2d88708cbe4e4ec5e04e4acb6bd7f5be68557379
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
152d88708cbe4e4ec5e04e4acb6bd7f5be68557379John McCall#include "clang/Sema/SemaInternal.h"
16384aff8b94bb0d1ad6c5667b90621e5699815bb2John McCall#include "clang/AST/DeclCXX.h"
175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner#include "clang/AST/Expr.h"
1816f0049415ec596504891259e2a83e19871c0d52Chris Lattner#include "clang/AST/StmtObjC.h"
19972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl#include "clang/AST/StmtCXX.h"
20e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#include "llvm/ADT/BitVector.h"
215af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerusing namespace clang;
225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
235af280ce21af061f96b5b5b752746871e364ba99Chris Lattnernamespace {
245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
255af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps
265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// into VLA and other protected scopes.  For example, this rejects:
275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner///    goto L;
285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner///    int a[n];
295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner///  L:
305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner///
315af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerclass JumpScopeChecker {
325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  Sema &S;
331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  /// GotoScope - This is a record that we use to keep track of all of the
355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  /// scopes that are introduced by VLAs and other things that scope jumps like
365af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  /// gotos.  This scope tree has nothing to do with the source scope tree,
375af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  /// because you can have multiple VLA scopes per compound statement, and most
385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  /// compound statements don't introduce any scopes.
395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  struct GotoScope {
405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    /// ParentScope - The index in ScopeMap of the parent scope.  This is 0 for
415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    /// the parent scope is the function body.
425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    unsigned ParentScope;
431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
44ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    /// InDiag - The diagnostic to emit if there is a jump into this scope.
45ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned InDiag;
46ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
47ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    /// OutDiag - The diagnostic to emit if there is an indirect jump out
48ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    /// of this scope.  Direct jumps always clean up their current scope
49ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    /// in an orderly way.
50ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned OutDiag;
511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    /// Loc - Location to emit the diagnostic.
535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    SourceLocation Loc;
541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
55ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag,
56ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall              SourceLocation L)
57ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
585af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  };
591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  llvm::SmallVector<GotoScope, 48> Scopes;
615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  llvm::SmallVector<Stmt*, 16> Jumps;
63ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
64ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
65ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets;
665af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerpublic:
675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  JumpScopeChecker(Stmt *Body, Sema &S);
685af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerprivate:
6943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  void BuildScopeInformation(Decl *D, unsigned &ParentScope);
705af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  void BuildScopeInformation(Stmt *S, unsigned ParentScope);
715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  void VerifyJumps();
72ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  void VerifyIndirectJumps();
73ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
74ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                            LabelStmt *Target, unsigned TargetScope);
755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  void CheckJump(Stmt *From, Stmt *To,
765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                 SourceLocation DiagLoc, unsigned JumpDiag);
775e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall
785e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  unsigned GetDeepestCommonScope(unsigned A, unsigned B);
795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner};
805af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} // end anonymous namespace
815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
825af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
835af280ce21af061f96b5b5b752746871e364ba99Chris LattnerJumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
845af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // Add a scope entry for function scope.
85ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));
861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
875af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // Build information for the top level compound statement, so that we have a
885af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // defined scope record for every "goto" and label.
895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  BuildScopeInformation(Body, 0);
901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
915af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // Check that all jumps we saw are kosher.
925af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  VerifyJumps();
93ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  VerifyIndirectJumps();
945af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
965e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// GetDeepestCommonScope - Finds the innermost scope enclosing the
975e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// two scopes.
985e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCallunsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
995e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  while (A != B) {
1005e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    // Inner scopes are created after outer scopes and therefore have
1015e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    // higher indices.
1025e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    if (A < B) {
1035e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      assert(Scopes[B].ParentScope < B);
1045e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      B = Scopes[B].ParentScope;
1055e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    } else {
1065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      assert(Scopes[A].ParentScope < A);
1075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      A = Scopes[A].ParentScope;
1085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    }
1095e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  }
1105e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  return A;
1115e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall}
1125e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall
1135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
1145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// diagnostic that should be emitted if control goes over it. If not, return 0.
115ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallstatic std::pair<unsigned,unsigned>
116ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
1175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
118ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned InDiag = 0, OutDiag = 0;
1195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (VD->getType()->isVariablyModifiedType())
120ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      InDiag = diag::note_protected_by_vla;
121ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
122ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    if (VD->hasAttr<BlocksAttr>()) {
123ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      InDiag = diag::note_protected_by___block;
124ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      OutDiag = diag::note_exits___block;
125ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    } else if (VD->hasAttr<CleanupAttr>()) {
126ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      InDiag = diag::note_protected_by_cleanup;
127ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      OutDiag = diag::note_exits_cleanup;
128ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    } else if (isCPlusPlus) {
129ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      // FIXME: In C++0x, we have to check more conditions than "did we
130ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      // just give it an initializer?". See 6.7p3.
131ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      if (VD->hasLocalStorage() && VD->hasInit())
132ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        InDiag = diag::note_protected_by_variable_init;
133ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
134ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      CanQualType T = VD->getType()->getCanonicalTypeUnqualified();
135025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor      if (!T->isDependentType()) {
136025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor        while (CanQual<ArrayType> AT = T->getAs<ArrayType>())
137025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor          T = AT->getElementType();
138025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor        if (CanQual<RecordType> RT = T->getAs<RecordType>())
139025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor          if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
140025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor            OutDiag = diag::note_exits_dtor;
141025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor      }
142ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    }
1436d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner
144ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    return std::make_pair(InDiag, OutDiag);
145ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  }
146ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
147ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
1485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (TD->getUnderlyingType()->isVariablyModifiedType())
149ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
1505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  }
1511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
152ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  return std::make_pair(0U, 0U);
1535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
1545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
15543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor/// \brief Build scope information for a declaration that is part of a DeclStmt.
15643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregorvoid JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
15743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
15843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor
15943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  // If this decl causes a new scope, push and switch to it.
16043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  std::pair<unsigned,unsigned> Diags
16143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    = GetDiagForGotoScopeDecl(D, isCPlusPlus);
16243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  if (Diags.first || Diags.second) {
16343dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
16443dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor                               D->getLocation()));
16543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    ParentScope = Scopes.size()-1;
16643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  }
16743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor
16843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  // If the decl has an initializer, walk it with the potentially new
16943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  // scope we just installed.
17043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  if (VarDecl *VD = dyn_cast<VarDecl>(D))
17143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    if (Expr *Init = VD->getInit())
17243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor      BuildScopeInformation(Init, ParentScope);
17343dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor}
1745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
1755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// BuildScopeInformation - The statements from CI to CE are known to form a
1765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// coherent VLA scope with a specified parent node.  Walk through the
1775af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
1785af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// walking the AST as needed.
1795af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
18043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  bool SkipFirstSubStmt = false;
18143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor
1825af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // If we found a label, remember that it is in ParentScope scope.
183ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  switch (S->getStmtClass()) {
184ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  case Stmt::AddrLabelExprClass:
185ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
186ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    break;
187ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
188ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  case Stmt::IndirectGotoStmtClass:
1895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    LabelAndGotoScopes[S] = ParentScope;
190ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
191ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    break;
192ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
193ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  case Stmt::SwitchStmtClass:
19443dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    // Evaluate the condition variable before entering the scope of the switch
19543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    // statement.
19643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
19743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor      BuildScopeInformation(Var, ParentScope);
19843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor      SkipFirstSubStmt = true;
19943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    }
20043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    // Fall through
20143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor
20243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor  case Stmt::GotoStmtClass:
2035af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // Remember both what scope a goto is in as well as the fact that we have
2045af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // it.  This makes the second scan not have to walk the AST again.
2055af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    LabelAndGotoScopes[S] = ParentScope;
2065af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    Jumps.push_back(S);
207ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    break;
208ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
209ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  default:
210ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    break;
2115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  }
2121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
2145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner       ++CI) {
21543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    if (SkipFirstSubStmt) {
21643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor      SkipFirstSubStmt = false;
21743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor      continue;
21843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor    }
21943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor
2205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    Stmt *SubStmt = *CI;
2215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (SubStmt == 0) continue;
2221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
22397ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall    // Cases, labels, and defaults aren't "scope parents".  It's also
22497ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall    // important to handle these iteratively instead of recursively in
22597ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall    // order to avoid blowing out the stack.
22697ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall    while (true) {
22797ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      Stmt *Next;
22897ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      if (isa<CaseStmt>(SubStmt))
22997ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall        Next = cast<CaseStmt>(SubStmt)->getSubStmt();
23097ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      else if (isa<DefaultStmt>(SubStmt))
23197ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall        Next = cast<DefaultStmt>(SubStmt)->getSubStmt();
23297ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      else if (isa<LabelStmt>(SubStmt))
23397ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall        Next = cast<LabelStmt>(SubStmt)->getSubStmt();
23497ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      else
23597ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall        break;
23697ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall
23797ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      LabelAndGotoScopes[SubStmt] = ParentScope;
23897ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall      SubStmt = Next;
23997ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall    }
24097ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall
2415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // If this is a declstmt with a VLA definition, it defines a scope from here
2425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // to the end of the containing context.
2435af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
2446d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner      // The decl statement creates a scope if any of the decls in it are VLAs
2456d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner      // or have the cleanup attribute.
2465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
24743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor           I != E; ++I)
24843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor        BuildScopeInformation(*I, ParentScope);
2495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      continue;
2505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
2515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
2525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // Disallow jumps into any part of an @try statement by pushing a scope and
2535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // walking all sub-stmts in that scope.
2545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
2555af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      // Recursively walk the AST for the @try part.
256ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      Scopes.push_back(GotoScope(ParentScope,
257ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                 diag::note_protected_by_objc_try,
258ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                 diag::note_exits_objc_try,
2595af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                 AT->getAtTryLoc()));
2605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      if (Stmt *TryPart = AT->getTryBody())
2615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner        BuildScopeInformation(TryPart, Scopes.size()-1);
2625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
2635af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      // Jump from the catch to the finally or try is not valid.
2648f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor      for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
2658f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor        ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
2665af280ce21af061f96b5b5b752746871e364ba99Chris Lattner        Scopes.push_back(GotoScope(ParentScope,
2675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                   diag::note_protected_by_objc_catch,
268ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                   diag::note_exits_objc_catch,
2695af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                   AC->getAtCatchLoc()));
2701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        // @catches are nested and it isn't
2715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner        BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
2725af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      }
2731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      // Jump from the finally to the try or catch is not valid.
2755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
2765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner        Scopes.push_back(GotoScope(ParentScope,
2775af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                   diag::note_protected_by_objc_finally,
278ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                   diag::note_exits_objc_finally,
2795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                   AF->getAtFinallyLoc()));
2805af280ce21af061f96b5b5b752746871e364ba99Chris Lattner        BuildScopeInformation(AF, Scopes.size()-1);
2815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      }
2821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2835af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      continue;
2845af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
2851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
28646c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner    // Disallow jumps into the protected statement of an @synchronized, but
28746c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner    // allow jumps into the object expression it protects.
28846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner    if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
28946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      // Recursively walk the AST for the @synchronized object expr, it is
29046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      // evaluated in the normal scope.
29146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      BuildScopeInformation(AS->getSynchExpr(), ParentScope);
2921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
29346c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      // Recursively walk the AST for the @synchronized part, protected by a new
29446c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      // scope.
29546c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      Scopes.push_back(GotoScope(ParentScope,
29646c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner                                 diag::note_protected_by_objc_synchronized,
297ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                 diag::note_exits_objc_synchronized,
29846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner                                 AS->getAtSynchronizedLoc()));
29946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
30046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner      continue;
30146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner    }
302972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl
303972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl    // Disallow jumps into any part of a C++ try statement. This is pretty
304972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl    // much the same as for Obj-C.
305972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl    if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
306ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      Scopes.push_back(GotoScope(ParentScope,
307ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                 diag::note_protected_by_cxx_try,
308ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                 diag::note_exits_cxx_try,
309972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl                                 TS->getSourceRange().getBegin()));
310972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl      if (Stmt *TryBlock = TS->getTryBlock())
311972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl        BuildScopeInformation(TryBlock, Scopes.size()-1);
312972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl
313972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl      // Jump from the catch into the try is not allowed either.
3141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
315972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl        CXXCatchStmt *CS = TS->getHandler(I);
316972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl        Scopes.push_back(GotoScope(ParentScope,
317972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl                                   diag::note_protected_by_cxx_catch,
318ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                   diag::note_exits_cxx_catch,
319972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl                                   CS->getSourceRange().getBegin()));
320972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl        BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
321972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl      }
322972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl
323972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl      continue;
324972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl    }
325972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl
3265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    // Recursively walk the AST.
3275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    BuildScopeInformation(SubStmt, ParentScope);
3285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  }
3295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
3305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
3315af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// VerifyJumps - Verify each element of the Jumps array to see if they are
3325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// valid, emitting diagnostics if not.
3335af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::VerifyJumps() {
3345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  while (!Jumps.empty()) {
3355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    Stmt *Jump = Jumps.pop_back_val();
3361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    // With a goto,
3385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
3395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      CheckJump(GS, GS->getLabel(), GS->getGotoLoc(),
3405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                diag::err_goto_into_protected_scope);
3415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner      continue;
3425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
3431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
344ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    SwitchStmt *SS = cast<SwitchStmt>(Jump);
345ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
346ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall         SC = SC->getNextSwitchCase()) {
347ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
348ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      CheckJump(SS, SC, SC->getLocStart(),
349ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                diag::err_switch_into_protected_scope);
3505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
351ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  }
352ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall}
353ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
3545e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// VerifyIndirectJumps - Verify whether any possible indirect jump
3555e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// might cross a protection boundary.  Unlike direct jumps, indirect
3565e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// jumps count cleanups as protection boundaries:  since there's no
3575e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// way to know where the jump is going, we can't implicitly run the
3585e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// right cleanups the way we can with direct jumps.
3595e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall///
3605e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Thus, an indirect jump is "trivial" if it bypasses no
3615e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// initializations and no teardowns.  More formally, an indirect jump
3625e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// from A to B is trivial if the path out from A to DCA(A,B) is
3635e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// trivial and the path in from DCA(A,B) to B is trivial, where
3645e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// DCA(A,B) is the deepest common ancestor of A and B.
3655e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Jump-triviality is transitive but asymmetric.
366ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall///
367ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall/// A path in is trivial if none of the entered scopes have an InDiag.
368ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall/// A path out is trivial is none of the exited scopes have an OutDiag.
3695e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall///
3705e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Under these definitions, this function checks that the indirect
3715e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// jump between A and B is trivial for every indirect goto statement A
3725e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// and every label B whose address was taken in the function.
373ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallvoid JumpScopeChecker::VerifyIndirectJumps() {
374ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  if (IndirectJumps.empty()) return;
375ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
376ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  // If there aren't any address-of-label expressions in this function,
377ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  // complain about the first indirect goto.
378ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  if (IndirectJumpTargets.empty()) {
379ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    S.Diag(IndirectJumps[0]->getGotoLoc(),
380ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall           diag::err_indirect_goto_without_addrlabel);
381ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    return;
382ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  }
383ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
3845e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // Collect a single representative of every scope containing an
3855e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // indirect goto.  For most code bases, this substantially cuts
3865e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // down on the number of jump sites we'll have to consider later.
387ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
388ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  llvm::SmallVector<JumpScope, 32> JumpScopes;
389ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  {
390ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
391ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator
392ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall           I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
393ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      IndirectGotoStmt *IG = *I;
394ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      assert(LabelAndGotoScopes.count(IG) &&
395ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall             "indirect jump didn't get added to scopes?");
396ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      unsigned IGScope = LabelAndGotoScopes[IG];
397ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
398ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      if (!Entry) Entry = IG;
399ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    }
400ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    JumpScopes.reserve(JumpScopesMap.size());
401ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
402ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall           I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
403ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      JumpScopes.push_back(*I);
404ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  }
405ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
4065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // Collect a single representative of every scope containing a
4075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // label whose address was taken somewhere in the function.
4085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // For most code bases, there will be only one such scope.
409ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  llvm::DenseMap<unsigned, LabelStmt*> TargetScopes;
410ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  for (llvm::SmallVectorImpl<LabelStmt*>::iterator
411ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall         I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
412ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall       I != E; ++I) {
413ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    LabelStmt *TheLabel = *I;
414ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    assert(LabelAndGotoScopes.count(TheLabel) &&
415ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall           "Referenced label didn't get added to scopes?");
416ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned LabelScope = LabelAndGotoScopes[TheLabel];
417ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    LabelStmt *&Target = TargetScopes[LabelScope];
418ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    if (!Target) Target = TheLabel;
419ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  }
420ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
4215e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // For each target scope, make sure it's trivially reachable from
4225e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // every scope containing a jump site.
4235e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  //
4245e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // A path between scopes always consists of exitting zero or more
4255e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // scopes, then entering zero or more scopes.  We build a set of
4265e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // of scopes S from which the target scope can be trivially
4275e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // entered, then verify that every jump scope can be trivially
4285e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // exitted to reach a scope in S.
429ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  llvm::BitVector Reachable(Scopes.size(), false);
430ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  for (llvm::DenseMap<unsigned,LabelStmt*>::iterator
431ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall         TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) {
432ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned TargetScope = TI->first;
433ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    LabelStmt *TargetLabel = TI->second;
434ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
435ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    Reachable.reset();
436ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
437ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    // Mark all the enclosing scopes from which you can safely jump
4385e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    // into the target scope.  'Min' will end up being the index of
4395e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    // the shallowest such scope.
440ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    unsigned Min = TargetScope;
441ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    while (true) {
442ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      Reachable.set(Min);
443ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
444ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      // Don't go beyond the outermost scope.
445ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      if (Min == 0) break;
446ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
4475e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      // Stop if we can't trivially enter the current scope.
448ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      if (Scopes[Min].InDiag) break;
4495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
450ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      Min = Scopes[Min].ParentScope;
4515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
4525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
453ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    // Walk through all the jump sites, checking that they can trivially
454ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    // reach this label scope.
455ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    for (llvm::SmallVectorImpl<JumpScope>::iterator
456ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall           I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) {
457ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      unsigned Scope = I->first;
458ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
459ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      // Walk out the "scope chain" for this scope, looking for a scope
4605e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      // we've marked reachable.  For well-formed code this amortizes
4615e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      // to O(JumpScopes.size() / Scopes.size()):  we only iterate
4625e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      // when we see something unmarked, and in well-formed code we
4635e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      // mark everything we iterate past.
464ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      bool IsReachable = false;
465ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      while (true) {
466ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        if (Reachable.test(Scope)) {
467ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall          // If we find something reachable, mark all the scopes we just
468ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall          // walked through as reachable.
469ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall          for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope)
470ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall            Reachable.set(S);
471ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall          IsReachable = true;
472ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall          break;
473ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        }
474ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
475ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        // Don't walk out if we've reached the top-level scope or we've
476ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        // gotten shallower than the shallowest reachable scope.
477ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        if (Scope == 0 || Scope < Min) break;
478ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
479ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        // Don't walk out through an out-diagnostic.
480ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        if (Scopes[Scope].OutDiag) break;
481ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
482ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall        Scope = Scopes[Scope].ParentScope;
483ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      }
484ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
485ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      // Only diagnose if we didn't find something.
486ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      if (IsReachable) continue;
487ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
488ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall      DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
4895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner    }
4905af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  }
4915af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
4925af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
4935e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Diagnose an indirect jump which is known to cross scopes.
494ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallvoid JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
495ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                            unsigned JumpScope,
496ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                            LabelStmt *Target,
497ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall                                            unsigned TargetScope) {
498ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  assert(JumpScope != TargetScope);
499ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
500ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope);
501ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target);
502ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
5035e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
5045e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall
5055e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // Walk out the scope chain until we reach the common ancestor.
5065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
5075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    if (Scopes[I].OutDiag)
5085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
509ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
510ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  // Now walk into the scopes containing the label whose address was taken.
5115e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
5125e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    if (Scopes[I].InDiag)
5135e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
514ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall}
515ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
5165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// CheckJump - Validate that the specified jump statement is valid: that it is
5175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// jumping within or out of its current scope, not into a deeper one.
5185af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
5195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner                                 SourceLocation DiagLoc, unsigned JumpDiag) {
5205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?");
5215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  unsigned FromScope = LabelAndGotoScopes[From];
5225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
5235af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?");
5245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  unsigned ToScope = LabelAndGotoScopes[To];
5251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
5265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // Common case: exactly the same scope, which is fine.
5275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  if (FromScope == ToScope) return;
5281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
5295e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
5301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
5315e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // It's okay to jump out from a nested scope.
5325e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  if (CommonScope == ToScope) return;
5331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
5345e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // Pull out (and reverse) any scopes we might need to diagnose skipping.
5355e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  llvm::SmallVector<unsigned, 10> ToScopes;
5365e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope)
5375e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall    if (Scopes[I].InDiag)
5385e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall      ToScopes.push_back(I);
5395e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall
5405e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall  // If the only scopes present are cleanup scopes, we're okay.
541ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  if (ToScopes.empty()) return;
542ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
543ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall  S.Diag(DiagLoc, JumpDiag);
544ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall
5455af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  // Emit diagnostics for whatever is left in ToScopes.
5465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner  for (unsigned i = 0, e = ToScopes.size(); i != e; ++i)
547ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall    S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag);
5485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
5495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner
5505af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid Sema::DiagnoseInvalidJumps(Stmt *Body) {
5516490ae5003226cae28f980648948bea8b21a8638Douglas Gregor  (void)JumpScopeChecker(Body, *this);
5525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}
553