diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-02-23 01:52:04 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-02-23 01:52:04 +0000 |
commit | 351ba91eaa6d30e523587b2d7ed676a5172c6e56 (patch) | |
tree | bab3939265bf7b3e8e922f978c9ac49701f7853e | |
parent | 42461eecee98fff3671b3c14ce10f1a9e18cc95c (diff) |
Enhance Sema::DiagRuntimeBehavior() to delay some diagnostics to see if the related code is reachable. This suppresses some
diagnostics that occur in unreachable code (e.g., -Warray-bound).
We only pay the cost of doing the reachability analysis when we issue one of these diagnostics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126290 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/PartialDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Sema/ScopeInfo.h | 17 | ||||
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 2 | ||||
-rw-r--r-- | test/Sema/i-c-e.c | 4 | ||||
-rw-r--r-- | test/SemaCXX/array-bounds.cpp | 21 |
8 files changed, 115 insertions, 22 deletions
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index d00195b326..c636194405 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -75,7 +75,7 @@ public: /// \brief An allocator for Storage objects, which uses a small cache to /// objects, used to reduce malloc()/free() traffic for partial diagnostics. class StorageAllocator { - static const unsigned NumCached = 4; + static const unsigned NumCached = 16; Storage Cached[NumCached]; Storage *FreeList[NumCached]; unsigned NumFreeListEntries; diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index b0bb95509a..51297ae402 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SEMA_SCOPE_INFO_H #include "clang/AST/Type.h" +#include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SetVector.h" @@ -30,6 +31,17 @@ class SwitchStmt; namespace sema { +class PossiblyUnreachableDiag { +public: + PartialDiagnostic PD; + SourceLocation Loc; + const Stmt *stmt; + + PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc, + const Stmt *stmt) + : PD(PD), Loc(Loc), stmt(stmt) {} +}; + /// \brief Retains information about a function, method, or block that is /// currently being parsed. class FunctionScopeInfo { @@ -60,6 +72,11 @@ public: /// block, if there is any chance of applying the named return value /// optimization. llvm::SmallVector<ReturnStmt*, 4> Returns; + + /// \brief A list of PartialDiagnostics created but delayed within the + /// current function scope. These diagnostics are vetted for reachability + /// prior to being emitted. + llvm::SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags; void setHasBranchIntoScope() { HasBranchIntoScope = true; diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index adfa690a64..6a422242a9 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/DeclObjC.h" @@ -26,6 +27,8 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" +#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/UninitializedValuesV2.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Casting.h" @@ -478,6 +481,16 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { Diagnostic::Ignored); } +static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) { + for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + i = fscope->PossiblyUnreachableDiags.begin(), + e = fscope->PossiblyUnreachableDiags.end(); + i != e; ++i) { + const sema::PossiblyUnreachableDiag &D = *i; + S.Diag(D.Loc, D.PD); + } +} + void clang::sema:: AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, @@ -491,9 +504,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // time. Diagnostic &Diags = S.getDiagnostics(); - if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) - return; - // Do not do any analysis for declarations in system headers if we are // going to just ignore them. if (Diags.getSuppressSystemWarnings() && @@ -504,6 +514,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (cast<DeclContext>(D)->isDependentContext()) return; + if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) { + // Flush out any possibly unreachable diagnostics. + flushDiagnostics(S, fscope); + return; + } + const Stmt *Body = D->getBody(); assert(Body); @@ -512,6 +528,34 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false, /*addImplicitDtors=*/true, /*addInitializers=*/true); + // Emit delayed diagnostics. + if (!fscope->PossiblyUnreachableDiags.empty()) { + bool analyzed = false; + if (CFGReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis()) + if (CFGStmtMap *csm = AC.getCFGStmtMap()) { + analyzed = true; + for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + i = fscope->PossiblyUnreachableDiags.begin(), + e = fscope->PossiblyUnreachableDiags.end(); + i != e; ++i) { + const sema::PossiblyUnreachableDiag &D = *i; + if (const CFGBlock *blk = csm->getBlock(D.stmt)) { + // Can this block be reached from the entrance? + if (cra->isReachable(&AC.getCFG()->getEntry(), blk)) + S.Diag(D.Loc, D.PD); + } + else { + // Emit the warning anyway if we cannot map to a basic block. + S.Diag(D.Loc, D.PD); + } + } + } + + if (!analyzed) + flushDiagnostics(S, fscope); + } + + // Warning: check missing 'return' if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 0827597abd..0c39e13253 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -48,6 +48,7 @@ void FunctionScopeInfo::Clear() { SwitchStack.clear(); Returns.clear(); ErrorTrap.reset(); + PossiblyUnreachableDiags.clear(); } BlockScopeInfo::~BlockScopeInfo() { } @@ -639,9 +640,19 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP, // Issue any analysis-based warnings. if (WP && D) AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr); + else { + for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + i = Scope->PossiblyUnreachableDiags.begin(), + e = Scope->PossiblyUnreachableDiags.end(); + i != e; ++i) { + const sema::PossiblyUnreachableDiag &D = *i; + Diag(D.Loc, D.PD); + } + } - if (FunctionScopes.back() != Scope) + if (FunctionScopes.back() != Scope) { delete Scope; + } } /// \brief Determine whether any errors occurred within this function/method/ diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ac747910dc..9e2b21aca2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -387,13 +387,13 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, return false; if (Expr->getType()->isObjCObjectType() && - DiagRuntimeBehavior(Expr->getLocStart(), Expr, + DiagRuntimeBehavior(Expr->getLocStart(), 0, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << Expr->getType() << CT)) return true; if (!Expr->getType()->isPODType() && - DiagRuntimeBehavior(Expr->getLocStart(), Expr, + DiagRuntimeBehavior(Expr->getLocStart(), 0, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) << Expr->getType() << CT)) return true; @@ -6721,7 +6721,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) { if (DRL->getDecl() == DRR->getDecl() && !IsWithinTemplateSpecialization(DRL->getDecl())) { - DiagRuntimeBehavior(Loc, lex, PDiag(diag::warn_comparison_always) + DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) << 0 // self- << (Opc == BO_EQ || Opc == BO_LE @@ -6743,7 +6743,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, always_evals_to = 2; // e.g. array1 <= array2 break; } - DiagRuntimeBehavior(Loc, lex, PDiag(diag::warn_comparison_always) + DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) << 1 // array << always_evals_to); } @@ -6784,7 +6784,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, default: assert(false && "Invalid comparison operator"); } - DiagRuntimeBehavior(Loc, literalString, + DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) << literalString->getSourceRange()); @@ -7094,7 +7094,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens())) if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) - DiagRuntimeBehavior(Loc, rex, + DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) << 0 // self- << 2 // "a constant" @@ -7355,9 +7355,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, UO->getSubExpr()->IgnoreParenCasts()-> isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) && !UO->getType().isVolatileQualified()) { - Diag(UO->getOperatorLoc(), diag::warn_indirection_through_null) - << UO->getSubExpr()->getSourceRange(); - Diag(UO->getOperatorLoc(), diag::note_indirection_through_null); + DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + PDiag(diag::warn_indirection_through_null) + << UO->getSubExpr()->getSourceRange()); + DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + PDiag(diag::note_indirection_through_null)); } // Check for trivial buffer overflows. @@ -9475,7 +9477,13 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: - Diag(Loc, PD); + if (stmt && getCurFunctionOrMethodDecl()) { + FunctionScopes.back()->PossiblyUnreachableDiags. + push_back(sema::PossiblyUnreachableDiag(PD, Loc, stmt)); + } + else + Diag(Loc, PD); + return true; case PotentiallyPotentiallyEvaluated: diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 94ba93d5c2..0abd79a696 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -146,7 +146,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } - DiagRuntimeBehavior(Loc, S, PDiag(DiagID) << R1 << R2); + DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2); } StmtResult diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c index 4c2962d4b2..d0a6c529c1 100644 --- a/test/Sema/i-c-e.c +++ b/test/Sema/i-c-e.c @@ -60,7 +60,9 @@ int comma3[(1,2)]; // expected-warning {{size of static array must be an integer // Pointer + __builtin_constant_p char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}} -int illegaldiv1[1 || 1/0]; // expected-warning {{division by zero is undefined}} +int illegaldiv1a[1 || 1/0]; // expected-warning {{division by zero is undefined}} +int illegaldiv1b[1 && 1/0]; // expected-warning {{division by zero is undefined}} expected-error{{variable length array declaration not allowed at file scope}} + int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}} \ // expected-warning {{division by zero is undefined}} int illegaldiv3[INT_MIN / -1]; // expected-error {{variable length array declaration not allowed at file scope}} diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp index 0286c01d85..ee7882daea 100644 --- a/test/SemaCXX/array-bounds.cpp +++ b/test/SemaCXX/array-bounds.cpp @@ -63,11 +63,11 @@ void test() { } template <int I> struct S { - char arr[I]; // expected-note 3 {{declared here}} + char arr[I]; // expected-note 2 {{declared here}} }; template <int I> void f() { S<3> s; - s.arr[4] = 0; // expected-warning 2 {{array index of '4' indexes past the end of an array (that contains 3 elements)}} + s.arr[4] = 0; // expected-warning {{array index of '4' indexes past the end of an array (that contains 3 elements)}} s.arr[I] = 0; // expected-warning {{array index of '5' indexes past the end of an array (that contains 3 elements)}} } @@ -79,9 +79,8 @@ void test_templates() { #define ARR_IN_MACRO(flag, arr, idx) flag ? arr[idx] : 1 int test_no_warn_macro_unreachable() { - int arr[SIZE]; // expected-note 2 {{array 'arr' declared here}} - // FIXME: We don't want to warn for the first case. - return ARR_IN_MACRO(0, arr, SIZE) + // expected-warning{{array index of '10' indexes past the end of an array (that contains 10 elements)}} + int arr[SIZE]; // expected-note {{array 'arr' declared here}} + return ARR_IN_MACRO(0, arr, SIZE) + // no-warning ARR_IN_MACRO(1, arr, SIZE); // expected-warning{{array index of '10' indexes past the end of an array (that contains 10 elements)}} } @@ -91,3 +90,15 @@ int test_pr9240() { return array[(unsigned long long) 100]; // expected-warning {{array index of '100' indexes past the end of an array (that contains 100 elements)}} } +template <bool extendArray> +void myFunc() { + int arr[3 + (extendArray ? 1 : 0)]; + + if (extendArray) + arr[3] = 42; +} + +void f() { + myFunc<false>(); +} + |