//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the JumpScopeChecker class, which is used to diagnose // jumps that enter a protected scope in an invalid way. // //===----------------------------------------------------------------------===// #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenACC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/BitVector.h" usingnamespaceclang; namespace { /// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps /// into VLA and other protected scopes. For example, this rejects: /// goto L; /// int a[n]; /// L: /// /// We also detect jumps out of protected scopes when it's not possible to do /// cleanups properly. Indirect jumps and ASM jumps can't do cleanups because /// the target is unknown. Return statements with \c [[clang::musttail]] cannot /// handle any cleanups due to the nature of a tail call. class JumpScopeChecker { … }; } // end anonymous namespace #define CHECK_PERMISSIVE(x) … JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : … { … } /// GetDeepestCommonScope - Finds the innermost scope enclosing the /// two scopes. unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { … } ScopePair; /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { … } /// Build scope information for a declaration that is part of a DeclStmt. void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { … } /// Build scope information for a captured block literal variables. void JumpScopeChecker::BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, unsigned &ParentScope) { … } /// Build scope information for compound literals of C struct types that are /// non-trivial to destruct. void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope) { … } /// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively /// walking the AST as needed. void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) { … } /// VerifyJumps - Verify each element of the Jumps array to see if they are /// valid, emitting diagnostics if not. void JumpScopeChecker::VerifyJumps() { … } /// VerifyIndirectJumps - Verify whether any possible indirect goto jump might /// cross a protection boundary. Unlike direct jumps, indirect goto jumps /// count cleanups as protection boundaries: since there's no way to know where /// the jump is going, we can't implicitly run the right cleanups the way we /// can with direct jumps. Thus, an indirect/asm jump is "trivial" if it /// bypasses no initializations and no teardowns. More formally, an /// indirect/asm jump from A to B is trivial if the path out from A to DCA(A,B) /// is trivial and the path in from DCA(A,B) to B is trivial, where DCA(A,B) is /// the deepest common ancestor of A and B. Jump-triviality is transitive but /// asymmetric. /// /// A path in is trivial if none of the entered scopes have an InDiag. /// A path out is trivial is none of the exited scopes have an OutDiag. /// /// Under these definitions, this function checks that the indirect /// jump between A and B is trivial for every indirect goto statement A /// and every label B whose address was taken in the function. void JumpScopeChecker::VerifyIndirectJumps() { … } /// Return true if a particular error+note combination must be downgraded to a /// warning in Microsoft mode. static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) { … } /// Return true if a particular note should be downgraded to a compatibility /// warning in C++11 mode. static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) { … } /// Produce primary diagnostic for an indirect jump statement. static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump, LabelDecl *Target, bool &Diagnosed) { … } /// Produce note diagnostics for a jump into a protected scope. void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) { … } /// Diagnose an indirect jump which is known to cross scopes. void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope, LabelDecl *Target, unsigned TargetScope) { … } /// CheckJump - Validate that the specified jump statement is valid: that it is /// jumping within or out of its current scope, not into a deeper one. void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiagError, unsigned JumpDiagWarning, unsigned JumpDiagCXX98Compat) { … } void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) { … } void JumpScopeChecker::VerifyMustTailStmts() { … } const Attr *JumpScopeChecker::GetMustTailAttr(AttributedStmt *AS) { … } void Sema::DiagnoseInvalidJumps(Stmt *Body) { … }