brintos

brintos / llvm-project-archived public Read only

0
0
Text · 41.6 KiB · 36704c3 Raw
1070 lines · cpp
1//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the JumpScopeChecker class, which is used to diagnose10// jumps that enter a protected scope in an invalid way.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/DeclCXX.h"15#include "clang/AST/Expr.h"16#include "clang/AST/ExprCXX.h"17#include "clang/AST/StmtCXX.h"18#include "clang/AST/StmtObjC.h"19#include "clang/AST/StmtOpenACC.h"20#include "clang/AST/StmtOpenMP.h"21#include "clang/Basic/SourceLocation.h"22#include "clang/Sema/SemaInternal.h"23#include "llvm/ADT/BitVector.h"24using namespace clang;25 26namespace {27 28/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps29/// into VLA and other protected scopes.  For example, this rejects:30///    goto L;31///    int a[n];32///  L:33///34/// We also detect jumps out of protected scopes when it's not possible to do35/// cleanups properly. Indirect jumps and ASM jumps can't do cleanups because36/// the target is unknown. Return statements with \c [[clang::musttail]] cannot37/// handle any cleanups due to the nature of a tail call.38class JumpScopeChecker {39  Sema &S;40 41  /// Permissive - True when recovering from errors, in which case precautions42  /// are taken to handle incomplete scope information.43  const bool Permissive;44 45  /// GotoScope - This is a record that we use to keep track of all of the46  /// scopes that are introduced by VLAs and other things that scope jumps like47  /// gotos.  This scope tree has nothing to do with the source scope tree,48  /// because you can have multiple VLA scopes per compound statement, and most49  /// compound statements don't introduce any scopes.50  struct GotoScope {51    /// ParentScope - The index in ScopeMap of the parent scope.  This is 0 for52    /// the parent scope is the function body.53    unsigned ParentScope;54 55    /// InDiag - The note to emit if there is a jump into this scope.56    unsigned InDiag;57 58    /// OutDiag - The note to emit if there is an indirect jump out59    /// of this scope.  Direct jumps always clean up their current scope60    /// in an orderly way.61    unsigned OutDiag;62 63    /// Loc - Location to emit the diagnostic.64    SourceLocation Loc;65 66    GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag,67              SourceLocation L)68      : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}69  };70 71  SmallVector<GotoScope, 48> Scopes;72  llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;73  SmallVector<Stmt*, 16> Jumps;74 75  SmallVector<Stmt*, 4> IndirectJumps;76  SmallVector<LabelDecl *, 4> IndirectJumpTargets;77  SmallVector<AttributedStmt *, 4> MustTailStmts;78 79public:80  JumpScopeChecker(Stmt *Body, Sema &S);81private:82  void BuildScopeInformation(Decl *D, unsigned &ParentScope);83  void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,84                             unsigned &ParentScope);85  void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope);86  void BuildScopeInformation(Stmt *S, unsigned &origParentScope);87 88  void VerifyJumps();89  void VerifyIndirectJumps();90  void VerifyMustTailStmts();91  void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);92  void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,93                                 unsigned TargetScope);94  void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,95                 unsigned JumpDiag, unsigned JumpDiagWarning,96                 unsigned JumpDiagCompat);97  void CheckGotoStmt(GotoStmt *GS);98  const Attr *GetMustTailAttr(AttributedStmt *AS);99 100  unsigned GetDeepestCommonScope(unsigned A, unsigned B);101};102} // end anonymous namespace103 104#define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x)))105 106JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)107    : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) {108  // Add a scope entry for function scope.109  Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));110 111  // Build information for the top level compound statement, so that we have a112  // defined scope record for every "goto" and label.113  unsigned BodyParentScope = 0;114  BuildScopeInformation(Body, BodyParentScope);115 116  // Check that all jumps we saw are kosher.117  VerifyJumps();118  VerifyIndirectJumps();119  VerifyMustTailStmts();120}121 122/// GetDeepestCommonScope - Finds the innermost scope enclosing the123/// two scopes.124unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {125  while (A != B) {126    // Inner scopes are created after outer scopes and therefore have127    // higher indices.128    if (A < B) {129      assert(Scopes[B].ParentScope < B);130      B = Scopes[B].ParentScope;131    } else {132      assert(Scopes[A].ParentScope < A);133      A = Scopes[A].ParentScope;134    }135  }136  return A;137}138 139typedef std::pair<unsigned,unsigned> ScopePair;140 141/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a142/// diagnostic that should be emitted if control goes over it. If not, return 0.143static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) {144  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {145    unsigned InDiag = 0;146    unsigned OutDiag = 0;147 148    if (VD->getType()->isVariablyModifiedType())149      InDiag = diag::note_protected_by_vla;150 151    if (VD->hasAttr<BlocksAttr>())152      return ScopePair(diag::note_protected_by___block,153                       diag::note_exits___block);154 155    if (VD->hasAttr<CleanupAttr>())156      return ScopePair(diag::note_protected_by_cleanup,157                       diag::note_exits_cleanup);158 159    if (VD->hasLocalStorage()) {160      switch (VD->getType().isDestructedType()) {161      case QualType::DK_objc_strong_lifetime:162        return ScopePair(diag::note_protected_by_objc_strong_init,163                         diag::note_exits_objc_strong);164 165      case QualType::DK_objc_weak_lifetime:166        return ScopePair(diag::note_protected_by_objc_weak_init,167                         diag::note_exits_objc_weak);168 169      case QualType::DK_nontrivial_c_struct:170        return ScopePair(diag::note_protected_by_non_trivial_c_struct_init,171                         diag::note_exits_dtor);172 173      case QualType::DK_cxx_destructor:174        OutDiag = diag::note_exits_dtor;175        break;176 177      case QualType::DK_none:178        break;179      }180    }181 182    if (const Expr *Init = VD->getInit();183        VD->hasLocalStorage() && Init && !Init->containsErrors()) {184      // C++11 [stmt.dcl]p3:185      //   A program that jumps from a point where a variable with automatic186      //   storage duration is not in scope to a point where it is in scope187      //   is ill-formed unless the variable has scalar type, class type with188      //   a trivial default constructor and a trivial destructor, a189      //   cv-qualified version of one of these types, or an array of one of190      //   the preceding types and is declared without an initializer.191 192      // C++03 [stmt.dcl.p3:193      //   A program that jumps from a point where a local variable194      //   with automatic storage duration is not in scope to a point195      //   where it is in scope is ill-formed unless the variable has196      //   POD type and is declared without an initializer.197 198      InDiag = diag::note_protected_by_variable_init;199 200      // For a variable of (array of) class type declared without an201      // initializer, we will have call-style initialization and the initializer202      // will be the CXXConstructExpr with no intervening nodes.203      if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {204        const CXXConstructorDecl *Ctor = CCE->getConstructor();205        if (Ctor->isTrivial() && Ctor->isDefaultConstructor() &&206            VD->getInitStyle() == VarDecl::CallInit) {207          if (OutDiag)208            InDiag = diag::note_protected_by_variable_nontriv_destructor;209          else if (!Ctor->getParent()->isPOD())210            InDiag = diag::note_protected_by_variable_non_pod;211          else212            InDiag = 0;213        }214      }215    }216 217    return ScopePair(InDiag, OutDiag);218  }219 220  if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {221    if (TD->getUnderlyingType()->isVariablyModifiedType())222      return ScopePair(isa<TypedefDecl>(TD)223                           ? diag::note_protected_by_vla_typedef224                           : diag::note_protected_by_vla_type_alias,225                       0);226  }227 228  return ScopePair(0U, 0U);229}230 231/// Build scope information for a declaration that is part of a DeclStmt.232void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {233  // If this decl causes a new scope, push and switch to it.234  std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D);235  if (Diags.first || Diags.second) {236    Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,237                               D->getLocation()));238    ParentScope = Scopes.size()-1;239  }240 241  // If the decl has an initializer, walk it with the potentially new242  // scope we just installed.243  if (VarDecl *VD = dyn_cast<VarDecl>(D))244    if (Expr *Init = VD->getInit())245      BuildScopeInformation(Init, ParentScope);246}247 248/// Build scope information for a captured block literal variables.249void JumpScopeChecker::BuildScopeInformation(VarDecl *D,250                                             const BlockDecl *BDecl,251                                             unsigned &ParentScope) {252  // exclude captured __block variables; there's no destructor253  // associated with the block literal for them.254  if (D->hasAttr<BlocksAttr>())255    return;256  QualType T = D->getType();257  QualType::DestructionKind destructKind = T.isDestructedType();258  if (destructKind != QualType::DK_none) {259    std::pair<unsigned,unsigned> Diags;260    switch (destructKind) {261      case QualType::DK_cxx_destructor:262        Diags = ScopePair(diag::note_enters_block_captures_cxx_obj,263                          diag::note_exits_block_captures_cxx_obj);264        break;265      case QualType::DK_objc_strong_lifetime:266        Diags = ScopePair(diag::note_enters_block_captures_strong,267                          diag::note_exits_block_captures_strong);268        break;269      case QualType::DK_objc_weak_lifetime:270        Diags = ScopePair(diag::note_enters_block_captures_weak,271                          diag::note_exits_block_captures_weak);272        break;273      case QualType::DK_nontrivial_c_struct:274        Diags = ScopePair(diag::note_enters_block_captures_non_trivial_c_struct,275                          diag::note_exits_block_captures_non_trivial_c_struct);276        break;277      case QualType::DK_none:278        llvm_unreachable("non-lifetime captured variable");279    }280    SourceLocation Loc = D->getLocation();281    if (Loc.isInvalid())282      Loc = BDecl->getLocation();283    Scopes.push_back(GotoScope(ParentScope,284                               Diags.first, Diags.second, Loc));285    ParentScope = Scopes.size()-1;286  }287}288 289/// Build scope information for compound literals of C struct types that are290/// non-trivial to destruct.291void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE,292                                             unsigned &ParentScope) {293  unsigned InDiag = diag::note_enters_compound_literal_scope;294  unsigned OutDiag = diag::note_exits_compound_literal_scope;295  Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc()));296  ParentScope = Scopes.size() - 1;297}298 299/// BuildScopeInformation - The statements from CI to CE are known to form a300/// coherent VLA scope with a specified parent node.  Walk through the301/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively302/// walking the AST as needed.303void JumpScopeChecker::BuildScopeInformation(Stmt *S,304                                             unsigned &origParentScope) {305  // If this is a statement, rather than an expression, scopes within it don't306  // propagate out into the enclosing scope.  Otherwise we have to worry307  // about block literals, which have the lifetime of their enclosing statement.308  unsigned independentParentScope = origParentScope;309  unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))310                            ? origParentScope : independentParentScope);311 312  unsigned StmtsToSkip = 0u;313 314  // If we found a label, remember that it is in ParentScope scope.315  switch (S->getStmtClass()) {316  case Stmt::AddrLabelExprClass:317    IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());318    break;319 320  case Stmt::ObjCForCollectionStmtClass: {321    auto *CS = cast<ObjCForCollectionStmt>(S);322    unsigned Diag = diag::note_protected_by_objc_fast_enumeration;323    unsigned NewParentScope = Scopes.size();324    Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getBeginLoc()));325    BuildScopeInformation(CS->getBody(), NewParentScope);326    return;327  }328 329  case Stmt::IndirectGotoStmtClass:330    // "goto *&&lbl;" is a special case which we treat as equivalent331    // to a normal goto.  In addition, we don't calculate scope in the332    // operand (to avoid recording the address-of-label use), which333    // works only because of the restricted set of expressions which334    // we detect as constant targets.335    if (cast<IndirectGotoStmt>(S)->getConstantTarget())336      goto RecordJumpScope;337 338    LabelAndGotoScopes[S] = ParentScope;339    IndirectJumps.push_back(S);340    break;341 342  case Stmt::SwitchStmtClass:343    // Evaluate the C++17 init stmt and condition variable344    // before entering the scope of the switch statement.345    if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {346      BuildScopeInformation(Init, ParentScope);347      ++StmtsToSkip;348    }349    if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {350      BuildScopeInformation(Var, ParentScope);351      ++StmtsToSkip;352    }353    goto RecordJumpScope;354 355  case Stmt::GCCAsmStmtClass:356    if (!cast<GCCAsmStmt>(S)->isAsmGoto())357      break;358    [[fallthrough]];359 360  case Stmt::GotoStmtClass:361  RecordJumpScope:362    // Remember both what scope a goto is in as well as the fact that we have363    // it.  This makes the second scan not have to walk the AST again.364    LabelAndGotoScopes[S] = ParentScope;365    Jumps.push_back(S);366    break;367 368  case Stmt::IfStmtClass: {369    IfStmt *IS = cast<IfStmt>(S);370    if (!(IS->isConstexpr() || IS->isConsteval() ||371          IS->isObjCAvailabilityCheck()))372      break;373 374    unsigned Diag = diag::note_protected_by_if_available;375    if (IS->isConstexpr())376      Diag = diag::note_protected_by_constexpr_if;377    else if (IS->isConsteval())378      Diag = diag::note_protected_by_consteval_if;379 380    if (VarDecl *Var = IS->getConditionVariable())381      BuildScopeInformation(Var, ParentScope);382 383    // Cannot jump into the middle of the condition.384    unsigned NewParentScope = Scopes.size();385    Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));386 387    if (!IS->isConsteval())388      BuildScopeInformation(IS->getCond(), NewParentScope);389 390    // Jumps into either arm of an 'if constexpr' are not allowed.391    NewParentScope = Scopes.size();392    Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));393    BuildScopeInformation(IS->getThen(), NewParentScope);394    if (Stmt *Else = IS->getElse()) {395      NewParentScope = Scopes.size();396      Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));397      BuildScopeInformation(Else, NewParentScope);398    }399    return;400  }401 402  case Stmt::CXXTryStmtClass: {403    CXXTryStmt *TS = cast<CXXTryStmt>(S);404    {405      unsigned NewParentScope = Scopes.size();406      Scopes.push_back(GotoScope(ParentScope,407                                 diag::note_protected_by_cxx_try,408                                 diag::note_exits_cxx_try,409                                 TS->getSourceRange().getBegin()));410      if (Stmt *TryBlock = TS->getTryBlock())411        BuildScopeInformation(TryBlock, NewParentScope);412    }413 414    // Jump from the catch into the try is not allowed either.415    for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {416      CXXCatchStmt *CS = TS->getHandler(I);417      unsigned NewParentScope = Scopes.size();418      Scopes.push_back(GotoScope(ParentScope,419                                 diag::note_protected_by_cxx_catch,420                                 diag::note_exits_cxx_catch,421                                 CS->getSourceRange().getBegin()));422      BuildScopeInformation(CS->getHandlerBlock(), NewParentScope);423    }424    return;425  }426 427  case Stmt::SEHTryStmtClass: {428    SEHTryStmt *TS = cast<SEHTryStmt>(S);429    {430      unsigned NewParentScope = Scopes.size();431      Scopes.push_back(GotoScope(ParentScope,432                                 diag::note_protected_by_seh_try,433                                 diag::note_exits_seh_try,434                                 TS->getSourceRange().getBegin()));435      if (Stmt *TryBlock = TS->getTryBlock())436        BuildScopeInformation(TryBlock, NewParentScope);437    }438 439    // Jump from __except or __finally into the __try are not allowed either.440    if (SEHExceptStmt *Except = TS->getExceptHandler()) {441      unsigned NewParentScope = Scopes.size();442      Scopes.push_back(GotoScope(ParentScope,443                                 diag::note_protected_by_seh_except,444                                 diag::note_exits_seh_except,445                                 Except->getSourceRange().getBegin()));446      BuildScopeInformation(Except->getBlock(), NewParentScope);447    } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) {448      unsigned NewParentScope = Scopes.size();449      Scopes.push_back(GotoScope(ParentScope,450                                 diag::note_protected_by_seh_finally,451                                 diag::note_exits_seh_finally,452                                 Finally->getSourceRange().getBegin()));453      BuildScopeInformation(Finally->getBlock(), NewParentScope);454    }455 456    return;457  }458 459  case Stmt::DeclStmtClass: {460    // If this is a declstmt with a VLA definition, it defines a scope from here461    // to the end of the containing context.462    DeclStmt *DS = cast<DeclStmt>(S);463    // The decl statement creates a scope if any of the decls in it are VLAs464    // or have the cleanup attribute.465    for (auto *I : DS->decls())466      BuildScopeInformation(I, origParentScope);467    return;468  }469 470  case Stmt::StmtExprClass: {471    // [GNU]472    // Jumping into a statement expression with goto or using473    // a switch statement outside the statement expression with474    // a case or default label inside the statement expression is not permitted.475    // Jumping out of a statement expression is permitted.476    StmtExpr *SE = cast<StmtExpr>(S);477    unsigned NewParentScope = Scopes.size();478    Scopes.push_back(GotoScope(ParentScope,479                               diag::note_enters_statement_expression,480                               /*OutDiag=*/0, SE->getBeginLoc()));481    BuildScopeInformation(SE->getSubStmt(), NewParentScope);482    return;483  }484 485  case Stmt::ObjCAtTryStmtClass: {486    // Disallow jumps into any part of an @try statement by pushing a scope and487    // walking all sub-stmts in that scope.488    ObjCAtTryStmt *AT = cast<ObjCAtTryStmt>(S);489    // Recursively walk the AST for the @try part.490    {491      unsigned NewParentScope = Scopes.size();492      Scopes.push_back(GotoScope(ParentScope,493                                 diag::note_protected_by_objc_try,494                                 diag::note_exits_objc_try,495                                 AT->getAtTryLoc()));496      if (Stmt *TryPart = AT->getTryBody())497        BuildScopeInformation(TryPart, NewParentScope);498    }499 500    // Jump from the catch to the finally or try is not valid.501    for (ObjCAtCatchStmt *AC : AT->catch_stmts()) {502      unsigned NewParentScope = Scopes.size();503      Scopes.push_back(GotoScope(ParentScope,504                                 diag::note_protected_by_objc_catch,505                                 diag::note_exits_objc_catch,506                                 AC->getAtCatchLoc()));507      // @catches are nested and it isn't508      BuildScopeInformation(AC->getCatchBody(), NewParentScope);509    }510 511    // Jump from the finally to the try or catch is not valid.512    if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {513      unsigned NewParentScope = Scopes.size();514      Scopes.push_back(GotoScope(ParentScope,515                                 diag::note_protected_by_objc_finally,516                                 diag::note_exits_objc_finally,517                                 AF->getAtFinallyLoc()));518      BuildScopeInformation(AF, NewParentScope);519    }520 521    return;522  }523 524  case Stmt::ObjCAtSynchronizedStmtClass: {525    // Disallow jumps into the protected statement of an @synchronized, but526    // allow jumps into the object expression it protects.527    ObjCAtSynchronizedStmt *AS = cast<ObjCAtSynchronizedStmt>(S);528    // Recursively walk the AST for the @synchronized object expr, it is529    // evaluated in the normal scope.530    BuildScopeInformation(AS->getSynchExpr(), ParentScope);531 532    // Recursively walk the AST for the @synchronized part, protected by a new533    // scope.534    unsigned NewParentScope = Scopes.size();535    Scopes.push_back(GotoScope(ParentScope,536                               diag::note_protected_by_objc_synchronized,537                               diag::note_exits_objc_synchronized,538                               AS->getAtSynchronizedLoc()));539    BuildScopeInformation(AS->getSynchBody(), NewParentScope);540    return;541  }542 543  case Stmt::ObjCAutoreleasePoolStmtClass: {544    // Disallow jumps into the protected statement of an @autoreleasepool.545    ObjCAutoreleasePoolStmt *AS = cast<ObjCAutoreleasePoolStmt>(S);546    // Recursively walk the AST for the @autoreleasepool part, protected by a547    // new scope.548    unsigned NewParentScope = Scopes.size();549    Scopes.push_back(GotoScope(ParentScope,550                               diag::note_protected_by_objc_autoreleasepool,551                               diag::note_exits_objc_autoreleasepool,552                               AS->getAtLoc()));553    BuildScopeInformation(AS->getSubStmt(), NewParentScope);554    return;555  }556 557  case Stmt::ExprWithCleanupsClass: {558    // Disallow jumps past full-expressions that use blocks with559    // non-trivial cleanups of their captures.  This is theoretically560    // implementable but a lot of work which we haven't felt up to doing.561    ExprWithCleanups *EWC = cast<ExprWithCleanups>(S);562    for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {563      if (auto *BDecl = dyn_cast<BlockDecl *>(EWC->getObject(i)))564        for (const auto &CI : BDecl->captures()) {565          VarDecl *variable = CI.getVariable();566          BuildScopeInformation(variable, BDecl, origParentScope);567        }568      else if (auto *CLE = dyn_cast<CompoundLiteralExpr *>(EWC->getObject(i)))569        BuildScopeInformation(CLE, origParentScope);570      else571        llvm_unreachable("unexpected cleanup object type");572    }573    break;574  }575 576  case Stmt::MaterializeTemporaryExprClass: {577    // Disallow jumps out of scopes containing temporaries lifetime-extended to578    // automatic storage duration.579    MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);580    if (MTE->getStorageDuration() == SD_Automatic) {581      const Expr *ExtendedObject =582          MTE->getSubExpr()->skipRValueSubobjectAdjustments();583      if (ExtendedObject->getType().isDestructedType()) {584        Scopes.push_back(GotoScope(ParentScope, 0,585                                   diag::note_exits_temporary_dtor,586                                   ExtendedObject->getExprLoc()));587        origParentScope = Scopes.size()-1;588      }589    }590    break;591  }592 593  case Stmt::CaseStmtClass:594  case Stmt::DefaultStmtClass:595  case Stmt::LabelStmtClass:596    LabelAndGotoScopes[S] = ParentScope;597    break;598 599  case Stmt::OpenACCComputeConstructClass: {600    unsigned NewParentScope = Scopes.size();601    OpenACCComputeConstruct *CC = cast<OpenACCComputeConstruct>(S);602    Scopes.push_back(GotoScope(603        ParentScope, diag::note_acc_branch_into_compute_construct,604        diag::note_acc_branch_out_of_compute_construct, CC->getBeginLoc()));605    // This can be 'null' if the 'body' is a break that we diagnosed, so no606    // reason to put the scope into place.607    if (CC->getStructuredBlock())608      BuildScopeInformation(CC->getStructuredBlock(), NewParentScope);609    return;610  }611 612  case Stmt::OpenACCCombinedConstructClass: {613    unsigned NewParentScope = Scopes.size();614    OpenACCCombinedConstruct *CC = cast<OpenACCCombinedConstruct>(S);615    Scopes.push_back(GotoScope(616        ParentScope, diag::note_acc_branch_into_compute_construct,617        diag::note_acc_branch_out_of_compute_construct, CC->getBeginLoc()));618    // This can be 'null' if the 'body' is a break that we diagnosed, so no619    // reason to put the scope into place.620    if (CC->getLoop())621      BuildScopeInformation(CC->getLoop(), NewParentScope);622    return;623  }624 625  default:626    if (auto *ED = dyn_cast<OMPExecutableDirective>(S)) {627      if (!ED->isStandaloneDirective()) {628        unsigned NewParentScope = Scopes.size();629        Scopes.emplace_back(ParentScope,630                            diag::note_omp_protected_structured_block,631                            diag::note_omp_exits_structured_block,632                            ED->getStructuredBlock()->getBeginLoc());633        BuildScopeInformation(ED->getStructuredBlock(), NewParentScope);634        return;635      }636    }637    break;638  }639 640  for (Stmt *SubStmt : S->children()) {641    if (!SubStmt)642        continue;643    if (StmtsToSkip) {644      --StmtsToSkip;645      continue;646    }647 648    // Cases, labels, attributes, and defaults aren't "scope parents".  It's also649    // important to handle these iteratively instead of recursively in650    // order to avoid blowing out the stack.651    while (true) {652      Stmt *Next;653      if (SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))654        Next = SC->getSubStmt();655      else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))656        Next = LS->getSubStmt();657      else if (AttributedStmt *AS = dyn_cast<AttributedStmt>(SubStmt)) {658        if (GetMustTailAttr(AS)) {659          LabelAndGotoScopes[AS] = ParentScope;660          MustTailStmts.push_back(AS);661        }662        Next = AS->getSubStmt();663      } else664        break;665 666      LabelAndGotoScopes[SubStmt] = ParentScope;667      SubStmt = Next;668    }669 670    // Recursively walk the AST.671    BuildScopeInformation(SubStmt, ParentScope);672  }673}674 675/// VerifyJumps - Verify each element of the Jumps array to see if they are676/// valid, emitting diagnostics if not.677void JumpScopeChecker::VerifyJumps() {678  while (!Jumps.empty()) {679    Stmt *Jump = Jumps.pop_back_val();680 681    // With a goto,682    if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {683      // The label may not have a statement if it's coming from inline MS ASM.684      if (GS->getLabel()->getStmt()) {685        CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),686                  diag::err_goto_into_protected_scope,687                  diag::ext_goto_into_protected_scope,688                  S.getLangOpts().CPlusPlus689                      ? diag::warn_cxx98_compat_goto_into_protected_scope690                      : diag::warn_cpp_compat_goto_into_protected_scope);691      }692      CheckGotoStmt(GS);693      continue;694    }695 696    // If an asm goto jumps to a different scope, things like destructors or697    // initializers might not be run which may be suprising to users. Perhaps698    // this behavior can be changed in the future, but today Clang will not699    // generate such code. Produce a diagnostic instead. See also the700    // discussion here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110728.701    if (auto *G = dyn_cast<GCCAsmStmt>(Jump)) {702      for (AddrLabelExpr *L : G->labels()) {703        LabelDecl *LD = L->getLabel();704        unsigned JumpScope = LabelAndGotoScopes[G];705        unsigned TargetScope = LabelAndGotoScopes[LD->getStmt()];706        if (JumpScope != TargetScope)707          DiagnoseIndirectOrAsmJump(G, JumpScope, LD, TargetScope);708      }709      continue;710    }711 712    // We only get indirect gotos here when they have a constant target.713    if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) {714      LabelDecl *Target = IGS->getConstantTarget();715      CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),716                diag::err_goto_into_protected_scope,717                diag::ext_goto_into_protected_scope,718                S.getLangOpts().CPlusPlus719                    ? diag::warn_cxx98_compat_goto_into_protected_scope720                    : diag::warn_cpp_compat_goto_into_protected_scope);721      continue;722    }723 724    SwitchStmt *SS = cast<SwitchStmt>(Jump);725    for (SwitchCase *SC = SS->getSwitchCaseList(); SC;726         SC = SC->getNextSwitchCase()) {727      if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC)))728        continue;729      SourceLocation Loc;730      if (CaseStmt *CS = dyn_cast<CaseStmt>(SC))731        Loc = CS->getBeginLoc();732      else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC))733        Loc = DS->getBeginLoc();734      else735        Loc = SC->getBeginLoc();736      CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0,737                S.getLangOpts().CPlusPlus738                    ? diag::warn_cxx98_compat_switch_into_protected_scope739                    : diag::warn_cpp_compat_switch_into_protected_scope);740    }741  }742}743 744/// VerifyIndirectJumps - Verify whether any possible indirect goto jump might745/// cross a protection boundary.  Unlike direct jumps, indirect goto jumps746/// count cleanups as protection boundaries: since there's no way to know where747/// the jump is going, we can't implicitly run the right cleanups the way we748/// can with direct jumps.  Thus, an indirect/asm jump is "trivial" if it749/// bypasses no initializations and no teardowns.  More formally, an750/// indirect/asm jump from A to B is trivial if the path out from A to DCA(A,B)751/// is trivial and the path in from DCA(A,B) to B is trivial, where DCA(A,B) is752/// the deepest common ancestor of A and B.  Jump-triviality is transitive but753/// asymmetric.754///755/// A path in is trivial if none of the entered scopes have an InDiag.756/// A path out is trivial is none of the exited scopes have an OutDiag.757///758/// Under these definitions, this function checks that the indirect759/// jump between A and B is trivial for every indirect goto statement A760/// and every label B whose address was taken in the function.761void JumpScopeChecker::VerifyIndirectJumps() {762  if (IndirectJumps.empty())763    return;764  // If there aren't any address-of-label expressions in this function,765  // complain about the first indirect goto.766  if (IndirectJumpTargets.empty()) {767    S.Diag(IndirectJumps[0]->getBeginLoc(),768           diag::err_indirect_goto_without_addrlabel);769    return;770  }771  // Collect a single representative of every scope containing an indirect772  // goto.  For most code bases, this substantially cuts down on the number of773  // jump sites we'll have to consider later.774  using JumpScope = std::pair<unsigned, Stmt *>;775  SmallVector<JumpScope, 32> JumpScopes;776  {777    llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;778    for (Stmt *IG : IndirectJumps) {779      if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))780        continue;781      unsigned IGScope = LabelAndGotoScopes[IG];782      JumpScopesMap.try_emplace(IGScope, IG);783    }784    JumpScopes.reserve(JumpScopesMap.size());785    for (auto &Pair : JumpScopesMap)786      JumpScopes.emplace_back(Pair);787  }788 789  // Collect a single representative of every scope containing a790  // label whose address was taken somewhere in the function.791  // For most code bases, there will be only one such scope.792  llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;793  for (LabelDecl *TheLabel : IndirectJumpTargets) {794    if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))795      continue;796    unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()];797    TargetScopes.try_emplace(LabelScope, TheLabel);798  }799 800  // For each target scope, make sure it's trivially reachable from801  // every scope containing a jump site.802  //803  // A path between scopes always consists of exitting zero or more804  // scopes, then entering zero or more scopes.  We build a set of805  // of scopes S from which the target scope can be trivially806  // entered, then verify that every jump scope can be trivially807  // exitted to reach a scope in S.808  llvm::BitVector Reachable(Scopes.size(), false);809  for (auto [TargetScope, TargetLabel] : TargetScopes) {810    Reachable.reset();811 812    // Mark all the enclosing scopes from which you can safely jump813    // into the target scope.  'Min' will end up being the index of814    // the shallowest such scope.815    unsigned Min = TargetScope;816    while (true) {817      Reachable.set(Min);818 819      // Don't go beyond the outermost scope.820      if (Min == 0) break;821 822      // Stop if we can't trivially enter the current scope.823      if (Scopes[Min].InDiag) break;824 825      Min = Scopes[Min].ParentScope;826    }827 828    // Walk through all the jump sites, checking that they can trivially829    // reach this label scope.830    for (auto [JumpScope, JumpStmt] : JumpScopes) {831      unsigned Scope = JumpScope;832      // Walk out the "scope chain" for this scope, looking for a scope833      // we've marked reachable.  For well-formed code this amortizes834      // to O(JumpScopes.size() / Scopes.size()):  we only iterate835      // when we see something unmarked, and in well-formed code we836      // mark everything we iterate past.837      bool IsReachable = false;838      while (true) {839        if (Reachable.test(Scope)) {840          // If we find something reachable, mark all the scopes we just841          // walked through as reachable.842          for (unsigned S = JumpScope; S != Scope; S = Scopes[S].ParentScope)843            Reachable.set(S);844          IsReachable = true;845          break;846        }847 848        // Don't walk out if we've reached the top-level scope or we've849        // gotten shallower than the shallowest reachable scope.850        if (Scope == 0 || Scope < Min) break;851 852        // Don't walk out through an out-diagnostic.853        if (Scopes[Scope].OutDiag) break;854 855        Scope = Scopes[Scope].ParentScope;856      }857 858      // Only diagnose if we didn't find something.859      if (IsReachable) continue;860 861      DiagnoseIndirectOrAsmJump(JumpStmt, JumpScope, TargetLabel, TargetScope);862    }863  }864}865 866/// Return true if a particular error+note combination must be downgraded to a867/// warning in Microsoft mode.868static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) {869  return (JumpDiag == diag::err_goto_into_protected_scope &&870         (InDiagNote == diag::note_protected_by_variable_init ||871          InDiagNote == diag::note_protected_by_variable_nontriv_destructor));872}873 874/// Return true if a particular note should be downgraded to a compatibility875/// warning in C++11 mode.876static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {877  return S.getLangOpts().CPlusPlus11 &&878         InDiagNote == diag::note_protected_by_variable_non_pod;879}880 881/// Returns true if a particular note should be a C++ compatibility warning in882/// C mode with -Wc++-compat.883static bool IsCppCompatWarning(Sema &S, unsigned InDiagNote) {884  return !S.getLangOpts().CPlusPlus &&885         InDiagNote == diag::note_protected_by_variable_init;886}887 888/// Produce primary diagnostic for an indirect jump statement.889static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,890                                          LabelDecl *Target, bool &Diagnosed) {891  if (Diagnosed)892    return;893  bool IsAsmGoto = isa<GCCAsmStmt>(Jump);894  S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)895      << IsAsmGoto;896  S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)897      << IsAsmGoto;898  Diagnosed = true;899}900 901/// Produce note diagnostics for a jump into a protected scope.902void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {903  if (CHECK_PERMISSIVE(ToScopes.empty()))904    return;905  for (unsigned I = 0, E = ToScopes.size(); I != E; ++I)906    if (Scopes[ToScopes[I]].InDiag)907      S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag);908}909 910/// Diagnose an indirect jump which is known to cross scopes.911void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,912                                                 LabelDecl *Target,913                                                 unsigned TargetScope) {914  if (CHECK_PERMISSIVE(JumpScope == TargetScope))915    return;916 917  unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);918  bool Diagnosed = false;919 920  // Walk out the scope chain until we reach the common ancestor.921  for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)922    if (Scopes[I].OutDiag) {923      DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);924      S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);925    }926 927  SmallVector<unsigned, 10> ToScopesCXX98Compat, ToScopesCppCompat;928 929  // Now walk into the scopes containing the label whose address was taken.930  for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)931    if (IsCXX98CompatWarning(S, Scopes[I].InDiag))932      ToScopesCXX98Compat.push_back(I);933    else if (IsCppCompatWarning(S, Scopes[I].InDiag))934      ToScopesCppCompat.push_back(I);935    else if (Scopes[I].InDiag) {936      DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);937      S.Diag(Scopes[I].Loc, Scopes[I].InDiag);938    }939 940  // Diagnose this jump if it would be ill-formed in C++[98].941  if (!Diagnosed) {942    bool IsAsmGoto = isa<GCCAsmStmt>(Jump);943    auto Diag = [&](unsigned DiagId, const SmallVectorImpl<unsigned> &Notes) {944      S.Diag(Jump->getBeginLoc(), DiagId) << IsAsmGoto;945      S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)946          << IsAsmGoto;947      NoteJumpIntoScopes(Notes);948    };949    if (!ToScopesCXX98Compat.empty())950      Diag(diag::warn_cxx98_compat_indirect_goto_in_protected_scope,951           ToScopesCXX98Compat);952    else if (!ToScopesCppCompat.empty())953      Diag(diag::warn_cpp_compat_indirect_goto_in_protected_scope,954           ToScopesCppCompat);955  }956}957 958/// CheckJump - Validate that the specified jump statement is valid: that it is959/// jumping within or out of its current scope, not into a deeper one.960void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,961                                 unsigned JumpDiagError,962                                 unsigned JumpDiagWarning,963                                 unsigned JumpDiagCompat) {964  if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(From)))965    return;966  if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(To)))967    return;968 969  unsigned FromScope = LabelAndGotoScopes[From];970  unsigned ToScope = LabelAndGotoScopes[To];971 972  // Common case: exactly the same scope, which is fine.973  if (FromScope == ToScope) return;974 975  // Warn on gotos out of __finally blocks.976  if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) {977    // If FromScope > ToScope, FromScope is more nested and the jump goes to a978    // less nested scope.  Check if it crosses a __finally along the way.979    for (unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) {980      if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) {981        S.Diag(From->getBeginLoc(), diag::warn_jump_out_of_seh_finally);982        break;983      } else if (Scopes[I].InDiag ==984                 diag::note_omp_protected_structured_block) {985        S.Diag(From->getBeginLoc(), diag::err_goto_into_protected_scope);986        S.Diag(To->getBeginLoc(), diag::note_omp_exits_structured_block);987        break;988      } else if (Scopes[I].InDiag ==989                 diag::note_acc_branch_into_compute_construct) {990        S.Diag(From->getBeginLoc(), diag::err_goto_into_protected_scope);991        S.Diag(Scopes[I].Loc, diag::note_acc_branch_out_of_compute_construct);992        return;993      }994    }995  }996 997  unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);998 999  // It's okay to jump out from a nested scope.1000  if (CommonScope == ToScope) return;1001 1002  // Pull out (and reverse) any scopes we might need to diagnose skipping.1003  SmallVector<unsigned, 10> ToScopesCompat;1004  SmallVector<unsigned, 10> ToScopesError;1005  SmallVector<unsigned, 10> ToScopesWarning;1006  for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {1007    if (S.getLangOpts().MSVCCompat && S.getLangOpts().CPlusPlus &&1008        JumpDiagWarning != 0 &&1009        IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag))1010      ToScopesWarning.push_back(I);1011    else if (IsCXX98CompatWarning(S, Scopes[I].InDiag) ||1012             IsCppCompatWarning(S, Scopes[I].InDiag))1013      ToScopesCompat.push_back(I);1014    else if (Scopes[I].InDiag)1015      ToScopesError.push_back(I);1016  }1017 1018  // Handle warnings.1019  if (!ToScopesWarning.empty()) {1020    S.Diag(DiagLoc, JumpDiagWarning);1021    NoteJumpIntoScopes(ToScopesWarning);1022    assert(isa<LabelStmt>(To));1023    LabelStmt *Label = cast<LabelStmt>(To);1024    Label->setSideEntry(true);1025  }1026 1027  // Handle errors.1028  if (!ToScopesError.empty()) {1029    S.Diag(DiagLoc, JumpDiagError);1030    NoteJumpIntoScopes(ToScopesError);1031  }1032 1033  // Handle -Wc++98-compat or -Wc++-compat warnings if the jump is well-formed.1034  if (ToScopesError.empty() && !ToScopesCompat.empty()) {1035    S.Diag(DiagLoc, JumpDiagCompat);1036    NoteJumpIntoScopes(ToScopesCompat);1037  }1038}1039 1040void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) {1041  if (GS->getLabel()->isMSAsmLabel()) {1042    S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label)1043        << GS->getLabel()->getIdentifier();1044    S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label)1045        << GS->getLabel()->getIdentifier();1046  }1047}1048 1049void JumpScopeChecker::VerifyMustTailStmts() {1050  for (AttributedStmt *AS : MustTailStmts) {1051    for (unsigned I = LabelAndGotoScopes[AS]; I; I = Scopes[I].ParentScope) {1052      if (Scopes[I].OutDiag) {1053        S.Diag(AS->getBeginLoc(), diag::err_musttail_scope);1054        S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);1055      }1056    }1057  }1058}1059 1060const Attr *JumpScopeChecker::GetMustTailAttr(AttributedStmt *AS) {1061  ArrayRef<const Attr *> Attrs = AS->getAttrs();1062  const auto *Iter =1063      llvm::find_if(Attrs, [](const Attr *A) { return isa<MustTailAttr>(A); });1064  return Iter != Attrs.end() ? *Iter : nullptr;1065}1066 1067void Sema::DiagnoseInvalidJumps(Stmt *Body) {1068  (void)JumpScopeChecker(Body, *this);1069}1070