[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