10b57cec5SDimitry Andric //===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the JumpScopeChecker class, which is used to diagnose
100b57cec5SDimitry Andric // jumps that enter a protected scope in an invalid way.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
150b57cec5SDimitry Andric #include "clang/AST/Expr.h"
160b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
170b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h"
180b57cec5SDimitry Andric #include "clang/AST/StmtObjC.h"
19*0fca6ea1SDimitry Andric #include "clang/AST/StmtOpenACC.h"
20e8d8bef9SDimitry Andric #include "clang/AST/StmtOpenMP.h"
21fe6060f1SDimitry Andric #include "clang/Basic/SourceLocation.h"
22fe6060f1SDimitry Andric #include "clang/Sema/SemaInternal.h"
230b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
240b57cec5SDimitry Andric using namespace clang;
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric namespace {
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric /// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps
290b57cec5SDimitry Andric /// into VLA and other protected scopes. For example, this rejects:
300b57cec5SDimitry Andric /// goto L;
310b57cec5SDimitry Andric /// int a[n];
320b57cec5SDimitry Andric /// L:
330b57cec5SDimitry Andric ///
34fe6060f1SDimitry Andric /// We also detect jumps out of protected scopes when it's not possible to do
35fe6060f1SDimitry Andric /// cleanups properly. Indirect jumps and ASM jumps can't do cleanups because
36fe6060f1SDimitry Andric /// the target is unknown. Return statements with \c [[clang::musttail]] cannot
37fe6060f1SDimitry Andric /// handle any cleanups due to the nature of a tail call.
380b57cec5SDimitry Andric class JumpScopeChecker {
390b57cec5SDimitry Andric Sema &S;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric /// Permissive - True when recovering from errors, in which case precautions
420b57cec5SDimitry Andric /// are taken to handle incomplete scope information.
430b57cec5SDimitry Andric const bool Permissive;
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric /// GotoScope - This is a record that we use to keep track of all of the
460b57cec5SDimitry Andric /// scopes that are introduced by VLAs and other things that scope jumps like
470b57cec5SDimitry Andric /// gotos. This scope tree has nothing to do with the source scope tree,
480b57cec5SDimitry Andric /// because you can have multiple VLA scopes per compound statement, and most
490b57cec5SDimitry Andric /// compound statements don't introduce any scopes.
500b57cec5SDimitry Andric struct GotoScope {
510b57cec5SDimitry Andric /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for
520b57cec5SDimitry Andric /// the parent scope is the function body.
530b57cec5SDimitry Andric unsigned ParentScope;
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric /// InDiag - The note to emit if there is a jump into this scope.
560b57cec5SDimitry Andric unsigned InDiag;
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric /// OutDiag - The note to emit if there is an indirect jump out
590b57cec5SDimitry Andric /// of this scope. Direct jumps always clean up their current scope
600b57cec5SDimitry Andric /// in an orderly way.
610b57cec5SDimitry Andric unsigned OutDiag;
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric /// Loc - Location to emit the diagnostic.
640b57cec5SDimitry Andric SourceLocation Loc;
650b57cec5SDimitry Andric
GotoScope__anon116d3ae30111::JumpScopeChecker::GotoScope660b57cec5SDimitry Andric GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag,
670b57cec5SDimitry Andric SourceLocation L)
680b57cec5SDimitry Andric : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
690b57cec5SDimitry Andric };
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric SmallVector<GotoScope, 48> Scopes;
720b57cec5SDimitry Andric llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
730b57cec5SDimitry Andric SmallVector<Stmt*, 16> Jumps;
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric SmallVector<Stmt*, 4> IndirectJumps;
760b57cec5SDimitry Andric SmallVector<LabelDecl *, 4> IndirectJumpTargets;
7706c3fb27SDimitry Andric SmallVector<AttributedStmt *, 4> MustTailStmts;
7806c3fb27SDimitry Andric
790b57cec5SDimitry Andric public:
800b57cec5SDimitry Andric JumpScopeChecker(Stmt *Body, Sema &S);
810b57cec5SDimitry Andric private:
820b57cec5SDimitry Andric void BuildScopeInformation(Decl *D, unsigned &ParentScope);
830b57cec5SDimitry Andric void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
840b57cec5SDimitry Andric unsigned &ParentScope);
855ffd83dbSDimitry Andric void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope);
860b57cec5SDimitry Andric void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric void VerifyJumps();
8906c3fb27SDimitry Andric void VerifyIndirectJumps();
90fe6060f1SDimitry Andric void VerifyMustTailStmts();
910b57cec5SDimitry Andric void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
920b57cec5SDimitry Andric void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
930b57cec5SDimitry Andric unsigned TargetScope);
940b57cec5SDimitry Andric void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
950b57cec5SDimitry Andric unsigned JumpDiag, unsigned JumpDiagWarning,
960b57cec5SDimitry Andric unsigned JumpDiagCXX98Compat);
970b57cec5SDimitry Andric void CheckGotoStmt(GotoStmt *GS);
98fe6060f1SDimitry Andric const Attr *GetMustTailAttr(AttributedStmt *AS);
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric unsigned GetDeepestCommonScope(unsigned A, unsigned B);
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric } // end anonymous namespace
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric #define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x)))
1050b57cec5SDimitry Andric
JumpScopeChecker(Stmt * Body,Sema & s)1060b57cec5SDimitry Andric JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
1070b57cec5SDimitry Andric : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) {
1080b57cec5SDimitry Andric // Add a scope entry for function scope.
1090b57cec5SDimitry Andric Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric // Build information for the top level compound statement, so that we have a
1120b57cec5SDimitry Andric // defined scope record for every "goto" and label.
1130b57cec5SDimitry Andric unsigned BodyParentScope = 0;
1140b57cec5SDimitry Andric BuildScopeInformation(Body, BodyParentScope);
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric // Check that all jumps we saw are kosher.
1170b57cec5SDimitry Andric VerifyJumps();
11806c3fb27SDimitry Andric VerifyIndirectJumps();
119fe6060f1SDimitry Andric VerifyMustTailStmts();
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric /// GetDeepestCommonScope - Finds the innermost scope enclosing the
1230b57cec5SDimitry Andric /// two scopes.
GetDeepestCommonScope(unsigned A,unsigned B)1240b57cec5SDimitry Andric unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
1250b57cec5SDimitry Andric while (A != B) {
1260b57cec5SDimitry Andric // Inner scopes are created after outer scopes and therefore have
1270b57cec5SDimitry Andric // higher indices.
1280b57cec5SDimitry Andric if (A < B) {
1290b57cec5SDimitry Andric assert(Scopes[B].ParentScope < B);
1300b57cec5SDimitry Andric B = Scopes[B].ParentScope;
1310b57cec5SDimitry Andric } else {
1320b57cec5SDimitry Andric assert(Scopes[A].ParentScope < A);
1330b57cec5SDimitry Andric A = Scopes[A].ParentScope;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric return A;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric typedef std::pair<unsigned,unsigned> ScopePair;
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
1420b57cec5SDimitry Andric /// diagnostic that should be emitted if control goes over it. If not, return 0.
GetDiagForGotoScopeDecl(Sema & S,const Decl * D)1430b57cec5SDimitry Andric static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) {
1440b57cec5SDimitry Andric if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
1450b57cec5SDimitry Andric unsigned InDiag = 0;
1460b57cec5SDimitry Andric unsigned OutDiag = 0;
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric if (VD->getType()->isVariablyModifiedType())
1490b57cec5SDimitry Andric InDiag = diag::note_protected_by_vla;
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric if (VD->hasAttr<BlocksAttr>())
1520b57cec5SDimitry Andric return ScopePair(diag::note_protected_by___block,
1530b57cec5SDimitry Andric diag::note_exits___block);
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric if (VD->hasAttr<CleanupAttr>())
1560b57cec5SDimitry Andric return ScopePair(diag::note_protected_by_cleanup,
1570b57cec5SDimitry Andric diag::note_exits_cleanup);
1580b57cec5SDimitry Andric
1590b57cec5SDimitry Andric if (VD->hasLocalStorage()) {
1600b57cec5SDimitry Andric switch (VD->getType().isDestructedType()) {
1610b57cec5SDimitry Andric case QualType::DK_objc_strong_lifetime:
1620b57cec5SDimitry Andric return ScopePair(diag::note_protected_by_objc_strong_init,
1630b57cec5SDimitry Andric diag::note_exits_objc_strong);
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric case QualType::DK_objc_weak_lifetime:
1660b57cec5SDimitry Andric return ScopePair(diag::note_protected_by_objc_weak_init,
1670b57cec5SDimitry Andric diag::note_exits_objc_weak);
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andric case QualType::DK_nontrivial_c_struct:
1700b57cec5SDimitry Andric return ScopePair(diag::note_protected_by_non_trivial_c_struct_init,
1710b57cec5SDimitry Andric diag::note_exits_dtor);
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric case QualType::DK_cxx_destructor:
1740b57cec5SDimitry Andric OutDiag = diag::note_exits_dtor;
1750b57cec5SDimitry Andric break;
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric case QualType::DK_none:
1780b57cec5SDimitry Andric break;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric const Expr *Init = VD->getInit();
183*0fca6ea1SDimitry Andric if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init &&
184*0fca6ea1SDimitry Andric !Init->containsErrors()) {
1850b57cec5SDimitry Andric // C++11 [stmt.dcl]p3:
1860b57cec5SDimitry Andric // A program that jumps from a point where a variable with automatic
1870b57cec5SDimitry Andric // storage duration is not in scope to a point where it is in scope
1880b57cec5SDimitry Andric // is ill-formed unless the variable has scalar type, class type with
1890b57cec5SDimitry Andric // a trivial default constructor and a trivial destructor, a
1900b57cec5SDimitry Andric // cv-qualified version of one of these types, or an array of one of
1910b57cec5SDimitry Andric // the preceding types and is declared without an initializer.
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric // C++03 [stmt.dcl.p3:
1940b57cec5SDimitry Andric // A program that jumps from a point where a local variable
1950b57cec5SDimitry Andric // with automatic storage duration is not in scope to a point
1960b57cec5SDimitry Andric // where it is in scope is ill-formed unless the variable has
1970b57cec5SDimitry Andric // POD type and is declared without an initializer.
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric InDiag = diag::note_protected_by_variable_init;
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric // For a variable of (array of) class type declared without an
2020b57cec5SDimitry Andric // initializer, we will have call-style initialization and the initializer
2030b57cec5SDimitry Andric // will be the CXXConstructExpr with no intervening nodes.
2040b57cec5SDimitry Andric if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
2050b57cec5SDimitry Andric const CXXConstructorDecl *Ctor = CCE->getConstructor();
2060b57cec5SDimitry Andric if (Ctor->isTrivial() && Ctor->isDefaultConstructor() &&
2070b57cec5SDimitry Andric VD->getInitStyle() == VarDecl::CallInit) {
2080b57cec5SDimitry Andric if (OutDiag)
2090b57cec5SDimitry Andric InDiag = diag::note_protected_by_variable_nontriv_destructor;
2100b57cec5SDimitry Andric else if (!Ctor->getParent()->isPOD())
2110b57cec5SDimitry Andric InDiag = diag::note_protected_by_variable_non_pod;
2120b57cec5SDimitry Andric else
2130b57cec5SDimitry Andric InDiag = 0;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric return ScopePair(InDiag, OutDiag);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
2220b57cec5SDimitry Andric if (TD->getUnderlyingType()->isVariablyModifiedType())
2230b57cec5SDimitry Andric return ScopePair(isa<TypedefDecl>(TD)
2240b57cec5SDimitry Andric ? diag::note_protected_by_vla_typedef
2250b57cec5SDimitry Andric : diag::note_protected_by_vla_type_alias,
2260b57cec5SDimitry Andric 0);
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric return ScopePair(0U, 0U);
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric /// Build scope information for a declaration that is part of a DeclStmt.
BuildScopeInformation(Decl * D,unsigned & ParentScope)2330b57cec5SDimitry Andric void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
2340b57cec5SDimitry Andric // If this decl causes a new scope, push and switch to it.
2350b57cec5SDimitry Andric std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D);
2360b57cec5SDimitry Andric if (Diags.first || Diags.second) {
2370b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
2380b57cec5SDimitry Andric D->getLocation()));
2390b57cec5SDimitry Andric ParentScope = Scopes.size()-1;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric // If the decl has an initializer, walk it with the potentially new
2430b57cec5SDimitry Andric // scope we just installed.
2440b57cec5SDimitry Andric if (VarDecl *VD = dyn_cast<VarDecl>(D))
2450b57cec5SDimitry Andric if (Expr *Init = VD->getInit())
2460b57cec5SDimitry Andric BuildScopeInformation(Init, ParentScope);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric /// Build scope information for a captured block literal variables.
BuildScopeInformation(VarDecl * D,const BlockDecl * BDecl,unsigned & ParentScope)2500b57cec5SDimitry Andric void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
2510b57cec5SDimitry Andric const BlockDecl *BDecl,
2520b57cec5SDimitry Andric unsigned &ParentScope) {
2530b57cec5SDimitry Andric // exclude captured __block variables; there's no destructor
2540b57cec5SDimitry Andric // associated with the block literal for them.
2550b57cec5SDimitry Andric if (D->hasAttr<BlocksAttr>())
2560b57cec5SDimitry Andric return;
2570b57cec5SDimitry Andric QualType T = D->getType();
2580b57cec5SDimitry Andric QualType::DestructionKind destructKind = T.isDestructedType();
2590b57cec5SDimitry Andric if (destructKind != QualType::DK_none) {
2600b57cec5SDimitry Andric std::pair<unsigned,unsigned> Diags;
2610b57cec5SDimitry Andric switch (destructKind) {
2620b57cec5SDimitry Andric case QualType::DK_cxx_destructor:
2630b57cec5SDimitry Andric Diags = ScopePair(diag::note_enters_block_captures_cxx_obj,
2640b57cec5SDimitry Andric diag::note_exits_block_captures_cxx_obj);
2650b57cec5SDimitry Andric break;
2660b57cec5SDimitry Andric case QualType::DK_objc_strong_lifetime:
2670b57cec5SDimitry Andric Diags = ScopePair(diag::note_enters_block_captures_strong,
2680b57cec5SDimitry Andric diag::note_exits_block_captures_strong);
2690b57cec5SDimitry Andric break;
2700b57cec5SDimitry Andric case QualType::DK_objc_weak_lifetime:
2710b57cec5SDimitry Andric Diags = ScopePair(diag::note_enters_block_captures_weak,
2720b57cec5SDimitry Andric diag::note_exits_block_captures_weak);
2730b57cec5SDimitry Andric break;
2740b57cec5SDimitry Andric case QualType::DK_nontrivial_c_struct:
2750b57cec5SDimitry Andric Diags = ScopePair(diag::note_enters_block_captures_non_trivial_c_struct,
2760b57cec5SDimitry Andric diag::note_exits_block_captures_non_trivial_c_struct);
2770b57cec5SDimitry Andric break;
2780b57cec5SDimitry Andric case QualType::DK_none:
2790b57cec5SDimitry Andric llvm_unreachable("non-lifetime captured variable");
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric SourceLocation Loc = D->getLocation();
2820b57cec5SDimitry Andric if (Loc.isInvalid())
2830b57cec5SDimitry Andric Loc = BDecl->getLocation();
2840b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
2850b57cec5SDimitry Andric Diags.first, Diags.second, Loc));
2860b57cec5SDimitry Andric ParentScope = Scopes.size()-1;
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
2905ffd83dbSDimitry Andric /// Build scope information for compound literals of C struct types that are
2915ffd83dbSDimitry Andric /// non-trivial to destruct.
BuildScopeInformation(CompoundLiteralExpr * CLE,unsigned & ParentScope)2925ffd83dbSDimitry Andric void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE,
2935ffd83dbSDimitry Andric unsigned &ParentScope) {
2945ffd83dbSDimitry Andric unsigned InDiag = diag::note_enters_compound_literal_scope;
2955ffd83dbSDimitry Andric unsigned OutDiag = diag::note_exits_compound_literal_scope;
2965ffd83dbSDimitry Andric Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc()));
2975ffd83dbSDimitry Andric ParentScope = Scopes.size() - 1;
2985ffd83dbSDimitry Andric }
2995ffd83dbSDimitry Andric
3000b57cec5SDimitry Andric /// BuildScopeInformation - The statements from CI to CE are known to form a
3010b57cec5SDimitry Andric /// coherent VLA scope with a specified parent node. Walk through the
3020b57cec5SDimitry Andric /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
3030b57cec5SDimitry Andric /// walking the AST as needed.
BuildScopeInformation(Stmt * S,unsigned & origParentScope)3040b57cec5SDimitry Andric void JumpScopeChecker::BuildScopeInformation(Stmt *S,
3050b57cec5SDimitry Andric unsigned &origParentScope) {
3060b57cec5SDimitry Andric // If this is a statement, rather than an expression, scopes within it don't
3070b57cec5SDimitry Andric // propagate out into the enclosing scope. Otherwise we have to worry
3080b57cec5SDimitry Andric // about block literals, which have the lifetime of their enclosing statement.
3090b57cec5SDimitry Andric unsigned independentParentScope = origParentScope;
3100b57cec5SDimitry Andric unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
3110b57cec5SDimitry Andric ? origParentScope : independentParentScope);
3120b57cec5SDimitry Andric
3130b57cec5SDimitry Andric unsigned StmtsToSkip = 0u;
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric // If we found a label, remember that it is in ParentScope scope.
3160b57cec5SDimitry Andric switch (S->getStmtClass()) {
3170b57cec5SDimitry Andric case Stmt::AddrLabelExprClass:
3180b57cec5SDimitry Andric IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
3190b57cec5SDimitry Andric break;
3200b57cec5SDimitry Andric
3210b57cec5SDimitry Andric case Stmt::ObjCForCollectionStmtClass: {
3220b57cec5SDimitry Andric auto *CS = cast<ObjCForCollectionStmt>(S);
3230b57cec5SDimitry Andric unsigned Diag = diag::note_protected_by_objc_fast_enumeration;
3240b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
3250b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getBeginLoc()));
3260b57cec5SDimitry Andric BuildScopeInformation(CS->getBody(), NewParentScope);
3270b57cec5SDimitry Andric return;
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric
3300b57cec5SDimitry Andric case Stmt::IndirectGotoStmtClass:
3310b57cec5SDimitry Andric // "goto *&&lbl;" is a special case which we treat as equivalent
3320b57cec5SDimitry Andric // to a normal goto. In addition, we don't calculate scope in the
3330b57cec5SDimitry Andric // operand (to avoid recording the address-of-label use), which
3340b57cec5SDimitry Andric // works only because of the restricted set of expressions which
3350b57cec5SDimitry Andric // we detect as constant targets.
33606c3fb27SDimitry Andric if (cast<IndirectGotoStmt>(S)->getConstantTarget())
33706c3fb27SDimitry Andric goto RecordJumpScope;
3380b57cec5SDimitry Andric
3390b57cec5SDimitry Andric LabelAndGotoScopes[S] = ParentScope;
3400b57cec5SDimitry Andric IndirectJumps.push_back(S);
3410b57cec5SDimitry Andric break;
3420b57cec5SDimitry Andric
3430b57cec5SDimitry Andric case Stmt::SwitchStmtClass:
3440b57cec5SDimitry Andric // Evaluate the C++17 init stmt and condition variable
3450b57cec5SDimitry Andric // before entering the scope of the switch statement.
3460b57cec5SDimitry Andric if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
3470b57cec5SDimitry Andric BuildScopeInformation(Init, ParentScope);
3480b57cec5SDimitry Andric ++StmtsToSkip;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
3510b57cec5SDimitry Andric BuildScopeInformation(Var, ParentScope);
3520b57cec5SDimitry Andric ++StmtsToSkip;
3530b57cec5SDimitry Andric }
35406c3fb27SDimitry Andric goto RecordJumpScope;
35506c3fb27SDimitry Andric
35606c3fb27SDimitry Andric case Stmt::GCCAsmStmtClass:
35706c3fb27SDimitry Andric if (!cast<GCCAsmStmt>(S)->isAsmGoto())
35806c3fb27SDimitry Andric break;
359bdd1243dSDimitry Andric [[fallthrough]];
3600b57cec5SDimitry Andric
3610b57cec5SDimitry Andric case Stmt::GotoStmtClass:
36206c3fb27SDimitry Andric RecordJumpScope:
3630b57cec5SDimitry Andric // Remember both what scope a goto is in as well as the fact that we have
3640b57cec5SDimitry Andric // it. This makes the second scan not have to walk the AST again.
3650b57cec5SDimitry Andric LabelAndGotoScopes[S] = ParentScope;
3660b57cec5SDimitry Andric Jumps.push_back(S);
3670b57cec5SDimitry Andric break;
3680b57cec5SDimitry Andric
3690b57cec5SDimitry Andric case Stmt::IfStmtClass: {
3700b57cec5SDimitry Andric IfStmt *IS = cast<IfStmt>(S);
371349cc55cSDimitry Andric if (!(IS->isConstexpr() || IS->isConsteval() ||
372349cc55cSDimitry Andric IS->isObjCAvailabilityCheck()))
3730b57cec5SDimitry Andric break;
3740b57cec5SDimitry Andric
375349cc55cSDimitry Andric unsigned Diag = diag::note_protected_by_if_available;
376349cc55cSDimitry Andric if (IS->isConstexpr())
377349cc55cSDimitry Andric Diag = diag::note_protected_by_constexpr_if;
378349cc55cSDimitry Andric else if (IS->isConsteval())
379349cc55cSDimitry Andric Diag = diag::note_protected_by_consteval_if;
3800b57cec5SDimitry Andric
3810b57cec5SDimitry Andric if (VarDecl *Var = IS->getConditionVariable())
3820b57cec5SDimitry Andric BuildScopeInformation(Var, ParentScope);
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric // Cannot jump into the middle of the condition.
3850b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
3860b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));
387349cc55cSDimitry Andric
388349cc55cSDimitry Andric if (!IS->isConsteval())
3890b57cec5SDimitry Andric BuildScopeInformation(IS->getCond(), NewParentScope);
3900b57cec5SDimitry Andric
3910b57cec5SDimitry Andric // Jumps into either arm of an 'if constexpr' are not allowed.
3920b57cec5SDimitry Andric NewParentScope = Scopes.size();
3930b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));
3940b57cec5SDimitry Andric BuildScopeInformation(IS->getThen(), NewParentScope);
3950b57cec5SDimitry Andric if (Stmt *Else = IS->getElse()) {
3960b57cec5SDimitry Andric NewParentScope = Scopes.size();
3970b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc()));
3980b57cec5SDimitry Andric BuildScopeInformation(Else, NewParentScope);
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric return;
4010b57cec5SDimitry Andric }
4020b57cec5SDimitry Andric
4030b57cec5SDimitry Andric case Stmt::CXXTryStmtClass: {
4040b57cec5SDimitry Andric CXXTryStmt *TS = cast<CXXTryStmt>(S);
4050b57cec5SDimitry Andric {
4060b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4070b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4080b57cec5SDimitry Andric diag::note_protected_by_cxx_try,
4090b57cec5SDimitry Andric diag::note_exits_cxx_try,
4100b57cec5SDimitry Andric TS->getSourceRange().getBegin()));
4110b57cec5SDimitry Andric if (Stmt *TryBlock = TS->getTryBlock())
4120b57cec5SDimitry Andric BuildScopeInformation(TryBlock, NewParentScope);
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric // Jump from the catch into the try is not allowed either.
4160b57cec5SDimitry Andric for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
4170b57cec5SDimitry Andric CXXCatchStmt *CS = TS->getHandler(I);
4180b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4190b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4200b57cec5SDimitry Andric diag::note_protected_by_cxx_catch,
4210b57cec5SDimitry Andric diag::note_exits_cxx_catch,
4220b57cec5SDimitry Andric CS->getSourceRange().getBegin()));
4230b57cec5SDimitry Andric BuildScopeInformation(CS->getHandlerBlock(), NewParentScope);
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric return;
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andric case Stmt::SEHTryStmtClass: {
4290b57cec5SDimitry Andric SEHTryStmt *TS = cast<SEHTryStmt>(S);
4300b57cec5SDimitry Andric {
4310b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4320b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4330b57cec5SDimitry Andric diag::note_protected_by_seh_try,
4340b57cec5SDimitry Andric diag::note_exits_seh_try,
4350b57cec5SDimitry Andric TS->getSourceRange().getBegin()));
4360b57cec5SDimitry Andric if (Stmt *TryBlock = TS->getTryBlock())
4370b57cec5SDimitry Andric BuildScopeInformation(TryBlock, NewParentScope);
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric
4400b57cec5SDimitry Andric // Jump from __except or __finally into the __try are not allowed either.
4410b57cec5SDimitry Andric if (SEHExceptStmt *Except = TS->getExceptHandler()) {
4420b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4430b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4440b57cec5SDimitry Andric diag::note_protected_by_seh_except,
4450b57cec5SDimitry Andric diag::note_exits_seh_except,
4460b57cec5SDimitry Andric Except->getSourceRange().getBegin()));
4470b57cec5SDimitry Andric BuildScopeInformation(Except->getBlock(), NewParentScope);
4480b57cec5SDimitry Andric } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) {
4490b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4500b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4510b57cec5SDimitry Andric diag::note_protected_by_seh_finally,
4520b57cec5SDimitry Andric diag::note_exits_seh_finally,
4530b57cec5SDimitry Andric Finally->getSourceRange().getBegin()));
4540b57cec5SDimitry Andric BuildScopeInformation(Finally->getBlock(), NewParentScope);
4550b57cec5SDimitry Andric }
4560b57cec5SDimitry Andric
4570b57cec5SDimitry Andric return;
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric case Stmt::DeclStmtClass: {
4610b57cec5SDimitry Andric // If this is a declstmt with a VLA definition, it defines a scope from here
4620b57cec5SDimitry Andric // to the end of the containing context.
4630b57cec5SDimitry Andric DeclStmt *DS = cast<DeclStmt>(S);
4640b57cec5SDimitry Andric // The decl statement creates a scope if any of the decls in it are VLAs
4650b57cec5SDimitry Andric // or have the cleanup attribute.
4660b57cec5SDimitry Andric for (auto *I : DS->decls())
4670b57cec5SDimitry Andric BuildScopeInformation(I, origParentScope);
4680b57cec5SDimitry Andric return;
4690b57cec5SDimitry Andric }
4700b57cec5SDimitry Andric
47106c3fb27SDimitry Andric case Stmt::StmtExprClass: {
47206c3fb27SDimitry Andric // [GNU]
47306c3fb27SDimitry Andric // Jumping into a statement expression with goto or using
47406c3fb27SDimitry Andric // a switch statement outside the statement expression with
47506c3fb27SDimitry Andric // a case or default label inside the statement expression is not permitted.
47606c3fb27SDimitry Andric // Jumping out of a statement expression is permitted.
47706c3fb27SDimitry Andric StmtExpr *SE = cast<StmtExpr>(S);
47806c3fb27SDimitry Andric unsigned NewParentScope = Scopes.size();
47906c3fb27SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
48006c3fb27SDimitry Andric diag::note_enters_statement_expression,
48106c3fb27SDimitry Andric /*OutDiag=*/0, SE->getBeginLoc()));
48206c3fb27SDimitry Andric BuildScopeInformation(SE->getSubStmt(), NewParentScope);
48306c3fb27SDimitry Andric return;
48406c3fb27SDimitry Andric }
48506c3fb27SDimitry Andric
4860b57cec5SDimitry Andric case Stmt::ObjCAtTryStmtClass: {
4870b57cec5SDimitry Andric // Disallow jumps into any part of an @try statement by pushing a scope and
4880b57cec5SDimitry Andric // walking all sub-stmts in that scope.
4890b57cec5SDimitry Andric ObjCAtTryStmt *AT = cast<ObjCAtTryStmt>(S);
4900b57cec5SDimitry Andric // Recursively walk the AST for the @try part.
4910b57cec5SDimitry Andric {
4920b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
4930b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
4940b57cec5SDimitry Andric diag::note_protected_by_objc_try,
4950b57cec5SDimitry Andric diag::note_exits_objc_try,
4960b57cec5SDimitry Andric AT->getAtTryLoc()));
4970b57cec5SDimitry Andric if (Stmt *TryPart = AT->getTryBody())
4980b57cec5SDimitry Andric BuildScopeInformation(TryPart, NewParentScope);
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric
5010b57cec5SDimitry Andric // Jump from the catch to the finally or try is not valid.
502349cc55cSDimitry Andric for (ObjCAtCatchStmt *AC : AT->catch_stmts()) {
5030b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
5040b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
5050b57cec5SDimitry Andric diag::note_protected_by_objc_catch,
5060b57cec5SDimitry Andric diag::note_exits_objc_catch,
5070b57cec5SDimitry Andric AC->getAtCatchLoc()));
5080b57cec5SDimitry Andric // @catches are nested and it isn't
5090b57cec5SDimitry Andric BuildScopeInformation(AC->getCatchBody(), NewParentScope);
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric
5120b57cec5SDimitry Andric // Jump from the finally to the try or catch is not valid.
5130b57cec5SDimitry Andric if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
5140b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
5150b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
5160b57cec5SDimitry Andric diag::note_protected_by_objc_finally,
5170b57cec5SDimitry Andric diag::note_exits_objc_finally,
5180b57cec5SDimitry Andric AF->getAtFinallyLoc()));
5190b57cec5SDimitry Andric BuildScopeInformation(AF, NewParentScope);
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric
5220b57cec5SDimitry Andric return;
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric
5250b57cec5SDimitry Andric case Stmt::ObjCAtSynchronizedStmtClass: {
5260b57cec5SDimitry Andric // Disallow jumps into the protected statement of an @synchronized, but
5270b57cec5SDimitry Andric // allow jumps into the object expression it protects.
5280b57cec5SDimitry Andric ObjCAtSynchronizedStmt *AS = cast<ObjCAtSynchronizedStmt>(S);
5290b57cec5SDimitry Andric // Recursively walk the AST for the @synchronized object expr, it is
5300b57cec5SDimitry Andric // evaluated in the normal scope.
5310b57cec5SDimitry Andric BuildScopeInformation(AS->getSynchExpr(), ParentScope);
5320b57cec5SDimitry Andric
5330b57cec5SDimitry Andric // Recursively walk the AST for the @synchronized part, protected by a new
5340b57cec5SDimitry Andric // scope.
5350b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
5360b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
5370b57cec5SDimitry Andric diag::note_protected_by_objc_synchronized,
5380b57cec5SDimitry Andric diag::note_exits_objc_synchronized,
5390b57cec5SDimitry Andric AS->getAtSynchronizedLoc()));
5400b57cec5SDimitry Andric BuildScopeInformation(AS->getSynchBody(), NewParentScope);
5410b57cec5SDimitry Andric return;
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric
5440b57cec5SDimitry Andric case Stmt::ObjCAutoreleasePoolStmtClass: {
5450b57cec5SDimitry Andric // Disallow jumps into the protected statement of an @autoreleasepool.
5460b57cec5SDimitry Andric ObjCAutoreleasePoolStmt *AS = cast<ObjCAutoreleasePoolStmt>(S);
5470b57cec5SDimitry Andric // Recursively walk the AST for the @autoreleasepool part, protected by a
5480b57cec5SDimitry Andric // new scope.
5490b57cec5SDimitry Andric unsigned NewParentScope = Scopes.size();
5500b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope,
5510b57cec5SDimitry Andric diag::note_protected_by_objc_autoreleasepool,
5520b57cec5SDimitry Andric diag::note_exits_objc_autoreleasepool,
5530b57cec5SDimitry Andric AS->getAtLoc()));
5540b57cec5SDimitry Andric BuildScopeInformation(AS->getSubStmt(), NewParentScope);
5550b57cec5SDimitry Andric return;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric
5580b57cec5SDimitry Andric case Stmt::ExprWithCleanupsClass: {
5590b57cec5SDimitry Andric // Disallow jumps past full-expressions that use blocks with
5600b57cec5SDimitry Andric // non-trivial cleanups of their captures. This is theoretically
5610b57cec5SDimitry Andric // implementable but a lot of work which we haven't felt up to doing.
5620b57cec5SDimitry Andric ExprWithCleanups *EWC = cast<ExprWithCleanups>(S);
5630b57cec5SDimitry Andric for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
5645ffd83dbSDimitry Andric if (auto *BDecl = EWC->getObject(i).dyn_cast<BlockDecl *>())
5650b57cec5SDimitry Andric for (const auto &CI : BDecl->captures()) {
5660b57cec5SDimitry Andric VarDecl *variable = CI.getVariable();
5670b57cec5SDimitry Andric BuildScopeInformation(variable, BDecl, origParentScope);
5680b57cec5SDimitry Andric }
5695ffd83dbSDimitry Andric else if (auto *CLE = EWC->getObject(i).dyn_cast<CompoundLiteralExpr *>())
5705ffd83dbSDimitry Andric BuildScopeInformation(CLE, origParentScope);
5715ffd83dbSDimitry Andric else
5725ffd83dbSDimitry Andric llvm_unreachable("unexpected cleanup object type");
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric break;
5750b57cec5SDimitry Andric }
5760b57cec5SDimitry Andric
5770b57cec5SDimitry Andric case Stmt::MaterializeTemporaryExprClass: {
5780b57cec5SDimitry Andric // Disallow jumps out of scopes containing temporaries lifetime-extended to
5790b57cec5SDimitry Andric // automatic storage duration.
5800b57cec5SDimitry Andric MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
5810b57cec5SDimitry Andric if (MTE->getStorageDuration() == SD_Automatic) {
5820b57cec5SDimitry Andric const Expr *ExtendedObject =
583*0fca6ea1SDimitry Andric MTE->getSubExpr()->skipRValueSubobjectAdjustments();
5840b57cec5SDimitry Andric if (ExtendedObject->getType().isDestructedType()) {
5850b57cec5SDimitry Andric Scopes.push_back(GotoScope(ParentScope, 0,
5860b57cec5SDimitry Andric diag::note_exits_temporary_dtor,
5870b57cec5SDimitry Andric ExtendedObject->getExprLoc()));
5880b57cec5SDimitry Andric origParentScope = Scopes.size()-1;
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric break;
5920b57cec5SDimitry Andric }
5930b57cec5SDimitry Andric
5940b57cec5SDimitry Andric case Stmt::CaseStmtClass:
5950b57cec5SDimitry Andric case Stmt::DefaultStmtClass:
5960b57cec5SDimitry Andric case Stmt::LabelStmtClass:
5970b57cec5SDimitry Andric LabelAndGotoScopes[S] = ParentScope;
5980b57cec5SDimitry Andric break;
5990b57cec5SDimitry Andric
600fe6060f1SDimitry Andric case Stmt::AttributedStmtClass: {
601fe6060f1SDimitry Andric AttributedStmt *AS = cast<AttributedStmt>(S);
602fe6060f1SDimitry Andric if (GetMustTailAttr(AS)) {
603fe6060f1SDimitry Andric LabelAndGotoScopes[AS] = ParentScope;
604fe6060f1SDimitry Andric MustTailStmts.push_back(AS);
605fe6060f1SDimitry Andric }
606fe6060f1SDimitry Andric break;
607fe6060f1SDimitry Andric }
608fe6060f1SDimitry Andric
609*0fca6ea1SDimitry Andric case Stmt::OpenACCComputeConstructClass: {
610*0fca6ea1SDimitry Andric unsigned NewParentScope = Scopes.size();
611*0fca6ea1SDimitry Andric OpenACCComputeConstruct *CC = cast<OpenACCComputeConstruct>(S);
612*0fca6ea1SDimitry Andric Scopes.push_back(GotoScope(
613*0fca6ea1SDimitry Andric ParentScope, diag::note_acc_branch_into_compute_construct,
614*0fca6ea1SDimitry Andric diag::note_acc_branch_out_of_compute_construct, CC->getBeginLoc()));
615*0fca6ea1SDimitry Andric BuildScopeInformation(CC->getStructuredBlock(), NewParentScope);
616*0fca6ea1SDimitry Andric return;
617*0fca6ea1SDimitry Andric }
618*0fca6ea1SDimitry Andric
6190b57cec5SDimitry Andric default:
620e8d8bef9SDimitry Andric if (auto *ED = dyn_cast<OMPExecutableDirective>(S)) {
621e8d8bef9SDimitry Andric if (!ED->isStandaloneDirective()) {
622e8d8bef9SDimitry Andric unsigned NewParentScope = Scopes.size();
623e8d8bef9SDimitry Andric Scopes.emplace_back(ParentScope,
624e8d8bef9SDimitry Andric diag::note_omp_protected_structured_block,
625e8d8bef9SDimitry Andric diag::note_omp_exits_structured_block,
626e8d8bef9SDimitry Andric ED->getStructuredBlock()->getBeginLoc());
627e8d8bef9SDimitry Andric BuildScopeInformation(ED->getStructuredBlock(), NewParentScope);
628e8d8bef9SDimitry Andric return;
629e8d8bef9SDimitry Andric }
630e8d8bef9SDimitry Andric }
6310b57cec5SDimitry Andric break;
6320b57cec5SDimitry Andric }
6330b57cec5SDimitry Andric
6340b57cec5SDimitry Andric for (Stmt *SubStmt : S->children()) {
6350b57cec5SDimitry Andric if (!SubStmt)
6360b57cec5SDimitry Andric continue;
6370b57cec5SDimitry Andric if (StmtsToSkip) {
6380b57cec5SDimitry Andric --StmtsToSkip;
6390b57cec5SDimitry Andric continue;
6400b57cec5SDimitry Andric }
6410b57cec5SDimitry Andric
6420b57cec5SDimitry Andric // Cases, labels, and defaults aren't "scope parents". It's also
6430b57cec5SDimitry Andric // important to handle these iteratively instead of recursively in
6440b57cec5SDimitry Andric // order to avoid blowing out the stack.
6450b57cec5SDimitry Andric while (true) {
6460b57cec5SDimitry Andric Stmt *Next;
6470b57cec5SDimitry Andric if (SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
6480b57cec5SDimitry Andric Next = SC->getSubStmt();
6490b57cec5SDimitry Andric else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
6500b57cec5SDimitry Andric Next = LS->getSubStmt();
6510b57cec5SDimitry Andric else
6520b57cec5SDimitry Andric break;
6530b57cec5SDimitry Andric
6540b57cec5SDimitry Andric LabelAndGotoScopes[SubStmt] = ParentScope;
6550b57cec5SDimitry Andric SubStmt = Next;
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric
6580b57cec5SDimitry Andric // Recursively walk the AST.
6590b57cec5SDimitry Andric BuildScopeInformation(SubStmt, ParentScope);
6600b57cec5SDimitry Andric }
6610b57cec5SDimitry Andric }
6620b57cec5SDimitry Andric
6630b57cec5SDimitry Andric /// VerifyJumps - Verify each element of the Jumps array to see if they are
6640b57cec5SDimitry Andric /// valid, emitting diagnostics if not.
VerifyJumps()6650b57cec5SDimitry Andric void JumpScopeChecker::VerifyJumps() {
6660b57cec5SDimitry Andric while (!Jumps.empty()) {
6670b57cec5SDimitry Andric Stmt *Jump = Jumps.pop_back_val();
6680b57cec5SDimitry Andric
6690b57cec5SDimitry Andric // With a goto,
6700b57cec5SDimitry Andric if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
6710b57cec5SDimitry Andric // The label may not have a statement if it's coming from inline MS ASM.
6720b57cec5SDimitry Andric if (GS->getLabel()->getStmt()) {
6730b57cec5SDimitry Andric CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
6740b57cec5SDimitry Andric diag::err_goto_into_protected_scope,
6750b57cec5SDimitry Andric diag::ext_goto_into_protected_scope,
6760b57cec5SDimitry Andric diag::warn_cxx98_compat_goto_into_protected_scope);
6770b57cec5SDimitry Andric }
6780b57cec5SDimitry Andric CheckGotoStmt(GS);
6790b57cec5SDimitry Andric continue;
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric
68206c3fb27SDimitry Andric // If an asm goto jumps to a different scope, things like destructors or
68306c3fb27SDimitry Andric // initializers might not be run which may be suprising to users. Perhaps
68406c3fb27SDimitry Andric // this behavior can be changed in the future, but today Clang will not
68506c3fb27SDimitry Andric // generate such code. Produce a diagnostic instead. See also the
68606c3fb27SDimitry Andric // discussion here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110728.
68706c3fb27SDimitry Andric if (auto *G = dyn_cast<GCCAsmStmt>(Jump)) {
68806c3fb27SDimitry Andric for (AddrLabelExpr *L : G->labels()) {
68906c3fb27SDimitry Andric LabelDecl *LD = L->getLabel();
69006c3fb27SDimitry Andric unsigned JumpScope = LabelAndGotoScopes[G];
69106c3fb27SDimitry Andric unsigned TargetScope = LabelAndGotoScopes[LD->getStmt()];
69206c3fb27SDimitry Andric if (JumpScope != TargetScope)
69306c3fb27SDimitry Andric DiagnoseIndirectOrAsmJump(G, JumpScope, LD, TargetScope);
69406c3fb27SDimitry Andric }
69506c3fb27SDimitry Andric continue;
69606c3fb27SDimitry Andric }
69706c3fb27SDimitry Andric
6980b57cec5SDimitry Andric // We only get indirect gotos here when they have a constant target.
6990b57cec5SDimitry Andric if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) {
7000b57cec5SDimitry Andric LabelDecl *Target = IGS->getConstantTarget();
7010b57cec5SDimitry Andric CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),
7020b57cec5SDimitry Andric diag::err_goto_into_protected_scope,
7030b57cec5SDimitry Andric diag::ext_goto_into_protected_scope,
7040b57cec5SDimitry Andric diag::warn_cxx98_compat_goto_into_protected_scope);
7050b57cec5SDimitry Andric continue;
7060b57cec5SDimitry Andric }
7070b57cec5SDimitry Andric
7080b57cec5SDimitry Andric SwitchStmt *SS = cast<SwitchStmt>(Jump);
7090b57cec5SDimitry Andric for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
7100b57cec5SDimitry Andric SC = SC->getNextSwitchCase()) {
7110b57cec5SDimitry Andric if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC)))
7120b57cec5SDimitry Andric continue;
7130b57cec5SDimitry Andric SourceLocation Loc;
7140b57cec5SDimitry Andric if (CaseStmt *CS = dyn_cast<CaseStmt>(SC))
7150b57cec5SDimitry Andric Loc = CS->getBeginLoc();
7160b57cec5SDimitry Andric else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC))
7170b57cec5SDimitry Andric Loc = DS->getBeginLoc();
7180b57cec5SDimitry Andric else
7190b57cec5SDimitry Andric Loc = SC->getBeginLoc();
7200b57cec5SDimitry Andric CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0,
7210b57cec5SDimitry Andric diag::warn_cxx98_compat_switch_into_protected_scope);
7220b57cec5SDimitry Andric }
7230b57cec5SDimitry Andric }
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric
72606c3fb27SDimitry Andric /// VerifyIndirectJumps - Verify whether any possible indirect goto jump might
72706c3fb27SDimitry Andric /// cross a protection boundary. Unlike direct jumps, indirect goto jumps
72806c3fb27SDimitry Andric /// count cleanups as protection boundaries: since there's no way to know where
72906c3fb27SDimitry Andric /// the jump is going, we can't implicitly run the right cleanups the way we
73006c3fb27SDimitry Andric /// can with direct jumps. Thus, an indirect/asm jump is "trivial" if it
73106c3fb27SDimitry Andric /// bypasses no initializations and no teardowns. More formally, an
73206c3fb27SDimitry Andric /// indirect/asm jump from A to B is trivial if the path out from A to DCA(A,B)
73306c3fb27SDimitry Andric /// is trivial and the path in from DCA(A,B) to B is trivial, where DCA(A,B) is
73406c3fb27SDimitry Andric /// the deepest common ancestor of A and B. Jump-triviality is transitive but
73506c3fb27SDimitry Andric /// asymmetric.
7360b57cec5SDimitry Andric ///
7370b57cec5SDimitry Andric /// A path in is trivial if none of the entered scopes have an InDiag.
7380b57cec5SDimitry Andric /// A path out is trivial is none of the exited scopes have an OutDiag.
7390b57cec5SDimitry Andric ///
7400b57cec5SDimitry Andric /// Under these definitions, this function checks that the indirect
7410b57cec5SDimitry Andric /// jump between A and B is trivial for every indirect goto statement A
7420b57cec5SDimitry Andric /// and every label B whose address was taken in the function.
VerifyIndirectJumps()74306c3fb27SDimitry Andric void JumpScopeChecker::VerifyIndirectJumps() {
74406c3fb27SDimitry Andric if (IndirectJumps.empty())
7450b57cec5SDimitry Andric return;
7460b57cec5SDimitry Andric // If there aren't any address-of-label expressions in this function,
7470b57cec5SDimitry Andric // complain about the first indirect goto.
74806c3fb27SDimitry Andric if (IndirectJumpTargets.empty()) {
74906c3fb27SDimitry Andric S.Diag(IndirectJumps[0]->getBeginLoc(),
7500b57cec5SDimitry Andric diag::err_indirect_goto_without_addrlabel);
7510b57cec5SDimitry Andric return;
7520b57cec5SDimitry Andric }
75306c3fb27SDimitry Andric // Collect a single representative of every scope containing an indirect
75406c3fb27SDimitry Andric // goto. For most code bases, this substantially cuts down on the number of
75506c3fb27SDimitry Andric // jump sites we'll have to consider later.
75606c3fb27SDimitry Andric using JumpScope = std::pair<unsigned, Stmt *>;
7570b57cec5SDimitry Andric SmallVector<JumpScope, 32> JumpScopes;
7580b57cec5SDimitry Andric {
7590b57cec5SDimitry Andric llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
76006c3fb27SDimitry Andric for (Stmt *IG : IndirectJumps) {
7610b57cec5SDimitry Andric if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
7620b57cec5SDimitry Andric continue;
7630b57cec5SDimitry Andric unsigned IGScope = LabelAndGotoScopes[IG];
76406c3fb27SDimitry Andric if (!JumpScopesMap.contains(IGScope))
76506c3fb27SDimitry Andric JumpScopesMap[IGScope] = IG;
7660b57cec5SDimitry Andric }
7670b57cec5SDimitry Andric JumpScopes.reserve(JumpScopesMap.size());
76806c3fb27SDimitry Andric for (auto &Pair : JumpScopesMap)
76906c3fb27SDimitry Andric JumpScopes.emplace_back(Pair);
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric
7720b57cec5SDimitry Andric // Collect a single representative of every scope containing a
7730b57cec5SDimitry Andric // label whose address was taken somewhere in the function.
7740b57cec5SDimitry Andric // For most code bases, there will be only one such scope.
7750b57cec5SDimitry Andric llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
77606c3fb27SDimitry Andric for (LabelDecl *TheLabel : IndirectJumpTargets) {
7770b57cec5SDimitry Andric if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
7780b57cec5SDimitry Andric continue;
7790b57cec5SDimitry Andric unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()];
78006c3fb27SDimitry Andric if (!TargetScopes.contains(LabelScope))
78106c3fb27SDimitry Andric TargetScopes[LabelScope] = TheLabel;
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric
7840b57cec5SDimitry Andric // For each target scope, make sure it's trivially reachable from
7850b57cec5SDimitry Andric // every scope containing a jump site.
7860b57cec5SDimitry Andric //
7870b57cec5SDimitry Andric // A path between scopes always consists of exitting zero or more
7880b57cec5SDimitry Andric // scopes, then entering zero or more scopes. We build a set of
7890b57cec5SDimitry Andric // of scopes S from which the target scope can be trivially
7900b57cec5SDimitry Andric // entered, then verify that every jump scope can be trivially
7910b57cec5SDimitry Andric // exitted to reach a scope in S.
7920b57cec5SDimitry Andric llvm::BitVector Reachable(Scopes.size(), false);
79306c3fb27SDimitry Andric for (auto [TargetScope, TargetLabel] : TargetScopes) {
7940b57cec5SDimitry Andric Reachable.reset();
7950b57cec5SDimitry Andric
7960b57cec5SDimitry Andric // Mark all the enclosing scopes from which you can safely jump
7970b57cec5SDimitry Andric // into the target scope. 'Min' will end up being the index of
7980b57cec5SDimitry Andric // the shallowest such scope.
7990b57cec5SDimitry Andric unsigned Min = TargetScope;
8000b57cec5SDimitry Andric while (true) {
8010b57cec5SDimitry Andric Reachable.set(Min);
8020b57cec5SDimitry Andric
8030b57cec5SDimitry Andric // Don't go beyond the outermost scope.
8040b57cec5SDimitry Andric if (Min == 0) break;
8050b57cec5SDimitry Andric
8060b57cec5SDimitry Andric // Stop if we can't trivially enter the current scope.
8070b57cec5SDimitry Andric if (Scopes[Min].InDiag) break;
8080b57cec5SDimitry Andric
8090b57cec5SDimitry Andric Min = Scopes[Min].ParentScope;
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric
8120b57cec5SDimitry Andric // Walk through all the jump sites, checking that they can trivially
8130b57cec5SDimitry Andric // reach this label scope.
81406c3fb27SDimitry Andric for (auto [JumpScope, JumpStmt] : JumpScopes) {
81506c3fb27SDimitry Andric unsigned Scope = JumpScope;
8160b57cec5SDimitry Andric // Walk out the "scope chain" for this scope, looking for a scope
8170b57cec5SDimitry Andric // we've marked reachable. For well-formed code this amortizes
8180b57cec5SDimitry Andric // to O(JumpScopes.size() / Scopes.size()): we only iterate
8190b57cec5SDimitry Andric // when we see something unmarked, and in well-formed code we
8200b57cec5SDimitry Andric // mark everything we iterate past.
8210b57cec5SDimitry Andric bool IsReachable = false;
8220b57cec5SDimitry Andric while (true) {
8230b57cec5SDimitry Andric if (Reachable.test(Scope)) {
8240b57cec5SDimitry Andric // If we find something reachable, mark all the scopes we just
8250b57cec5SDimitry Andric // walked through as reachable.
82606c3fb27SDimitry Andric for (unsigned S = JumpScope; S != Scope; S = Scopes[S].ParentScope)
8270b57cec5SDimitry Andric Reachable.set(S);
8280b57cec5SDimitry Andric IsReachable = true;
8290b57cec5SDimitry Andric break;
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric
8320b57cec5SDimitry Andric // Don't walk out if we've reached the top-level scope or we've
8330b57cec5SDimitry Andric // gotten shallower than the shallowest reachable scope.
8340b57cec5SDimitry Andric if (Scope == 0 || Scope < Min) break;
8350b57cec5SDimitry Andric
8360b57cec5SDimitry Andric // Don't walk out through an out-diagnostic.
8370b57cec5SDimitry Andric if (Scopes[Scope].OutDiag) break;
8380b57cec5SDimitry Andric
8390b57cec5SDimitry Andric Scope = Scopes[Scope].ParentScope;
8400b57cec5SDimitry Andric }
8410b57cec5SDimitry Andric
8420b57cec5SDimitry Andric // Only diagnose if we didn't find something.
8430b57cec5SDimitry Andric if (IsReachable) continue;
8440b57cec5SDimitry Andric
84506c3fb27SDimitry Andric DiagnoseIndirectOrAsmJump(JumpStmt, JumpScope, TargetLabel, TargetScope);
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric }
8480b57cec5SDimitry Andric }
8490b57cec5SDimitry Andric
8500b57cec5SDimitry Andric /// Return true if a particular error+note combination must be downgraded to a
8510b57cec5SDimitry Andric /// warning in Microsoft mode.
IsMicrosoftJumpWarning(unsigned JumpDiag,unsigned InDiagNote)8520b57cec5SDimitry Andric static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) {
8530b57cec5SDimitry Andric return (JumpDiag == diag::err_goto_into_protected_scope &&
8540b57cec5SDimitry Andric (InDiagNote == diag::note_protected_by_variable_init ||
8550b57cec5SDimitry Andric InDiagNote == diag::note_protected_by_variable_nontriv_destructor));
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric
8580b57cec5SDimitry Andric /// Return true if a particular note should be downgraded to a compatibility
8590b57cec5SDimitry Andric /// warning in C++11 mode.
IsCXX98CompatWarning(Sema & S,unsigned InDiagNote)8600b57cec5SDimitry Andric static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
8610b57cec5SDimitry Andric return S.getLangOpts().CPlusPlus11 &&
8620b57cec5SDimitry Andric InDiagNote == diag::note_protected_by_variable_non_pod;
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric
8650b57cec5SDimitry Andric /// Produce primary diagnostic for an indirect jump statement.
DiagnoseIndirectOrAsmJumpStmt(Sema & S,Stmt * Jump,LabelDecl * Target,bool & Diagnosed)8660b57cec5SDimitry Andric static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
8670b57cec5SDimitry Andric LabelDecl *Target, bool &Diagnosed) {
8680b57cec5SDimitry Andric if (Diagnosed)
8690b57cec5SDimitry Andric return;
8700b57cec5SDimitry Andric bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
8710b57cec5SDimitry Andric S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
8720b57cec5SDimitry Andric << IsAsmGoto;
8730b57cec5SDimitry Andric S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
8740b57cec5SDimitry Andric << IsAsmGoto;
8750b57cec5SDimitry Andric Diagnosed = true;
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric
8780b57cec5SDimitry Andric /// Produce note diagnostics for a jump into a protected scope.
NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes)8790b57cec5SDimitry Andric void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
8800b57cec5SDimitry Andric if (CHECK_PERMISSIVE(ToScopes.empty()))
8810b57cec5SDimitry Andric return;
8820b57cec5SDimitry Andric for (unsigned I = 0, E = ToScopes.size(); I != E; ++I)
8830b57cec5SDimitry Andric if (Scopes[ToScopes[I]].InDiag)
8840b57cec5SDimitry Andric S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag);
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric
8870b57cec5SDimitry Andric /// Diagnose an indirect jump which is known to cross scopes.
DiagnoseIndirectOrAsmJump(Stmt * Jump,unsigned JumpScope,LabelDecl * Target,unsigned TargetScope)8880b57cec5SDimitry Andric void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
8890b57cec5SDimitry Andric LabelDecl *Target,
8900b57cec5SDimitry Andric unsigned TargetScope) {
8910b57cec5SDimitry Andric if (CHECK_PERMISSIVE(JumpScope == TargetScope))
8920b57cec5SDimitry Andric return;
8930b57cec5SDimitry Andric
8940b57cec5SDimitry Andric unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
8950b57cec5SDimitry Andric bool Diagnosed = false;
8960b57cec5SDimitry Andric
8970b57cec5SDimitry Andric // Walk out the scope chain until we reach the common ancestor.
8980b57cec5SDimitry Andric for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
8990b57cec5SDimitry Andric if (Scopes[I].OutDiag) {
9000b57cec5SDimitry Andric DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
9010b57cec5SDimitry Andric S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
9020b57cec5SDimitry Andric }
9030b57cec5SDimitry Andric
9040b57cec5SDimitry Andric SmallVector<unsigned, 10> ToScopesCXX98Compat;
9050b57cec5SDimitry Andric
9060b57cec5SDimitry Andric // Now walk into the scopes containing the label whose address was taken.
9070b57cec5SDimitry Andric for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
9080b57cec5SDimitry Andric if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
9090b57cec5SDimitry Andric ToScopesCXX98Compat.push_back(I);
9100b57cec5SDimitry Andric else if (Scopes[I].InDiag) {
9110b57cec5SDimitry Andric DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
9120b57cec5SDimitry Andric S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
9130b57cec5SDimitry Andric }
9140b57cec5SDimitry Andric
9150b57cec5SDimitry Andric // Diagnose this jump if it would be ill-formed in C++98.
9160b57cec5SDimitry Andric if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
9170b57cec5SDimitry Andric bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
9180b57cec5SDimitry Andric S.Diag(Jump->getBeginLoc(),
9190b57cec5SDimitry Andric diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
9200b57cec5SDimitry Andric << IsAsmGoto;
9210b57cec5SDimitry Andric S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
9220b57cec5SDimitry Andric << IsAsmGoto;
9230b57cec5SDimitry Andric NoteJumpIntoScopes(ToScopesCXX98Compat);
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric }
9260b57cec5SDimitry Andric
9270b57cec5SDimitry Andric /// CheckJump - Validate that the specified jump statement is valid: that it is
9280b57cec5SDimitry Andric /// jumping within or out of its current scope, not into a deeper one.
CheckJump(Stmt * From,Stmt * To,SourceLocation DiagLoc,unsigned JumpDiagError,unsigned JumpDiagWarning,unsigned JumpDiagCXX98Compat)9290b57cec5SDimitry Andric void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
9300b57cec5SDimitry Andric unsigned JumpDiagError, unsigned JumpDiagWarning,
9310b57cec5SDimitry Andric unsigned JumpDiagCXX98Compat) {
9320b57cec5SDimitry Andric if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(From)))
9330b57cec5SDimitry Andric return;
9340b57cec5SDimitry Andric if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(To)))
9350b57cec5SDimitry Andric return;
9360b57cec5SDimitry Andric
9370b57cec5SDimitry Andric unsigned FromScope = LabelAndGotoScopes[From];
9380b57cec5SDimitry Andric unsigned ToScope = LabelAndGotoScopes[To];
9390b57cec5SDimitry Andric
9400b57cec5SDimitry Andric // Common case: exactly the same scope, which is fine.
9410b57cec5SDimitry Andric if (FromScope == ToScope) return;
9420b57cec5SDimitry Andric
9430b57cec5SDimitry Andric // Warn on gotos out of __finally blocks.
9440b57cec5SDimitry Andric if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) {
9450b57cec5SDimitry Andric // If FromScope > ToScope, FromScope is more nested and the jump goes to a
9460b57cec5SDimitry Andric // less nested scope. Check if it crosses a __finally along the way.
9470b57cec5SDimitry Andric for (unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) {
9480b57cec5SDimitry Andric if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) {
9490b57cec5SDimitry Andric S.Diag(From->getBeginLoc(), diag::warn_jump_out_of_seh_finally);
9500b57cec5SDimitry Andric break;
951*0fca6ea1SDimitry Andric } else if (Scopes[I].InDiag ==
952*0fca6ea1SDimitry Andric diag::note_omp_protected_structured_block) {
953e8d8bef9SDimitry Andric S.Diag(From->getBeginLoc(), diag::err_goto_into_protected_scope);
954e8d8bef9SDimitry Andric S.Diag(To->getBeginLoc(), diag::note_omp_exits_structured_block);
955e8d8bef9SDimitry Andric break;
956*0fca6ea1SDimitry Andric } else if (Scopes[I].InDiag ==
957*0fca6ea1SDimitry Andric diag::note_acc_branch_into_compute_construct) {
958*0fca6ea1SDimitry Andric S.Diag(From->getBeginLoc(), diag::err_goto_into_protected_scope);
959*0fca6ea1SDimitry Andric S.Diag(Scopes[I].Loc, diag::note_acc_branch_out_of_compute_construct);
960*0fca6ea1SDimitry Andric return;
961e8d8bef9SDimitry Andric }
9620b57cec5SDimitry Andric }
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric
9650b57cec5SDimitry Andric unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
9660b57cec5SDimitry Andric
9670b57cec5SDimitry Andric // It's okay to jump out from a nested scope.
9680b57cec5SDimitry Andric if (CommonScope == ToScope) return;
9690b57cec5SDimitry Andric
9700b57cec5SDimitry Andric // Pull out (and reverse) any scopes we might need to diagnose skipping.
9710b57cec5SDimitry Andric SmallVector<unsigned, 10> ToScopesCXX98Compat;
9720b57cec5SDimitry Andric SmallVector<unsigned, 10> ToScopesError;
9730b57cec5SDimitry Andric SmallVector<unsigned, 10> ToScopesWarning;
9740b57cec5SDimitry Andric for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {
9750b57cec5SDimitry Andric if (S.getLangOpts().MSVCCompat && JumpDiagWarning != 0 &&
9760b57cec5SDimitry Andric IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag))
9770b57cec5SDimitry Andric ToScopesWarning.push_back(I);
9780b57cec5SDimitry Andric else if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
9790b57cec5SDimitry Andric ToScopesCXX98Compat.push_back(I);
9800b57cec5SDimitry Andric else if (Scopes[I].InDiag)
9810b57cec5SDimitry Andric ToScopesError.push_back(I);
9820b57cec5SDimitry Andric }
9830b57cec5SDimitry Andric
9840b57cec5SDimitry Andric // Handle warnings.
9850b57cec5SDimitry Andric if (!ToScopesWarning.empty()) {
9860b57cec5SDimitry Andric S.Diag(DiagLoc, JumpDiagWarning);
9870b57cec5SDimitry Andric NoteJumpIntoScopes(ToScopesWarning);
988fe6060f1SDimitry Andric assert(isa<LabelStmt>(To));
989fe6060f1SDimitry Andric LabelStmt *Label = cast<LabelStmt>(To);
990fe6060f1SDimitry Andric Label->setSideEntry(true);
9910b57cec5SDimitry Andric }
9920b57cec5SDimitry Andric
9930b57cec5SDimitry Andric // Handle errors.
9940b57cec5SDimitry Andric if (!ToScopesError.empty()) {
9950b57cec5SDimitry Andric S.Diag(DiagLoc, JumpDiagError);
9960b57cec5SDimitry Andric NoteJumpIntoScopes(ToScopesError);
9970b57cec5SDimitry Andric }
9980b57cec5SDimitry Andric
9990b57cec5SDimitry Andric // Handle -Wc++98-compat warnings if the jump is well-formed.
10000b57cec5SDimitry Andric if (ToScopesError.empty() && !ToScopesCXX98Compat.empty()) {
10010b57cec5SDimitry Andric S.Diag(DiagLoc, JumpDiagCXX98Compat);
10020b57cec5SDimitry Andric NoteJumpIntoScopes(ToScopesCXX98Compat);
10030b57cec5SDimitry Andric }
10040b57cec5SDimitry Andric }
10050b57cec5SDimitry Andric
CheckGotoStmt(GotoStmt * GS)10060b57cec5SDimitry Andric void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) {
10070b57cec5SDimitry Andric if (GS->getLabel()->isMSAsmLabel()) {
10080b57cec5SDimitry Andric S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label)
10090b57cec5SDimitry Andric << GS->getLabel()->getIdentifier();
10100b57cec5SDimitry Andric S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label)
10110b57cec5SDimitry Andric << GS->getLabel()->getIdentifier();
10120b57cec5SDimitry Andric }
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric
VerifyMustTailStmts()1015fe6060f1SDimitry Andric void JumpScopeChecker::VerifyMustTailStmts() {
1016fe6060f1SDimitry Andric for (AttributedStmt *AS : MustTailStmts) {
1017fe6060f1SDimitry Andric for (unsigned I = LabelAndGotoScopes[AS]; I; I = Scopes[I].ParentScope) {
1018fe6060f1SDimitry Andric if (Scopes[I].OutDiag) {
1019fe6060f1SDimitry Andric S.Diag(AS->getBeginLoc(), diag::err_musttail_scope);
1020fe6060f1SDimitry Andric S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
1021fe6060f1SDimitry Andric }
1022fe6060f1SDimitry Andric }
1023fe6060f1SDimitry Andric }
1024fe6060f1SDimitry Andric }
1025fe6060f1SDimitry Andric
GetMustTailAttr(AttributedStmt * AS)1026fe6060f1SDimitry Andric const Attr *JumpScopeChecker::GetMustTailAttr(AttributedStmt *AS) {
1027fe6060f1SDimitry Andric ArrayRef<const Attr *> Attrs = AS->getAttrs();
1028fe6060f1SDimitry Andric const auto *Iter =
1029fe6060f1SDimitry Andric llvm::find_if(Attrs, [](const Attr *A) { return isa<MustTailAttr>(A); });
1030fe6060f1SDimitry Andric return Iter != Attrs.end() ? *Iter : nullptr;
1031fe6060f1SDimitry Andric }
1032fe6060f1SDimitry Andric
DiagnoseInvalidJumps(Stmt * Body)10330b57cec5SDimitry Andric void Sema::DiagnoseInvalidJumps(Stmt *Body) {
10340b57cec5SDimitry Andric (void)JumpScopeChecker(Body, *this);
10350b57cec5SDimitry Andric }
1036