[cfe-commits] r99233 - in /cfe/trunk: include/clang/Analysis/AnalysisContext.h lib/Analysis/AnalysisContext.cpp lib/Sema/AnalysisBasedWarnings.cpp lib/Sema/AnalysisBasedWarnings.h lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp test/Sema/return.c
Ted Kremenek
kremenek at apple.com
Mon Mar 22 17:13:24 PDT 2010
Author: kremenek
Date: Mon Mar 22 19:13:23 2010
New Revision: 99233
URL: http://llvm.org/viewvc/llvm-project?rev=99233&view=rev
Log:
Only perform CFG-based warnings on 'static inline' functions that
are called (transitively) by regular functions/blocks within a
translation untion.
Modified:
cfe/trunk/include/clang/Analysis/AnalysisContext.h
cfe/trunk/lib/Analysis/AnalysisContext.cpp
cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
cfe/trunk/lib/Sema/AnalysisBasedWarnings.h
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/Sema/return.c
Modified: cfe/trunk/include/clang/Analysis/AnalysisContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisContext.h?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/AnalysisContext.h (original)
+++ cfe/trunk/include/clang/Analysis/AnalysisContext.h Mon Mar 22 19:13:23 2010
@@ -33,7 +33,7 @@
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
-
+
/// AnalysisContext contains the context data for the function or method under
/// analysis.
class AnalysisContext {
@@ -41,6 +41,7 @@
// AnalysisContext owns the following data.
CFG *cfg;
+ bool builtCFG;
LiveVariables *liveness;
ParentMap *PM;
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
@@ -48,8 +49,8 @@
bool AddEHEdges;
public:
AnalysisContext(const Decl *d, bool addehedges = false)
- : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0),
- AddEHEdges(addehedges) {}
+ : D(d), cfg(0), builtCFG(false), liveness(0), PM(0),
+ ReferencedBlockVars(0), AddEHEdges(addehedges) {}
~AnalysisContext();
@@ -69,7 +70,7 @@
std::pair<referenced_decls_iterator, referenced_decls_iterator>
getReferencedBlockVars(const BlockDecl *BD);
-
+
/// Return the ImplicitParamDecl* associated with 'self' if this
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
@@ -82,7 +83,7 @@
~AnalysisContextManager();
AnalysisContext *getContext(const Decl *D);
-
+
// Discard all previously created AnalysisContexts.
void clear();
};
@@ -103,7 +104,7 @@
public:
virtual ~LocationContext();
-
+
ContextKind getKind() const { return Kind; }
AnalysisContext *getAnalysisContext() const { return Ctx; }
@@ -120,14 +121,14 @@
return getAnalysisContext()->getLiveVariables();
}
- ParentMap &getParentMap() const {
+ ParentMap &getParentMap() const {
return getAnalysisContext()->getParentMap();
}
const ImplicitParamDecl *getSelfDecl() const {
return Ctx->getSelfDecl();
}
-
+
const StackFrameContext *getCurrentStackFrame() const;
const StackFrameContext *
getStackFrameForDeclContext(const DeclContext *DC) const;
@@ -157,7 +158,7 @@
friend class LocationContextManager;
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s, const CFGBlock *blk, unsigned idx)
- : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
+ : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
Index(idx) {}
public:
@@ -170,9 +171,9 @@
unsigned getIndex() const { return Index; }
void Profile(llvm::FoldingSetNodeID &ID);
-
+
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s,
+ const LocationContext *parent, const Stmt *s,
const CFGBlock *blk, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
ID.AddPointer(blk);
@@ -186,7 +187,7 @@
class ScopeContext : public LocationContext {
const Stmt *Enter;
-
+
friend class LocationContextManager;
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s)
@@ -229,7 +230,7 @@
const LocationContext *parent, const BlockDecl *bd) {
ProfileCommon(ID, Block, ctx, parent, bd);
}
-
+
static bool classof(const LocationContext* Ctx) {
return Ctx->getKind() == Block;
}
@@ -239,7 +240,7 @@
llvm::FoldingSet<LocationContext> Contexts;
public:
~LocationContextManager();
-
+
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s, const CFGBlock *blk,
@@ -248,7 +249,7 @@
const ScopeContext *getScope(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s);
-
+
/// Discard all previously created LocationContext objects.
void clear();
private:
Modified: cfe/trunk/lib/Analysis/AnalysisContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisContext.cpp?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisContext.cpp Mon Mar 22 19:13:23 2010
@@ -54,8 +54,12 @@
}
CFG *AnalysisContext::getCFG() {
- if (!cfg)
+ if (!builtCFG) {
cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
+ // Even when the cfg is not successfully built, we don't
+ // want to try building it again.
+ builtCFG = true;
+ }
return cfg;
}
@@ -126,9 +130,9 @@
llvm::FoldingSetNodeID ID;
LOC::Profile(ID, ctx, parent, d);
void *InsertPos;
-
+
LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
-
+
if (!L) {
L = new LOC(ctx, parent, d);
Contexts.InsertNode(L, InsertPos);
@@ -144,7 +148,7 @@
llvm::FoldingSetNodeID ID;
StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
void *InsertPos;
- StackFrameContext *L =
+ StackFrameContext *L =
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
if (!L) {
L = new StackFrameContext(ctx, parent, s, blk, idx);
@@ -253,7 +257,7 @@
IgnoredContexts.insert(BR->getBlockDecl());
Visit(BR->getBlockDecl()->getBody());
}
-};
+};
} // end anonymous namespace
typedef BumpVector<const VarDecl*> DeclVec;
@@ -263,16 +267,16 @@
llvm::BumpPtrAllocator &A) {
if (Vec)
return (DeclVec*) Vec;
-
+
BumpVectorContext BC(A);
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
new (BV) DeclVec(BC, 10);
-
+
// Find the referenced variables.
FindBlockDeclRefExprsVals F(*BV, BC);
F.Visit(BD->getBody());
-
- Vec = BV;
+
+ Vec = BV;
return BV;
}
@@ -281,7 +285,7 @@
AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
if (!ReferencedBlockVars)
ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
-
+
DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
return std::make_pair(V->begin(), V->end());
}
@@ -310,12 +314,12 @@
void LocationContextManager::clear() {
for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
- E = Contexts.end(); I != E; ) {
+ E = Contexts.end(); I != E; ) {
LocationContext *LC = &*I;
++I;
delete LC;
}
-
+
Contexts.clear();
}
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Mon Mar 22 19:13:23 2010
@@ -189,7 +189,7 @@
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
-
+
static CheckFallThroughDiagnostics MakeForFunction() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -205,7 +205,7 @@
D.funMode = true;
return D;
}
-
+
static CheckFallThroughDiagnostics MakeForBlock() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -221,7 +221,7 @@
D.funMode = false;
return D;
}
-
+
bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
bool HasNoReturn) const {
if (funMode) {
@@ -232,7 +232,7 @@
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
== Diagnostic::Ignored || !ReturnsVoid);
}
-
+
// For blocks.
return ReturnsVoid && !HasNoReturn
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
@@ -262,7 +262,7 @@
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
- if (const FunctionType *FT =
+ if (const FunctionType *FT =
BlockTy->getPointeeType()->getAs<FunctionType>()) {
if (FT->getResultType()->isVoidType())
ReturnsVoid = true;
@@ -276,7 +276,7 @@
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
-
+
// FIXME: Function try block
if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
switch (CheckFallThrough(AC)) {
@@ -312,25 +312,23 @@
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
- Diagnostic &D = S.getDiagnostics();
-
+clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
+ enableCheckUnreachable = 0;
+}
- enableCheckUnreachable = (unsigned)
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+ Diagnostic &D = S.getDiagnostics();
+ DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
}
-void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
- QualType BlockTy) {
-
+void clang::sema::
+AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
+ const Decl *D, QualType BlockTy,
+ const bool analyzeStaticInline) {
+
assert(BlockTy.isNull() || isa<BlockDecl>(D));
-
- // Do not do any analysis for declarations in system headers if we are
- // going to just ignore them.
- if (S.getDiagnostics().getSuppressSystemWarnings() &&
- S.SourceMgr.isInSystemHeader(D->getLocation()))
- return;
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
@@ -339,13 +337,24 @@
// (2) The code already has problems; running the analysis just takes more
// time.
if (S.getDiagnostics().hasErrorOccurred())
- return;
-
+ return;
+
+ // Do not do any analysis for declarations in system headers if we are
+ // going to just ignore them.
+ if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ S.SourceMgr.isInSystemHeader(D->getLocation()))
+ return;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// For function templates, class templates and member function templates
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
+
+ // Only analyze 'static inline' functions when explicitly asked.
+ if (!analyzeStaticInline && FD->isInlineSpecified() &&
+ FD->getStorageClass() == FunctionDecl::Static)
+ return;
}
const Stmt *Body = D->getBody();
@@ -354,16 +363,53 @@
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
AnalysisContext AC(D, false);
+ bool performedCheck = false;
// Warning: check missing 'return'
- if (enableCheckFallThrough) {
+ if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
: CheckFallThroughDiagnostics::MakeForFunction());
CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+ performedCheck = true;
}
// Warning: check for unreachable code
- if (enableCheckUnreachable)
+ if (P.enableCheckUnreachable) {
CheckUnreachable(S, AC);
+ performedCheck = true;
+ }
+
+ // If this block or function calls a 'static inline' function,
+ // we should analyze those functions as well.
+ if (performedCheck) {
+ // The CFG should already be constructed, so this should not
+ // incur any extra cost. We might not have a CFG, however, for
+ // invalid code.
+ if (const CFG *cfg = AC.getCFG()) {
+ // All CallExprs are block-level expressions in the CFG. This means
+ // that walking the basic blocks in the CFG is more efficient
+ // than walking the entire AST to find all calls.
+ for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) {
+ const CFGBlock *B = *I;
+ for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI)
+ if (const CallExpr *CE = dyn_cast<CallExpr>(*BI))
+ if (const DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts()))
+ if (const FunctionDecl *calleeD =
+ dyn_cast<FunctionDecl>(DR->getDecl()))
+ if (calleeD->isInlineSpecified() &&
+ calleeD->getStorageClass() == FunctionDecl::Static) {
+ // Have we analyzed this static inline function before?
+ unsigned &visited = VisitedFD[calleeD];
+ if (!visited) {
+ // Mark the callee visited prior to analyzing it
+ // so we terminate in case of recursion.
+ visited = 1;
+ IssueWarnings(DefaultPolicy, calleeD, QualType(), true);
+ }
+ }
+ }
+ }
+ }
}
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.h?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.h (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.h Mon Mar 22 19:13:23 2010
@@ -14,22 +14,43 @@
#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
-namespace clang { namespace sema {
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class Sema;
+
+namespace sema {
class AnalysisBasedWarnings {
- Sema &S;
- // The warnings to run.
- unsigned enableCheckFallThrough : 1;
- unsigned enableCheckUnreachable : 1;
-
public:
+ class Policy {
+ friend class AnalysisBasedWarnings;
+ // The warnings to run.
+ unsigned enableCheckFallThrough : 1;
+ unsigned enableCheckUnreachable : 1;
+ public:
+ Policy();
+ void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+ };
+
+private:
+ Sema &S;
+ Policy DefaultPolicy;
+ llvm::DenseMap<const FunctionDecl*, unsigned> VisitedFD;
+
+public:
AnalysisBasedWarnings(Sema &s);
- void IssueWarnings(const Decl *D, QualType BlockTy = QualType());
-
- void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+
+ Policy getDefaultPolicy() { return DefaultPolicy; }
+
+ void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(),
+ const bool analyzeStaticInline = false);
+
};
-
+
}} // end namespace clang::sema
#endif
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Mon Mar 22 19:13:23 2010
@@ -132,7 +132,8 @@
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0), TyposCorrected(0)
+ CurrentInstantiationScope(0), TyposCorrected(0),
+ AnalysisWarnings(*this)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 22 19:13:23 2010
@@ -19,6 +19,7 @@
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
#include "SemaTemplate.h"
+#include "AnalysisBasedWarnings.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
@@ -298,7 +299,7 @@
/// \brief The set of static functions seen so far that have not been used.
std::vector<FunctionDecl*> UnusedStaticFuncs;
-
+
class AccessedEntity {
public:
/// A member declaration found through lookup. The target is the
@@ -3542,6 +3543,9 @@
/// \brief The number of typos corrected by CorrectTypo.
unsigned TyposCorrected;
+ /// \brief Worker object for performing CFG-based warnings.
+ sema::AnalysisBasedWarnings AnalysisWarnings;
+
/// \brief An entity for which implicit template instantiation is required.
///
/// The source location associated with the declaration is the first place in
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar 22 19:13:23 2010
@@ -14,7 +14,6 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "AnalysisBasedWarnings.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -4276,7 +4275,7 @@
else
FD = dyn_cast_or_null<FunctionDecl>(dcl);
- sema::AnalysisBasedWarnings W(*this);
+ sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
if (FD) {
FD->setBody(Body);
@@ -4284,7 +4283,7 @@
// C and C++ allow for main to automagically return 0.
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
- W.disableCheckFallThrough();
+ WP.disableCheckFallThrough();
}
if (!FD->isInvalidDecl())
@@ -4381,7 +4380,7 @@
ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
ResultType = MD->getResultType();
}
- W.IssueWarnings(dcl);
+ AnalysisWarnings.IssueWarnings(WP, dcl);
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Mar 22 19:13:23 2010
@@ -7012,8 +7012,9 @@
}
// Issue any analysis-based warnings.
- sema::AnalysisBasedWarnings W(*this);
- W.IssueWarnings(BSI->TheDecl, BlockTy);
+ const sema::AnalysisBasedWarnings::Policy &WP =
+ AnalysisWarnings.getDefaultPolicy();
+ AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy);
Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs);
Modified: cfe/trunk/test/Sema/return.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/return.c?rev=99233&r1=99232&r2=99233&view=diff
==============================================================================
--- cfe/trunk/test/Sema/return.c (original)
+++ cfe/trunk/test/Sema/return.c Mon Mar 22 19:13:23 2010
@@ -222,3 +222,17 @@
void test33() {
if (j) while (1) { }
}
+
+// Test that 'static inline' functions are only analyzed for CFG-based warnings
+// when they are used.
+static inline int si_has_missing_return() {} // no-warning
+static inline int si_has_missing_return_2() {}; // expected-warning{{control reaches end of non-void function}}
+static inline int si_has_missing_return_3(int x) {
+ if (x)
+ return si_has_missing_return_3(x+1);
+} // expected-warning{{control may reach end of non-void function}}
+
+int test_static_inline(int x) {
+ return x ? si_has_missing_return_2() : si_has_missing_return_3(x);
+}
+
More information about the cfe-commits
mailing list