[cfe-commits] r91501 - in /cfe/trunk: include/clang/Analysis/CFG.h include/clang/Analysis/PathSensitive/GRCoreEngine.h include/clang/Analysis/PathSensitive/GRExprEngine.h include/clang/Analysis/PathSensitive/GRSubEngine.h include/clang/Analysis/PathSensitive/SVals.h include/clang/Analysis/ProgramPoint.h lib/Analysis/CFG.cpp lib/Analysis/CheckDeadStores.cpp lib/Analysis/GRCoreEngine.cpp lib/Analysis/GRExprEngine.cpp lib/Analysis/RegionStore.cpp lib/Analysis/Store.cpp test/Analysis/dead-stores.cpp

Ted Kremenek kremenek at apple.com
Tue Dec 15 19:18:58 PST 2009


Author: kremenek
Date: Tue Dec 15 21:18:58 2009
New Revision: 91501

URL: http://llvm.org/viewvc/llvm-project?rev=91501&view=rev
Log:
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.

The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements.  Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue.  DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.

The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.

In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents.  EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).

Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).

Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references.  This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRSubEngine.h
    cfe/trunk/include/clang/Analysis/PathSensitive/SVals.h
    cfe/trunk/include/clang/Analysis/ProgramPoint.h
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/Analysis/CheckDeadStores.cpp
    cfe/trunk/lib/Analysis/GRCoreEngine.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp
    cfe/trunk/lib/Analysis/RegionStore.cpp
    cfe/trunk/lib/Analysis/Store.cpp
    cfe/trunk/test/Analysis/dead-stores.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue Dec 15 21:18:58 2009
@@ -15,8 +15,10 @@
 #ifndef LLVM_CLANG_CFG_H
 #define LLVM_CLANG_CFG_H
 
+#include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
 #include "clang/Analysis/Support/BumpVector.h"
 #include <cassert>
 
@@ -31,6 +33,17 @@
   class LangOptions;
   class ASTContext;
 
+/// CFGElement - Represents a top-level expression in a basic block.
+class CFGElement {
+  llvm::PointerIntPair<Stmt *, 1> Data;
+public:
+  explicit CFGElement() {}
+  CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {}
+  Stmt *getStmt() const { return Data.getPointer(); }
+  bool asLValue() const { return Data.getInt() == 1; }
+  operator Stmt*() const { return getStmt(); }
+};
+
 /// CFGBlock - Represents a single basic block in a source-level CFG.
 ///  It consists of:
 ///
@@ -57,7 +70,7 @@
 ///
 class CFGBlock {
   class StatementList {
-    typedef BumpVector<Stmt*> ImplTy;
+    typedef BumpVector<CFGElement> ImplTy;
     ImplTy Impl;
   public:
     StatementList(BumpVectorContext &C) : Impl(C, 4) {}
@@ -67,9 +80,9 @@
     typedef ImplTy::iterator                              reverse_iterator;
     typedef ImplTy::const_iterator                        const_reverse_iterator;
   
-    void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); }
-    Stmt *front() const { return Impl.back(); }
-    Stmt *back() const { return Impl.front(); }
+    void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
+    CFGElement front() const { return Impl.back(); }
+    CFGElement back() const { return Impl.front(); }
     
     iterator begin() { return Impl.rbegin(); }
     iterator end() { return Impl.rend(); }
@@ -80,7 +93,7 @@
     const_reverse_iterator rbegin() const { return Impl.begin(); }
     const_reverse_iterator rend() const { return Impl.end(); }
 
-   Stmt*  operator[](size_t i) const  {
+   CFGElement operator[](size_t i) const  {
      assert(i < Impl.size());
      return Impl[Impl.size() - 1 - i];
    }
@@ -129,8 +142,8 @@
   typedef StatementList::reverse_iterator              reverse_iterator;
   typedef StatementList::const_reverse_iterator        const_reverse_iterator;
 
-  Stmt*                        front()       const { return Stmts.front();   }
-  Stmt*                        back()        const { return Stmts.back();    }
+  CFGElement                   front()       const { return Stmts.front();   }
+  CFGElement                   back()        const { return Stmts.back();    }
 
   iterator                     begin()             { return Stmts.begin();   }
   iterator                     end()               { return Stmts.end();     }
@@ -145,8 +158,7 @@
   unsigned                     size()        const { return Stmts.size();    }
   bool                         empty()       const { return Stmts.empty();   }
 
-  Stmt*  operator[](size_t i) const  { return Stmts[i]; }
-
+  CFGElement operator[](size_t i) const  { return Stmts[i]; }
 
   // CFG iterators
   typedef AdjacentBlocks::iterator                              pred_iterator;
@@ -221,8 +233,8 @@
     Succs.push_back(Block, C);
   }
   
-  void appendStmt(Stmt* Statement, BumpVectorContext &C) {
-      Stmts.push_back(Statement, C);
+  void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) {
+      Stmts.push_back(CFGElement(Statement, asLValue), C);
   }  
 };
 
@@ -370,13 +382,25 @@
 
 namespace llvm {
 
+/// Implement simplify_type for CFGElement, so that we can dyn_cast from
+/// CFGElement to a specific Stmt class.
+template <> struct simplify_type<const ::clang::CFGElement> {
+  typedef ::clang::Stmt* SimpleType;
+  static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) {
+    return Val.getStmt();
+  }
+};
+  
+template <> struct simplify_type< ::clang::CFGElement> 
+  : public simplify_type<const ::clang::CFGElement> {};
+  
 // Traits for: CFGBlock
 
-template <> struct GraphTraits<clang::CFGBlock* > {
-  typedef clang::CFGBlock NodeType;
-  typedef clang::CFGBlock::succ_iterator ChildIteratorType;
+template <> struct GraphTraits< ::clang::CFGBlock* > {
+  typedef ::clang::CFGBlock NodeType;
+  typedef ::clang::CFGBlock::succ_iterator ChildIteratorType;
 
-  static NodeType* getEntryNode(clang::CFGBlock* BB)
+  static NodeType* getEntryNode(::clang::CFGBlock* BB)
   { return BB; }
 
   static inline ChildIteratorType child_begin(NodeType* N)
@@ -386,9 +410,9 @@
   { return N->succ_end(); }
 };
 
-template <> struct GraphTraits<const clang::CFGBlock* > {
-  typedef const clang::CFGBlock NodeType;
-  typedef clang::CFGBlock::const_succ_iterator ChildIteratorType;
+template <> struct GraphTraits< const ::clang::CFGBlock* > {
+  typedef const ::clang::CFGBlock NodeType;
+  typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType;
 
   static NodeType* getEntryNode(const clang::CFGBlock* BB)
   { return BB; }
@@ -400,11 +424,11 @@
   { return N->succ_end(); }
 };
 
-template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
-  typedef const clang::CFGBlock NodeType;
-  typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
+template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
+  typedef const ::clang::CFGBlock NodeType;
+  typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
 
-  static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G)
+  static NodeType *getEntryNode(Inverse<const ::clang::CFGBlock*> G)
   { return G.Graph; }
 
   static inline ChildIteratorType child_begin(NodeType* N)
@@ -416,36 +440,40 @@
 
 // Traits for: CFG
 
-template <> struct GraphTraits<clang::CFG* >
-            : public GraphTraits<clang::CFGBlock* >  {
+template <> struct GraphTraits< ::clang::CFG* >
+    : public GraphTraits< ::clang::CFGBlock* >  {
 
-  typedef clang::CFG::iterator nodes_iterator;
+  typedef ::clang::CFG::iterator nodes_iterator;
 
-  static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); }
-  static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); }
-  static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); }
+  static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); }
+  static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); }
+  static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); }
 };
 
-template <> struct GraphTraits< const clang::CFG* >
-            : public GraphTraits< const clang::CFGBlock* >  {
+template <> struct GraphTraits<const ::clang::CFG* >
+    : public GraphTraits<const ::clang::CFGBlock* >  {
 
-  typedef clang::CFG::const_iterator nodes_iterator;
+  typedef ::clang::CFG::const_iterator nodes_iterator;
 
-  static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); }
-  static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); }
-  static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
+  static NodeType *getEntryNode( const ::clang::CFG* F) {
+    return &F->getEntry();
+  }
+  static nodes_iterator nodes_begin( const ::clang::CFG* F) {
+    return F->begin();
+  }
+  static nodes_iterator nodes_end( const ::clang::CFG* F) {
+    return F->end();
+  }
 };
 
-template <> struct GraphTraits<Inverse<const clang::CFG*> >
-            : public GraphTraits<Inverse<const clang::CFGBlock*> > {
+template <> struct GraphTraits<Inverse<const ::clang::CFG*> >
+  : public GraphTraits<Inverse<const ::clang::CFGBlock*> > {
 
-  typedef clang::CFG::const_iterator nodes_iterator;
+  typedef ::clang::CFG::const_iterator nodes_iterator;
 
-  static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); }
-  static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();}
-  static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); }
+  static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); }
+  static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();}
+  static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); }
 };
-
 } // end llvm namespace
-
 #endif

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Tue Dec 15 21:18:58 2009
@@ -75,8 +75,7 @@
 
   void ProcessEndPath(GREndPathNodeBuilder& Builder);
 
-  void ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder);
-
+  void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder);
 
   bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
                             GRBlockCounter BC);

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Tue Dec 15 21:18:58 2009
@@ -149,7 +149,7 @@
 
   /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a block-level statement.
-  void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder);
+  void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder);
 
   /// ProcessBlockEntrance - Called by GRCoreEngine when start processing
   ///  a CFGBlock.  This method returns true if the analysis should continue
@@ -399,15 +399,19 @@
 
   // FIXME: 'tag' should be removed, and a LocationContext should be used
   // instead.
-  void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred,
-                       const GRState* St, SVal location,
-                       const void *tag, bool isLoad);
-
-  // FIXME: 'tag' should be removed, and a LocationContext should be used
-  // instead.
   void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE,
                  ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
                  const void *tag = 0);
+private:  
+  void EvalLoadCommon(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+                      const GRState* St, SVal location, const void *tag,
+                      QualType LoadTy);
+
+  // FIXME: 'tag' should be removed, and a LocationContext should be used
+  // instead.
+  void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred,
+                    const GRState* St, SVal location,
+                    const void *tag, bool isLoad);
 };
 
 } // end clang namespace

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRSubEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRSubEngine.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRSubEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRSubEngine.h Tue Dec 15 21:18:58 2009
@@ -37,7 +37,7 @@
 
   /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a block-level statement.
-  virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) = 0;
+  virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0;
 
   /// ProcessBlockEntrance - Called by GRCoreEngine when start processing
   ///  a CFGBlock.  This method returns true if the analysis should continue

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/SVals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/SVals.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/SVals.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/SVals.h Tue Dec 15 21:18:58 2009
@@ -244,7 +244,8 @@
   }
 
   static inline bool IsLocType(QualType T) {
-    return T->isAnyPointerType() || T->isBlockPointerType();
+    return T->isAnyPointerType() || T->isBlockPointerType() || 
+           T->isReferenceType();
   }
 };
 

Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original)
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Tue Dec 15 21:18:58 2009
@@ -108,9 +108,13 @@
     return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1()));
   }
 
-  Stmt* getFirstStmt() const {
+  CFGElement getFirstElement() const {
     const CFGBlock* B = getBlock();
-    return B->empty() ? NULL : B->front();
+    return B->empty() ? CFGElement() : B->front();
+  }
+  
+  Stmt *getFirstStmt() const {
+    return getFirstElement().getStmt();
   }
 
   static bool classof(const ProgramPoint* Location) {
@@ -129,7 +133,7 @@
 
   Stmt* getLastStmt() const {
     const CFGBlock* B = getBlock();
-    return B->empty() ? NULL : B->back();
+    return B->empty() ? CFGElement() : B->back();
   }
 
   Stmt* getTerminator() const {

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Dec 15 21:18:58 2009
@@ -34,6 +34,17 @@
 
   return D->getLocation();
 }
+  
+class AddStmtChoice {
+public:
+  enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue };
+public:
+  AddStmtChoice(Kind kind) : k(kind) {}  
+  bool alwaysAdd() const { return k != NotAlwaysAdd; }
+  bool asLValue() const { return k == AlwaysAddAsLValue; }
+private:
+  Kind k;
+};
 
 /// CFGBuilder - This class implements CFG construction from an AST.
 ///   The builder is stateful: an instance of the builder should be used to only
@@ -84,15 +95,16 @@
 
 private:
   // Visitors to walk an AST and construct the CFG.
-  CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd);
-  CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd);
-  CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd);
+  CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
+  CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
+  CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc);
   CFGBlock *VisitBreakStmt(BreakStmt *B);
-  CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd);
+  CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
   CFGBlock *VisitCaseStmt(CaseStmt *C);
-  CFGBlock *VisitChooseExpr(ChooseExpr *C);
+  CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
   CFGBlock *VisitCompoundStmt(CompoundStmt *C);
-  CFGBlock *VisitConditionalOperator(ConditionalOperator *C);
+  CFGBlock *VisitConditionalOperator(ConditionalOperator *C,
+                                     AddStmtChoice asc);
   CFGBlock *VisitContinueStmt(ContinueStmt *C);
   CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); }
   CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
@@ -112,13 +124,13 @@
   CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
   CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
   CFGBlock *VisitReturnStmt(ReturnStmt* R);
-  CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd);
-  CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd);
+  CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc);
+  CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
   CFGBlock *VisitSwitchStmt(SwitchStmt *S);
   CFGBlock *VisitWhileStmt(WhileStmt *W);
 
-  CFGBlock *Visit(Stmt *S, bool alwaysAdd = false);
-  CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd);
+  CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
+  CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
   CFGBlock *VisitChildren(Stmt* S);
 
   // NYS == Not Yet Supported
@@ -130,10 +142,13 @@
   void autoCreateBlock() { if (!Block) Block = createBlock(); }
   CFGBlock *createBlock(bool add_successor = true);
   bool FinishBlock(CFGBlock* B);
-  CFGBlock *addStmt(Stmt *S) { return Visit(S, true); }
+  CFGBlock *addStmt(Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
+    return Visit(S, asc);
+  }
   
-  void AppendStmt(CFGBlock *B, Stmt *S) {
-    B->appendStmt(S, cfg->getBumpVectorContext());
+  void AppendStmt(CFGBlock *B, Stmt *S,
+                  AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
+    B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue());
   }
   
   void AddSuccessor(CFGBlock *B, CFGBlock *S) {
@@ -278,38 +293,38 @@
 /// Visit - Walk the subtree of a statement and add extra
 ///   blocks for ternary operators, &&, and ||.  We also process "," and
 ///   DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) {
+CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
 tryAgain:
   switch (S->getStmtClass()) {
     default:
-      return VisitStmt(S, alwaysAdd);
+      return VisitStmt(S, asc);
 
     case Stmt::AddrLabelExprClass:
-      return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), alwaysAdd);
+      return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
 
     case Stmt::BinaryOperatorClass:
-      return VisitBinaryOperator(cast<BinaryOperator>(S), alwaysAdd);
+      return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
 
     case Stmt::BlockExprClass:
-      return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd);
+      return VisitBlockExpr(cast<BlockExpr>(S), asc);
 
     case Stmt::BreakStmtClass:
       return VisitBreakStmt(cast<BreakStmt>(S));
 
     case Stmt::CallExprClass:
-      return VisitCallExpr(cast<CallExpr>(S), alwaysAdd);
+      return VisitCallExpr(cast<CallExpr>(S), asc);
 
     case Stmt::CaseStmtClass:
       return VisitCaseStmt(cast<CaseStmt>(S));
 
     case Stmt::ChooseExprClass:
-      return VisitChooseExpr(cast<ChooseExpr>(S));
+      return VisitChooseExpr(cast<ChooseExpr>(S), asc);
 
     case Stmt::CompoundStmtClass:
       return VisitCompoundStmt(cast<CompoundStmt>(S));
 
     case Stmt::ConditionalOperatorClass:
-      return VisitConditionalOperator(cast<ConditionalOperator>(S));
+      return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
 
     case Stmt::ContinueStmtClass:
       return VisitContinueStmt(cast<ContinueStmt>(S));
@@ -367,10 +382,10 @@
       return VisitReturnStmt(cast<ReturnStmt>(S));
 
     case Stmt::SizeOfAlignOfExprClass:
-      return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), alwaysAdd);
+      return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc);
 
     case Stmt::StmtExprClass:
-      return VisitStmtExpr(cast<StmtExpr>(S), alwaysAdd);
+      return VisitStmtExpr(cast<StmtExpr>(S), asc);
 
     case Stmt::SwitchStmtClass:
       return VisitSwitchStmt(cast<SwitchStmt>(S));
@@ -380,10 +395,10 @@
   }
 }
 
-CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) {
-  if (alwaysAdd) {
+CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
+  if (asc.alwaysAdd()) {
     autoCreateBlock();
-    AppendStmt(Block, S);
+    AppendStmt(Block, S, asc);
   }
 
   return VisitChildren(S);
@@ -399,21 +414,23 @@
   return B;
 }
 
-CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) {
+CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
+                                         AddStmtChoice asc) {
   AddressTakenLabels.insert(A->getLabel());
 
-  if (alwaysAdd) {
+  if (asc.alwaysAdd()) {
     autoCreateBlock();
-    AppendStmt(Block, A);
+    AppendStmt(Block, A, asc);
   }
 
   return Block;
 }
 
-CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
+CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
+                                          AddStmtChoice asc) {
   if (B->isLogicalOp()) { // && or ||
     CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
-    AppendStmt(ConfluenceBlock, B);
+    AppendStmt(ConfluenceBlock, B, asc);
 
     if (!FinishBlock(ConfluenceBlock))
       return 0;
@@ -450,18 +467,18 @@
   }
   else if (B->getOpcode() == BinaryOperator::Comma) { // ,
     autoCreateBlock();
-    AppendStmt(Block, B);
+    AppendStmt(Block, B, asc);
     addStmt(B->getRHS());
     return addStmt(B->getLHS());
   }
 
-  return VisitStmt(B, alwaysAdd);
+  return VisitStmt(B, asc);
 }
 
-CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
-  if (alwaysAdd) {
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
+  if (asc.alwaysAdd()) {
     autoCreateBlock();
-    AppendStmt(Block, E);
+    AppendStmt(Block, E, asc);
   }
   return Block;
 }
@@ -487,7 +504,7 @@
   return Block;
 }
 
-CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
+CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
   // If this is a call to a no-return function, this stops the block here.
   bool NoReturn = false;
   if (C->getCallee()->getType().getNoReturnAttr()) {
@@ -499,14 +516,14 @@
       NoReturn = true;
 
   if (!NoReturn)
-    return VisitStmt(C, alwaysAdd);
+    return VisitStmt(C, asc);
 
   if (Block && !FinishBlock(Block))
     return 0;
 
   // Create new block with no successor for the remaining pieces.
   Block = createBlock(false);
-  AppendStmt(Block, C);
+  AppendStmt(Block, C, asc);
 
   // Wire this to the exit block directly.
   AddSuccessor(Block, &cfg->getExit());
@@ -514,9 +531,10 @@
   return VisitChildren(C);
 }
 
-CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) {
+CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
+                                      AddStmtChoice asc) {
   CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
-  AppendStmt(ConfluenceBlock, C);
+  AppendStmt(ConfluenceBlock, C, asc);
   if (!FinishBlock(ConfluenceBlock))
     return 0;
 
@@ -555,11 +573,12 @@
   return LastBlock;
 }
 
-CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) {
+CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
+                                               AddStmtChoice asc) {
   // Create the confluence block that will "merge" the results of the ternary
   // expression.
   CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
-  AppendStmt(ConfluenceBlock, C);
+  AppendStmt(ConfluenceBlock, C, asc);
   if (!FinishBlock(ConfluenceBlock))
     return 0;
 
@@ -670,7 +689,10 @@
       case Stmt::StringLiteralClass:
         break;
       default:
-        Block = addStmt(Init);
+        Block = addStmt(Init,
+                        VD->getType()->isReferenceType()
+                        ? AddStmtChoice::AlwaysAddAsLValue
+                        : AddStmtChoice::AlwaysAdd);
     }
   }
 
@@ -776,7 +798,7 @@
 
   // Add the return statement to the block.  This may create new blocks if R
   // contains control-flow (short-circuit operations).
-  return VisitStmt(R, true);
+  return VisitStmt(R, AddStmtChoice::AlwaysAdd);
 }
 
 CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
@@ -1000,7 +1022,7 @@
   // Walk the 'element' expression to see if there are any side-effects.  We
   // generate new blocks as necesary.  We DON'T add the statement by default to
   // the CFG unless it contains control-flow.
-  EntryConditionBlock = Visit(S->getElement(), false);
+  EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd);
   if (Block) {
     if (!FinishBlock(EntryConditionBlock))
       return 0;
@@ -1182,7 +1204,7 @@
 
   // Add the statement to the block.  This may create new blocks if S contains
   // control-flow (short-circuit operations).
-  return VisitStmt(S, true);
+  return VisitStmt(S, AddStmtChoice::AlwaysAdd);
 }
 
 CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
@@ -1198,7 +1220,7 @@
 
   // Add the statement to the block.  This may create new blocks if S contains
   // control-flow (short-circuit operations).
-  return VisitStmt(T, true);
+  return VisitStmt(T, AddStmtChoice::AlwaysAdd);
 }
 
 CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
@@ -1316,9 +1338,9 @@
 }
 
 CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
-                                             bool alwaysAdd) {
+                                             AddStmtChoice asc) {
 
-  if (alwaysAdd) {
+  if (asc.alwaysAdd()) {
     autoCreateBlock();
     AppendStmt(Block, E);
   }
@@ -1335,8 +1357,8 @@
 
 /// VisitStmtExpr - Utility method to handle (nested) statement
 ///  expressions (a GCC extension).
-CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) {
-  if (alwaysAdd) {
+CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
+  if (asc.alwaysAdd()) {
     autoCreateBlock();
     AppendStmt(Block, SE);
   }

Modified: cfe/trunk/lib/Analysis/CheckDeadStores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CheckDeadStores.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CheckDeadStores.cpp (original)
+++ cfe/trunk/lib/Analysis/CheckDeadStores.cpp Tue Dec 15 21:18:58 2009
@@ -84,7 +84,14 @@
                     const LiveVariables::AnalysisDataTy& AD,
                     const LiveVariables::ValTy& Live) {
 
-    if (VD->hasLocalStorage() && !Live(VD, AD) && 
+    if (!VD->hasLocalStorage())
+      return;
+    // Reference types confuse the dead stores checker.  Skip them
+    // for now.
+    if (VD->getType()->getAs<ReferenceType>())
+      return;
+
+    if (!Live(VD, AD) && 
         !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
       Report(VD, dsk, Ex->getSourceRange().getBegin(),
              Val->getSourceRange());
@@ -93,7 +100,6 @@
   void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
                     const LiveVariables::AnalysisDataTy& AD,
                     const LiveVariables::ValTy& Live) {
-
     if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
       CheckVarDecl(VD, DR, Val, dsk, AD, Live);
   }
@@ -183,8 +189,13 @@
 
         if (!V)
           continue;
-
-        if (V->hasLocalStorage())
+          
+        if (V->hasLocalStorage()) {          
+          // Reference types confuse the dead stores checker.  Skip them
+          // for now.
+          if (V->getType()->getAs<ReferenceType>())
+            return;
+            
           if (Expr* E = V->getInit()) {
             // Don't warn on C++ objects (yet) until we can show that their
             // constructors/destructors don't have side effects.
@@ -218,6 +229,7 @@
               Report(V, DeadInit, V->getLocation(), E->getSourceRange());
             }
           }
+        }
       }
   }
 };

Modified: cfe/trunk/lib/Analysis/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRCoreEngine.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRCoreEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRCoreEngine.cpp Tue Dec 15 21:18:58 2009
@@ -122,8 +122,8 @@
   SubEngine.ProcessEndPath(Builder);
 }
 
-void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) {
-  SubEngine.ProcessStmt(S, Builder);
+void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) {
+  SubEngine.ProcessStmt(E, Builder);
 }
 
 bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
@@ -241,10 +241,10 @@
   WList->setBlockCounter(Counter);
 
   // Process the entrance of the block.
-  if (Stmt* S = L.getFirstStmt()) {
+  if (CFGElement E = L.getFirstElement()) {
     GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
                               SubEngine.getStateManager());
-    ProcessStmt(S, Builder);
+    ProcessStmt(E, Builder);
   }
   else
     HandleBlockExit(L.getBlock(), Pred);

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Tue Dec 15 21:18:58 2009
@@ -33,6 +33,7 @@
 
 using namespace clang;
 using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
 using llvm::cast;
 using llvm::APSInt;
 
@@ -378,17 +379,15 @@
 // Top-level transfer function logic (Dispatcher).
 //===----------------------------------------------------------------------===//
 
-void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
-
+void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
+  CurrentStmt = CE.getStmt();
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
-                                S->getLocStart(),
+                                CurrentStmt->getLocStart(),
                                 "Error evaluating statement");
 
   Builder = &builder;
   EntryNode = builder.getLastNode();
 
-  CurrentStmt = S;
-
   // Set up our simple checks.
   if (BatchAuditor)
     Builder->setAuditor(BatchAuditor.get());
@@ -415,7 +414,7 @@
 
     // FIXME: This should soon be removed.
     ExplodedNodeSet Tmp2;
-    getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S,
+    getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CurrentStmt,
                             CleanedState, SymReaper);
 
     if (Checkers.empty())
@@ -437,8 +436,8 @@
         Checker *checker = I->second;
         for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
              NI != NE; ++NI)
-          checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI, 
-                                      SymReaper, tag);
+          checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, CurrentStmt,
+                                      *NI, SymReaper, tag);
         SrcSet = DstSet;
       }
     }
@@ -457,7 +456,10 @@
     Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
 
     // Visit the statement.
-    Visit(S, *I, Dst);
+    if (CE.asLValue())
+      VisitLValue(cast<Expr>(CurrentStmt), *I, Dst);
+    else
+      Visit(CurrentStmt, *I, Dst);
 
     // Do we need to auto-generate a node?  We only need to do this to generate
     // a node with a "cleaned" state; GRCoreEngine will actually handle
@@ -465,7 +467,7 @@
     if (Dst.size() == 1 && *Dst.begin() == EntryNode
         && !Builder->HasGeneratedNode && !HasAutoGenerated) {
       HasAutoGenerated = true;
-      builder.generateNode(S, GetState(EntryNode), *I);
+      builder.generateNode(CurrentStmt, GetState(EntryNode), *I);
     }
   }
 
@@ -1232,13 +1234,23 @@
 
     SVal V = state->getLValue(VD, Pred->getLocationContext());
 
-    if (asLValue)
-      MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
-               ProgramPoint::PostLValueKind);
+    if (asLValue) {
+      // For references, the 'lvalue' is the pointer address stored in the
+      // reference region.
+      if (VD->getType()->isReferenceType()) {
+        if (const MemRegion *R = V.getAsRegion())
+          V = state->getSVal(R);
+        else
+          V = UnknownVal();
+      }
+      
+      MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V,
+                                              ProgramPoint::PostLValueKind));
+    }
     else
       EvalLoad(Dst, Ex, Pred, state, V);
-    return;
 
+    return;
   } else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
     assert(!asLValue && "EnumConstantDecl does not have lvalue.");
 
@@ -1415,6 +1427,37 @@
                             const GRState* state, SVal location,
                             const void *tag, QualType LoadTy) {
 
+  // Are we loading from a region?  This actually results in two loads; one
+  // to fetch the address of the referenced value and one to fetch the
+  // referenced value.
+  if (const TypedRegion *TR = 
+        dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+    
+    QualType ValTy = TR->getValueType(getContext());
+    if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
+      static int loadReferenceTag = 0;    
+      ExplodedNodeSet Tmp;
+      EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
+                     getContext().getPointerType(RT->getPointeeType()));
+
+      // Perform the load from the referenced value.
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
+        state = GetState(*I);
+        location = state->getSVal(Ex);
+        EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
+      }    
+      return;
+    }
+  }
+  
+  EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
+}
+
+void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
+                                  ExplodedNode* Pred,
+                                  const GRState* state, SVal location,
+                                  const void *tag, QualType LoadTy) {
+  
   // Evaluate the location (checks for bad dereferences).
   ExplodedNodeSet Tmp;
   EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
@@ -1992,8 +2035,12 @@
   //  time a function is called those values may not be current.
   ExplodedNodeSet Tmp;
 
-  if (InitEx)
-    Visit(InitEx, Pred, Tmp);
+  if (InitEx) {
+    if (VD->getType()->isReferenceType())
+      VisitLValue(InitEx, Pred, Tmp);
+    else
+      Visit(InitEx, Pred, Tmp);
+  }
   else
     Tmp.Add(Pred);
 

Modified: cfe/trunk/lib/Analysis/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/RegionStore.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/RegionStore.cpp (original)
+++ cfe/trunk/lib/Analysis/RegionStore.cpp Tue Dec 15 21:18:58 2009
@@ -1424,7 +1424,13 @@
     // Binding directly to a symbolic region should be treated as binding
     // to element 0.
     QualType T = SR->getSymbol()->getType(getContext());
-    T = T->getAs<PointerType>()->getPointeeType();
+    
+    // FIXME: Is this the right way to handle symbols that are references?
+    if (const PointerType *PT = T->getAs<PointerType>())
+      T = PT->getPointeeType();
+    else
+      T = T->getAs<ReferenceType>()->getPointeeType();
+
     R = GetElementZeroRegion(SR, T);
   }
 

Modified: cfe/trunk/lib/Analysis/Store.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Store.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/Store.cpp (original)
+++ cfe/trunk/lib/Analysis/Store.cpp Tue Dec 15 21:18:58 2009
@@ -198,11 +198,21 @@
 ///  as another region.
 SVal  StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
                                      QualType castTy) {
+  
+#ifndef NDEBUG
   if (castTy.isNull())
     return V;
+  
+  ASTContext &Ctx = ValMgr.getContext();
+  QualType T = R->getValueType(Ctx);
+
+  // Automatically translate references to pointers.
+  if (const ReferenceType *RT = T->getAs<ReferenceType>())
+    T = Ctx.getPointerType(RT->getPointeeType());
+
+  assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
+#endif
 
-  assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
-                                         R->getValueType(ValMgr.getContext())));
   return V;
 }
 

Modified: cfe/trunk/test/Analysis/dead-stores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dead-stores.cpp?rev=91501&r1=91500&r2=91501&view=diff

==============================================================================
--- cfe/trunk/test/Analysis/dead-stores.cpp (original)
+++ cfe/trunk/test/Analysis/dead-stores.cpp Tue Dec 15 21:18:58 2009
@@ -9,7 +9,7 @@
 //===----------------------------------------------------------------------===//
 
 int j;
-void f1() {
+void test1() {
   int x = 4;
 
   ++x; // expected-warning{{never read}}
@@ -26,14 +26,43 @@
 // Dead store checking involving constructors.
 //===----------------------------------------------------------------------===//
 
-class Test1 {
+class Test2 {
   int &x;
 public:
-  Test1(int &y) : x(y) {}
-  ~Test1() { ++x; }
+  Test2(int &y) : x(y) {}
+  ~Test2() { ++x; }
 };
 
-int test_ctor_1(int x) {
-  { Test1 a(x); } // no-warning
+int test2(int x) {
+  { Test2 a(x); } // no-warning
   return x;
 }
+
+//===----------------------------------------------------------------------===//
+// Test references.
+//===----------------------------------------------------------------------===//
+
+void test3_a(int x) {
+  ++x; // expected-warning{{never read}}
+}
+
+void test3_b(int &x) {
+  ++x; // no-warninge
+}
+
+void test3_c(int x) {
+  int &y = x;
+  // Shows the limitation of dead stores tracking.  The write is really
+  // dead since the value cannot escape the function.
+  ++y; // no-warning
+}
+
+void test3_d(int &x) {
+  int &y = x;
+  ++y; // no-warning
+}
+
+void test3_e(int &x) {
+  int &y = x;
+}
+





More information about the cfe-commits mailing list