diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp | 169 |
1 files changed, 84 insertions, 85 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index d3de173..2558452 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -32,6 +32,10 @@ namespace { class JumpScopeChecker { Sema &S; + /// Permissive - True when recovering from errors, in which case precautions + /// are taken to handle incomplete scope information. + const bool Permissive; + /// GotoScope - This is a record that we use to keep track of all of the /// scopes that are introduced by VLAs and other things that scope jumps like /// gotos. This scope tree has nothing to do with the source scope tree, @@ -85,8 +89,10 @@ private: }; } // end anonymous namespace +#define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x))) -JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { +JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) + : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) { // Add a scope entry for function scope. Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); @@ -121,9 +127,11 @@ typedef std::pair<unsigned,unsigned> 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(ASTContext &Context, const Decl *D) { +static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { unsigned InDiag = 0; + unsigned OutDiag = 0; + if (VD->getType()->isVariablyModifiedType()) InDiag = diag::note_protected_by_vla; @@ -135,21 +143,24 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { return ScopePair(diag::note_protected_by_cleanup, diag::note_exits_cleanup); - if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) { - switch (VD->getType().getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - break; - - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Weak: + if (VD->hasLocalStorage()) { + switch (VD->getType().isDestructedType()) { + case QualType::DK_objc_strong_lifetime: + case QualType::DK_objc_weak_lifetime: return ScopePair(diag::note_protected_by_objc_ownership, diag::note_exits_objc_ownership); + + case QualType::DK_cxx_destructor: + OutDiag = diag::note_exits_dtor; + break; + + case QualType::DK_none: + break; } } - if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) { + const Expr *Init = VD->getInit(); + if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init) { // C++11 [stmt.dcl]p3: // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope @@ -164,68 +175,34 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { // where it is in scope is ill-formed unless the variable has // POD type and is declared without an initializer. - const Expr *Init = VD->getInit(); - if (!Init) - return ScopePair(InDiag, 0); - - const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init); - if (EWC) - Init = EWC->getSubExpr(); - - const MaterializeTemporaryExpr *M = NULL; - Init = Init->findMaterializedTemporary(M); - - SmallVector<const Expr *, 2> CommaLHSs; - SmallVector<SubobjectAdjustment, 2> Adjustments; - Init = Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); - - QualType QT = Init->getType(); - if (QT.isNull()) - return ScopePair(diag::note_protected_by_variable_init, 0); - - const Type *T = QT.getTypePtr(); - if (T->isArrayType()) - T = T->getBaseElementTypeUnsafe(); - - const CXXRecordDecl *Record = T->getAsCXXRecordDecl(); - if (!Record) - return ScopePair(diag::note_protected_by_variable_init, 0); + InDiag = diag::note_protected_by_variable_init; - // If we need to call a non trivial destructor for this variable, - // record an out diagnostic. - unsigned OutDiag = 0; - if (!Init->isGLValue() && !Record->hasTrivialDestructor()) - OutDiag = diag::note_exits_dtor; - - if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) { - const CXXConstructorDecl *ctor = cce->getConstructor(); - // For a variable declared without an initializer, we will have - // call-style initialization and the initializer will be the - // CXXConstructExpr with no intervening nodes. - if (ctor->isTrivial() && ctor->isDefaultConstructor() && - VD->getInit() == Init && VD->getInitStyle() == VarDecl::CallInit) { + // For a variable of (array of) class type declared without an + // initializer, we will have call-style initialization and the initializer + // will be the CXXConstructExpr with no intervening nodes. + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { + const CXXConstructorDecl *Ctor = CCE->getConstructor(); + if (Ctor->isTrivial() && Ctor->isDefaultConstructor() && + VD->getInitStyle() == VarDecl::CallInit) { if (OutDiag) InDiag = diag::note_protected_by_variable_nontriv_destructor; - else if (!Record->isPOD()) + else if (!Ctor->getParent()->isPOD()) InDiag = diag::note_protected_by_variable_non_pod; - return ScopePair(InDiag, OutDiag); + else + InDiag = 0; } } - - return ScopePair(diag::note_protected_by_variable_init, OutDiag); } - return ScopePair(InDiag, 0); - } - - if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { - if (TD->getUnderlyingType()->isVariablyModifiedType()) - return ScopePair(diag::note_protected_by_vla_typedef, 0); + return ScopePair(InDiag, OutDiag); } - if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { + if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) - return ScopePair(diag::note_protected_by_vla_type_alias, 0); + return ScopePair(isa<TypedefDecl>(TD) + ? diag::note_protected_by_vla_typedef + : diag::note_protected_by_vla_type_alias, + 0); } return ScopePair(0U, 0U); @@ -234,7 +211,7 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { /// \brief Build scope information for a declaration that is part of a DeclStmt. void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { // If this decl causes a new scope, push and switch to it. - std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D); + std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D); if (Diags.first || Diags.second) { Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, D->getLocation())); @@ -371,7 +348,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) } Stmt *SubStmt = *CI; - if (SubStmt == 0) continue; + if (!SubStmt) continue; // Cases, labels, and defaults aren't "scope parents". It's also // important to handle these iteratively instead of recursively in @@ -396,9 +373,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { // The decl statement creates a scope if any of the decls in it are VLAs // or have the cleanup attribute. - for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); - I != E; ++I) - BuildScopeInformation(*I, ParentScope); + for (auto *I : DS->decls()) + BuildScopeInformation(I, ParentScope); continue; } // Disallow jumps into any part of an @try statement by pushing a scope and @@ -474,14 +450,32 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) { for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { const BlockDecl *BDecl = EWC->getObject(i); - for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(), - ce = BDecl->capture_end(); ci != ce; ++ci) { - VarDecl *variable = ci->getVariable(); + for (const auto &CI : BDecl->captures()) { + VarDecl *variable = CI.getVariable(); BuildScopeInformation(variable, BDecl, ParentScope); } } } - + + // Disallow jumps out of scopes containing temporaries lifetime-extended to + // automatic storage duration. + if (MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(SubStmt)) { + if (MTE->getStorageDuration() == SD_Automatic) { + SmallVector<const Expr *, 4> CommaLHS; + SmallVector<SubobjectAdjustment, 4> Adjustments; + const Expr *ExtendedObject = + MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments( + CommaLHS, Adjustments); + if (ExtendedObject->getType().isDestructedType()) { + Scopes.push_back(GotoScope(ParentScope, 0, + diag::note_exits_temporary_dtor, + ExtendedObject->getExprLoc())); + ParentScope = Scopes.size()-1; + } + } + } + // Recursively walk the AST. BuildScopeInformation(SubStmt, ParentScope); } @@ -497,7 +491,7 @@ void JumpScopeChecker::VerifyJumps() { if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), diag::err_goto_into_protected_scope, - diag::warn_goto_into_protected_scope, + diag::ext_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); continue; } @@ -507,7 +501,7 @@ void JumpScopeChecker::VerifyJumps() { LabelDecl *Target = IGS->getConstantTarget(); CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), diag::err_goto_into_protected_scope, - diag::warn_goto_into_protected_scope, + diag::ext_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); continue; } @@ -515,7 +509,8 @@ void JumpScopeChecker::VerifyJumps() { SwitchStmt *SS = cast<SwitchStmt>(Jump); for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { - assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); + if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC))) + continue; SourceLocation Loc; if (CaseStmt *CS = dyn_cast<CaseStmt>(SC)) Loc = CS->getLocStart(); @@ -569,8 +564,8 @@ void JumpScopeChecker::VerifyIndirectJumps() { for (SmallVectorImpl<IndirectGotoStmt*>::iterator I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { IndirectGotoStmt *IG = *I; - assert(LabelAndGotoScopes.count(IG) && - "indirect jump didn't get added to scopes?"); + if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG))) + continue; unsigned IGScope = LabelAndGotoScopes[IG]; IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; if (!Entry) Entry = IG; @@ -589,8 +584,8 @@ void JumpScopeChecker::VerifyIndirectJumps() { I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); I != E; ++I) { LabelDecl *TheLabel = *I; - assert(LabelAndGotoScopes.count(TheLabel->getStmt()) && - "Referenced label didn't get added to scopes?"); + if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt()))) + continue; unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; LabelDecl *&Target = TargetScopes[LabelScope]; if (!Target) Target = TheLabel; @@ -695,7 +690,8 @@ static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump, /// Produce note diagnostics for a jump into a protected scope. void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) { - assert(!ToScopes.empty()); + if (CHECK_PERMISSIVE(ToScopes.empty())) + return; for (unsigned I = 0, E = ToScopes.size(); I != E; ++I) if (Scopes[ToScopes[I]].InDiag) S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag); @@ -706,7 +702,8 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, unsigned JumpScope, LabelDecl *Target, unsigned TargetScope) { - assert(JumpScope != TargetScope); + if (CHECK_PERMISSIVE(JumpScope == TargetScope)) + return; unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); bool Diagnosed = false; @@ -743,10 +740,12 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiagError, unsigned JumpDiagWarning, unsigned JumpDiagCXX98Compat) { - assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); - unsigned FromScope = LabelAndGotoScopes[From]; + if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(From))) + return; + if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(To))) + return; - assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); + unsigned FromScope = LabelAndGotoScopes[From]; unsigned ToScope = LabelAndGotoScopes[To]; // Common case: exactly the same scope, which is fine. @@ -762,7 +761,7 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, SmallVector<unsigned, 10> ToScopesError; SmallVector<unsigned, 10> ToScopesWarning; for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { - if (S.getLangOpts().MicrosoftMode && JumpDiagWarning != 0 && + if (S.getLangOpts().MSVCCompat && JumpDiagWarning != 0 && IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) ToScopesWarning.push_back(I); else if (IsCXX98CompatWarning(S, Scopes[I].InDiag)) |