Re-check in clang support gun asm goto after fixing tests.

llvm-svn: 362410
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index 2234d6b..c8743df 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -65,8 +65,10 @@
   llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
   SmallVector<Stmt*, 16> Jumps;
 
-  SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+  SmallVector<Stmt*, 4> IndirectJumps;
+  SmallVector<Stmt*, 4> AsmJumps;
   SmallVector<LabelDecl*, 4> IndirectJumpTargets;
+  SmallVector<LabelDecl*, 4> AsmJumpTargets;
 public:
   JumpScopeChecker(Stmt *Body, Sema &S);
 private:
@@ -76,10 +78,10 @@
   void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
 
   void VerifyJumps();
-  void VerifyIndirectJumps();
+  void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
   void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
-  void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
-                            LabelDecl *Target, unsigned TargetScope);
+  void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
+                                 unsigned TargetScope);
   void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
                  unsigned JumpDiag, unsigned JumpDiagWarning,
                  unsigned JumpDiagCXX98Compat);
@@ -103,7 +105,8 @@
 
   // Check that all jumps we saw are kosher.
   VerifyJumps();
-  VerifyIndirectJumps();
+  VerifyIndirectOrAsmJumps(false);
+  VerifyIndirectOrAsmJumps(true);
 }
 
 /// GetDeepestCommonScope - Finds the innermost scope enclosing the
@@ -316,7 +319,7 @@
     }
 
     LabelAndGotoScopes[S] = ParentScope;
-    IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
+    IndirectJumps.push_back(S);
     break;
 
   case Stmt::SwitchStmtClass:
@@ -339,6 +342,18 @@
     Jumps.push_back(S);
     break;
 
+  case Stmt::GCCAsmStmtClass:
+    if (auto *GS = dyn_cast<GCCAsmStmt>(S))
+      if (GS->isAsmGoto()) {
+        // Remember both what scope a goto is in as well as the fact that we
+        // have it.  This makes the second scan not have to walk the AST again.
+        LabelAndGotoScopes[S] = ParentScope;
+        AsmJumps.push_back(GS);
+        for (auto *E : GS->labels())
+          AsmJumpTargets.push_back(E->getLabel());
+      }
+    break;
+
   case Stmt::IfStmtClass: {
     IfStmt *IS = cast<IfStmt>(S);
     if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck()))
@@ -629,14 +644,13 @@
   }
 }
 
-/// VerifyIndirectJumps - Verify whether any possible indirect jump
-/// might cross a protection boundary.  Unlike direct jumps, indirect
-/// jumps count cleanups as protection boundaries:  since there's no
-/// way to know where the jump is going, we can't implicitly run the
-/// right cleanups the way we can with direct jumps.
-///
-/// Thus, an indirect jump is "trivial" if it bypasses no
-/// initializations and no teardowns.  More formally, an indirect jump
+/// VerifyIndirectOrAsmJumps - Verify whether any possible indirect goto or
+/// asm goto jump might cross a protection boundary.  Unlike direct jumps,
+/// indirect or asm goto jumps count cleanups as protection boundaries:
+/// since there's no way to know where the jump is going, we can't implicitly
+/// run the right cleanups the way we can with direct jumps.
+/// Thus, an indirect/asm jump is "trivial" if it bypasses no
+/// initializations and no teardowns.  More formally, an indirect/asm jump
 /// from A to B is trivial if the path out from A to DCA(A,B) is
 /// trivial and the path in from DCA(A,B) to B is trivial, where
 /// DCA(A,B) is the deepest common ancestor of A and B.
@@ -648,36 +662,41 @@
 /// Under these definitions, this function checks that the indirect
 /// jump between A and B is trivial for every indirect goto statement A
 /// and every label B whose address was taken in the function.
-void JumpScopeChecker::VerifyIndirectJumps() {
-  if (IndirectJumps.empty()) return;
-
+void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
+  SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps;
+  if (GotoJumps.empty())
+    return;
+  SmallVector<LabelDecl *, 4> JumpTargets =
+      IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
   // If there aren't any address-of-label expressions in this function,
   // complain about the first indirect goto.
-  if (IndirectJumpTargets.empty()) {
-    S.Diag(IndirectJumps[0]->getGotoLoc(),
+  if (JumpTargets.empty()) {
+    assert(!IsAsmGoto &&"only indirect goto can get here");
+    S.Diag(GotoJumps[0]->getBeginLoc(),
            diag::err_indirect_goto_without_addrlabel);
     return;
   }
-
   // Collect a single representative of every scope containing an
-  // indirect goto.  For most code bases, this substantially cuts
+  // indirect or asm goto.  For most code bases, this substantially cuts
   // down on the number of jump sites we'll have to consider later.
-  typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
+  typedef std::pair<unsigned, Stmt*> JumpScope;
   SmallVector<JumpScope, 32> JumpScopes;
   {
-    llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
-    for (SmallVectorImpl<IndirectGotoStmt*>::iterator
-           I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
-      IndirectGotoStmt *IG = *I;
+    llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
+    for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(),
+                                           E = GotoJumps.end();
+         I != E; ++I) {
+      Stmt *IG = *I;
       if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
         continue;
       unsigned IGScope = LabelAndGotoScopes[IG];
-      IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
+      Stmt *&Entry = JumpScopesMap[IGScope];
       if (!Entry) Entry = IG;
     }
     JumpScopes.reserve(JumpScopesMap.size());
-    for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
-           I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
+    for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
+                                                    E = JumpScopesMap.end();
+         I != E; ++I)
       JumpScopes.push_back(*I);
   }
 
@@ -685,8 +704,8 @@
   // label whose address was taken somewhere in the function.
   // For most code bases, there will be only one such scope.
   llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
-  for (SmallVectorImpl<LabelDecl*>::iterator
-         I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
+  for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(),
+                                              E = JumpTargets.end();
        I != E; ++I) {
     LabelDecl *TheLabel = *I;
     if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
@@ -763,7 +782,7 @@
       // Only diagnose if we didn't find something.
       if (IsReachable) continue;
 
-      DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
+      DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
     }
   }
 }
@@ -784,12 +803,15 @@
 }
 
 /// Produce primary diagnostic for an indirect jump statement.
-static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
-                                     LabelDecl *Target, bool &Diagnosed) {
+static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
+                                          LabelDecl *Target, bool &Diagnosed) {
   if (Diagnosed)
     return;
-  S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
-  S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+  bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
+  S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
+      << IsAsmGoto;
+  S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
+      << IsAsmGoto;
   Diagnosed = true;
 }
 
@@ -803,10 +825,9 @@
 }
 
 /// Diagnose an indirect jump which is known to cross scopes.
-void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
-                                            unsigned JumpScope,
-                                            LabelDecl *Target,
-                                            unsigned TargetScope) {
+void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
+                                                 LabelDecl *Target,
+                                                 unsigned TargetScope) {
   if (CHECK_PERMISSIVE(JumpScope == TargetScope))
     return;
 
@@ -816,7 +837,7 @@
   // Walk out the scope chain until we reach the common ancestor.
   for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
     if (Scopes[I].OutDiag) {
-      DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+      DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
       S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
     }
 
@@ -827,15 +848,18 @@
     if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
       ToScopesCXX98Compat.push_back(I);
     else if (Scopes[I].InDiag) {
-      DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+      DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
       S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
     }
 
   // Diagnose this jump if it would be ill-formed in C++98.
   if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
-    S.Diag(Jump->getGotoLoc(),
-           diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
-    S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+    bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
+    S.Diag(Jump->getBeginLoc(),
+           diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
+        << IsAsmGoto;
+    S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
+        << IsAsmGoto;
     NoteJumpIntoScopes(ToScopesCXX98Compat);
   }
 }