r188206 - Patch by Chris Wailes <chris.wailes at gmail.com>.

Eric Christopher echristo at gmail.com
Tue Aug 13 14:16:54 PDT 2013


Should probably just submit those separately since it should be easy to do so :)

-eric

On Tue, Aug 13, 2013 at 9:55 AM, Chris Wailes <chris.wailes at gmail.com> wrote:
> Thanks for the feedback.  I've made the appropriate fixes and they will be
> in the next patch submission.
>
> - Chris
>
>
> On Mon, Aug 12, 2013 at 4:39 PM, Aaron Ballman <aaron at aaronballman.com>
> wrote:
>>
>> On Mon, Aug 12, 2013 at 5:20 PM, DeLesley Hutchins <delesley at google.com>
>> wrote:
>> > Author: delesley
>> > Date: Mon Aug 12 16:20:55 2013
>> > New Revision: 188206
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=188206&view=rev
>> > Log:
>> > Patch by Chris Wailes <chris.wailes at gmail.com>.
>> > Reviewed by delesley, dblaikie.
>> >
>> > Add the annotations and code needed to support a basic 'consumed'
>> > analysis.
>> >
>> > Summary:
>> > This new analysis is based on academic literature on linear types.  It
>> > tracks
>> > the state of a value, either as unconsumed, consumed, or unknown.
>> > Methods are
>> > then annotated as CallableWhenUnconsumed, and when an annotated method
>> > is
>> > called while the value is in the 'consumed' state a warning is issued.
>> > A value
>> > may be tested in the conditional statement of an if-statement; when this
>> > occurs
>> > we know the state of the value in the different branches, and this
>> > information
>> > is added to our analysis.  The code is still highly experimental, and
>> > the names
>> > of annotations or the algorithm may be subject to change.
>> >
>> > Added:
>> >     cfe/trunk/include/clang/Analysis/Analyses/Consumed.h
>> >     cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h
>> >     cfe/trunk/lib/Analysis/Consumed.cpp
>> >     cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp
>> >     cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
>> >     cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp
>> > Modified:
>> >     cfe/trunk/include/clang/Basic/Attr.td
>> >     cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> >     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> >     cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h
>> >     cfe/trunk/lib/Analysis/CMakeLists.txt
>> >     cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
>> >     cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>> >
>> > Added: cfe/trunk/include/clang/Analysis/Analyses/Consumed.h
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/Consumed.h?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Analysis/Analyses/Consumed.h (added)
>> > +++ cfe/trunk/include/clang/Analysis/Analyses/Consumed.h Mon Aug 12
>> > 16:20:55 2013
>> > @@ -0,0 +1,140 @@
>> > +//===- Consumed.h ----------------------------------------------*- C++
>> > --*-===//
>> > +//
>> > +//                     The LLVM Compiler Infrastructure
>> > +//
>> > +// This file is distributed under the University of Illinois Open
>> > Source
>> > +// License. See LICENSE.TXT for details.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +//
>> > +// A intra-procedural analysis for checking consumed properties.  This
>> > is based,
>> > +// in part, on research on linear types.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +
>> > +#ifndef LLVM_CLANG_CONSUMED_H
>> > +#define LLVM_CLANG_CONSUMED_H
>> > +
>> > +#include "clang/AST/DeclCXX.h"
>> > +#include "clang/AST/ExprCXX.h"
>> > +#include "clang/AST/StmtCXX.h"
>> > +#include "clang/Analysis/AnalysisContext.h"
>> > +#include "clang/Analysis/Analyses/PostOrderCFGView.h"
>> > +#include "clang/Basic/SourceLocation.h"
>> > +#include "clang/Sema/ConsumedWarningsHandler.h"
>> > +#include "clang/Sema/Sema.h"
>> > +
>> > +namespace clang {
>> > +namespace consumed {
>> > +
>> > +  enum ConsumedState {
>> > +    // No state information for the given variable.
>> > +    CS_None,
>> > +
>> > +    CS_Unknown,
>> > +    CS_Unconsumed,
>> > +    CS_Consumed
>> > +  };
>> > +
>> > +  class ConsumedStateMap {
>> > +
>> > +    typedef llvm::DenseMap<const VarDecl *, ConsumedState> MapType;
>> > +    typedef std::pair<const VarDecl *, ConsumedState> PairType;
>> > +
>> > +  protected:
>> > +
>> > +    MapType Map;
>> > +
>> > +  public:
>> > +    /// \brief Get the consumed state of a given variable.
>> > +    ConsumedState getState(const VarDecl *Var);
>> > +
>> > +    /// \brief Merge this state map with another map.
>> > +    void intersect(const ConsumedStateMap *Other);
>> > +
>> > +    /// \brief Mark all variables as unknown.
>> > +    void makeUnknown();
>> > +
>> > +    /// \brief Set the consumed state of a given variable.
>> > +    void setState(const VarDecl *Var, ConsumedState State);
>> > +  };
>> > +
>> > +  class ConsumedBlockInfo {
>> > +
>> > +    ConsumedStateMap **StateMapsArray;
>> > +    PostOrderCFGView::CFGBlockSet VisitedBlocks;
>> > +
>> > +  public:
>> > +
>> > +    ConsumedBlockInfo() : StateMapsArray(NULL) {}
>> > +
>> > +    ConsumedBlockInfo(const CFG *CFGraph)
>> > +      : StateMapsArray(new
>> > ConsumedStateMap*[CFGraph->getNumBlockIDs()]()),
>> > +        VisitedBlocks(CFGraph) {}
>> > +
>> > +    void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
>> > +                 bool &AlreadyOwned);
>> > +    void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap);
>> > +
>> > +    ConsumedStateMap* getInfo(const CFGBlock *Block);
>> > +
>> > +    void markVisited(const CFGBlock *Block);
>> > +  };
>> > +
>> > +  struct VarTestResult {
>> > +    const VarDecl *Var;
>> > +    SourceLocation Loc;
>> > +    bool UnconsumedInTrueBranch;
>> > +
>> > +    VarTestResult() : Var(NULL), Loc(), UnconsumedInTrueBranch(true) {}
>> > +
>> > +    VarTestResult(const VarDecl *Var, SourceLocation Loc,
>> > +                  bool UnconsumedInTrueBranch)
>> > +      : Var(Var), Loc(Loc),
>> > UnconsumedInTrueBranch(UnconsumedInTrueBranch) {}
>> > +  };
>> > +
>> > +  /// A class that handles the analysis of uniqueness violations.
>> > +  class ConsumedAnalyzer {
>> > +
>> > +    typedef llvm::DenseMap<const CXXRecordDecl *, bool> CacheMapType;
>> > +    typedef std::pair<const CXXRecordDecl *, bool> CachePairType;
>> > +
>> > +    Sema &S;
>> > +
>> > +    ConsumedBlockInfo BlockInfo;
>> > +    ConsumedStateMap *CurrStates;
>> > +
>> > +    CacheMapType ConsumableTypeCache;
>> > +
>> > +    bool hasConsumableAttributes(const CXXRecordDecl *RD);
>> > +    void splitState(const CFGBlock *CurrBlock, const IfStmt
>> > *Terminator);
>> > +
>> > +  public:
>> > +
>> > +    ConsumedWarningsHandlerBase &WarningsHandler;
>> > +
>> > +    ConsumedAnalyzer(Sema &S, ConsumedWarningsHandlerBase
>> > &WarningsHandler)
>> > +        : S(S), WarningsHandler(WarningsHandler) {}
>> > +
>> > +    /// \brief Get a constant reference to the Sema object.
>> > +    const Sema & getSema(void);
>> > +
>> > +    /// \brief Check to see if the type is a consumable type.
>> > +    bool isConsumableType(QualType Type);
>> > +
>> > +    /// \brief Check a function's CFG for consumed violations.
>> > +    ///
>> > +    /// We traverse the blocks in the CFG, keeping track of the state
>> > of each
>> > +    /// value who's type has uniquness annotations.  If methods are
>> > invoked in
>> > +    /// the wrong state a warning is issued.  Each block in the CFG is
>> > traversed
>> > +    /// exactly once.
>> > +    void run(AnalysisDeclContext &AC);
>> > +  };
>> > +
>> > +  unsigned checkEnabled(DiagnosticsEngine &D);
>> > +  /// \brief Check to see if a function tests an object's validity.
>> > +  bool isTestingFunction(const CXXMethodDecl *MethodDecl);
>> > +
>> > +}} // end namespace clang::consumed
>> > +
>> > +#endif
>> >
>> > Modified: cfe/trunk/include/clang/Basic/Attr.td
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Basic/Attr.td (original)
>> > +++ cfe/trunk/include/clang/Basic/Attr.td Mon Aug 12 16:20:55 2013
>> > @@ -918,6 +918,28 @@ def SharedLocksRequired : InheritableAtt
>> >    let TemplateDependent = 1;
>> >  }
>> >
>> > +// C/C++ consumed attributes.
>> > +
>> > +def CallableWhenUnconsumed : InheritableAttr {
>> > +  let Spellings = [GNU<"callable_when_unconsumed">];
>> > +  let Subjects = [CXXMethod];
>> > +}
>> > +
>> > +def TestsUnconsumed : InheritableAttr {
>> > +  let Spellings = [GNU<"tests_unconsumed">];
>> > +  let Subjects = [CXXMethod];
>> > +}
>> > +
>> > +def Consumes : InheritableAttr {
>> > +  let Spellings = [GNU<"consumes">];
>> > +  let Subjects = [CXXMethod];
>> > +}
>> > +
>> > +def TestsConsumed : InheritableAttr {
>> > +  let Spellings = [GNU<"tests_consumed">];
>> > +  let Subjects = [CXXMethod];
>> > +}
>> > +
>> >  // Type safety attributes for `void *' pointers and type tags.
>> >
>> >  def ArgumentWithTypeTag : InheritableAttr {
>> >
>> > Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
>> > +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Aug 12
>> > 16:20:55 2013
>> > @@ -478,6 +478,10 @@ def ThreadSafety : DiagGroup<"thread-saf
>> >                                ThreadSafetyPrecise]>;
>> >  def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">;
>> >
>> > +// Uniqueness Analysis warnings
>> > +def Consumed       : DiagGroup<"consumed">;
>> > +def ConsumedStrict : DiagGroup<"consumed-strict", [Consumed]>;
>> > +
>> >  // Note that putting warnings in -Wall will not disable them by
>> > default. If a
>> >  // warning should be active _only_ when -Wall is passed in, mark it as
>> >  // DefaultIgnore in addition to putting it here.
>> >
>> > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Aug 12
>> > 16:20:55 2013
>> > @@ -2178,6 +2178,28 @@ def note_found_mutex_near_match : Note<"
>> >  def warn_thread_safety_beta : Warning<
>> >    "Thread safety beta warning.">, InGroup<ThreadSafetyBeta>,
>> > DefaultIgnore;
>> >
>> > +// Consumed warnings
>> > +def warn_use_while_consumed : Warning<
>> > +  "invocation of method '%0' on object '%1' while it is in the
>> > 'consumed' "
>> > +  "state">, InGroup<Consumed>, DefaultIgnore;
>> > +def warn_use_of_temp_while_consumed : Warning<
>> > +  "invocation of method '%0' on a temporary object while it is in the "
>> > +  "'consumed' state">, InGroup<Consumed>, DefaultIgnore;
>> > +def warn_uniqueness_attribute_wrong_decl_type : Warning<
>> > +  "%0 attribute only applies to methods">,
>> > +  InGroup<Consumed>, DefaultIgnore;
>>
>> Please use warn_attribute_wrong_decl_type instead.
>>
>> > +
>> > +// ConsumedStrict warnings
>> > +def warn_use_in_unknown_state : Warning<
>> > +  "invocation of method '%0' on object '%1' while it is in an unknown
>> > state">,
>> > +  InGroup<ConsumedStrict>, DefaultIgnore;
>> > +def warn_use_of_temp_in_unknown_state : Warning<
>> > +  "invocation of method '%0' on a temporary object while it is in an
>> > unknown "
>> > +  "state">, InGroup<ConsumedStrict>, DefaultIgnore;
>> > +def warn_unnecessary_test : Warning<
>> > +  "unnecessary test. Variable '%0' is known to be in the '%1' state">,
>> > +  InGroup<ConsumedStrict>, DefaultIgnore;
>> > +
>> >  def warn_impcast_vector_scalar : Warning<
>> >    "implicit conversion turns vector to scalar: %0 to %1">,
>> >    InGroup<Conversion>, DefaultIgnore;
>> >
>> > Modified: cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h (original)
>> > +++ cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h Mon Aug 12
>> > 16:20:55 2013
>> > @@ -38,6 +38,7 @@ public:
>> >      unsigned enableCheckFallThrough : 1;
>> >      unsigned enableCheckUnreachable : 1;
>> >      unsigned enableThreadSafetyAnalysis : 1;
>> > +    unsigned enableConsumedAnalysis : 1;
>> >    public:
>> >      Policy();
>> >      void disableCheckFallThrough() { enableCheckFallThrough = 0; }
>> >
>> > Added: cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h (added)
>> > +++ cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h Mon Aug 12
>> > 16:20:55 2013
>> > @@ -0,0 +1,98 @@
>> > +//===- ConsumedWarningsHandler.h -------------------------------*- C++
>> > --*-===//
>> > +//
>> > +//                     The LLVM Compiler Infrastructure
>> > +//
>> > +// This file is distributed under the University of Illinois Open
>> > Source
>> > +// License. See LICENSE.TXT for details.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +//
>> > +// A handler class for warnings issued by the consumed analysis.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +
>> > +#ifndef LLVM_CLANG_CONSUMED_WARNING_HANDLER_H
>> > +#define LLVM_CLANG_CONSUMED_WARNING_HANDLER_H
>> > +
>> > +#include <list>
>> > +#include <utility>
>> > +
>> > +#include "clang/Basic/SourceLocation.h"
>> > +#include "clang/Sema/Sema.h"
>> > +#include "llvm/ADT/SmallVector.h"
>> > +#include "llvm/ADT/StringRef.h"
>> > +
>> > +namespace clang {
>> > +namespace consumed {
>> > +
>> > +  typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
>> > +  typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
>> > +  typedef std::list<DelayedDiag> DiagList;
>> > +
>> > +  class ConsumedWarningsHandlerBase {
>> > +
>> > +  public:
>> > +
>> > +    virtual ~ConsumedWarningsHandlerBase();
>> > +
>> > +    /// \brief Emit the warnings and notes left by the analysis.
>> > +    virtual void emitDiagnostics() {}
>> > +
>> > +    /// Warn about unnecessary-test errors.
>> > +    /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +    /// value.
>> > +    ///
>> > +    /// \param Loc -- The SourceLocation of the unnecessary test.
>> > +    virtual void warnUnnecessaryTest(StringRef VariableName,
>> > +                                     StringRef VariableState,
>> > +                                     SourceLocation Loc) {}
>> > +
>> > +    /// Warn about use-while-consumed errors.
>> > +    /// \param MethodName -- The name of the method that was
>> > incorrectly
>> > +    /// invoked.
>> > +    ///
>> > +    /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +    /// value.
>> > +    ///
>> > +    /// \param Loc -- The SourceLocation of the method invocation.
>> > +    virtual void warnUseOfTempWhileConsumed(StringRef MethodName,
>> > +                                            SourceLocation Loc) {}
>> > +
>> > +    /// Warn about use-in-unknown-state errors.
>> > +    /// \param MethodName -- The name of the method that was
>> > incorrectly
>> > +    /// invoked.
>> > +    ///
>> > +    /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +    /// value.
>> > +    ///
>> > +    /// \param Loc -- The SourceLocation of the method invocation.
>> > +    virtual void warnUseOfTempInUnknownState(StringRef MethodName,
>> > +                                             SourceLocation Loc) {}
>> > +
>> > +    /// Warn about use-while-consumed errors.
>> > +    /// \param MethodName -- The name of the method that was
>> > incorrectly
>> > +    /// invoked.
>> > +    ///
>> > +    /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +    /// value.
>> > +    ///
>> > +    /// \param Loc -- The SourceLocation of the method invocation.
>> > +    virtual void warnUseWhileConsumed(StringRef MethodName,
>> > +                                      StringRef VariableName,
>> > +                                      SourceLocation Loc) {}
>> > +
>> > +    /// Warn about use-in-unknown-state errors.
>> > +    /// \param MethodName -- The name of the method that was
>> > incorrectly
>> > +    /// invoked.
>> > +    ///
>> > +    /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +    /// value.
>> > +    ///
>> > +    /// \param Loc -- The SourceLocation of the method invocation.
>> > +    virtual void warnUseInUnknownState(StringRef MethodName,
>> > +                                       StringRef VariableName,
>> > +                                       SourceLocation Loc) {}
>> > +  };
>> > +}} // end clang::consumed
>> > +
>> > +#endif
>> >
>> > Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
>> > +++ cfe/trunk/lib/Analysis/CMakeLists.txt Mon Aug 12 16:20:55 2013
>> > @@ -6,6 +6,7 @@ add_clang_library(clangAnalysis
>> >    CFGStmtMap.cpp
>> >    CallGraph.cpp
>> >    CocoaConventions.cpp
>> > +  Consumed.cpp
>> >    Dominators.cpp
>> >    FormatString.cpp
>> >    LiveVariables.cpp
>> >
>> > Added: cfe/trunk/lib/Analysis/Consumed.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Consumed.cpp?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Analysis/Consumed.cpp (added)
>> > +++ cfe/trunk/lib/Analysis/Consumed.cpp Mon Aug 12 16:20:55 2013
>> > @@ -0,0 +1,802 @@
>> > +//===- Consumed.cpp --------------------------------------------*- C++
>> > --*-===//
>> > +//
>> > +//                     The LLVM Compiler Infrastructure
>> > +//
>> > +// This file is distributed under the University of Illinois Open
>> > Source
>> > +// License. See LICENSE.TXT for details.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +//
>> > +// A intra-procedural analysis for checking consumed properties.  This
>> > is based,
>> > +// in part, on research on linear types.
>> > +//
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +
>> > +#include "clang/AST/ASTContext.h"
>> > +#include "clang/AST/Attr.h"
>> > +#include "clang/AST/DeclCXX.h"
>> > +#include "clang/AST/ExprCXX.h"
>> > +#include "clang/AST/RecursiveASTVisitor.h"
>> > +#include "clang/AST/StmtVisitor.h"
>> > +#include "clang/AST/StmtCXX.h"
>> > +#include "clang/AST/Type.h"
>> > +#include "clang/Analysis/Analyses/PostOrderCFGView.h"
>> > +#include "clang/Analysis/AnalysisContext.h"
>> > +#include "clang/Analysis/CFG.h"
>> > +#include "clang/Analysis/Analyses/Consumed.h"
>> > +#include "clang/Basic/OperatorKinds.h"
>> > +#include "clang/Basic/SourceLocation.h"
>> > +#include "clang/Sema/ConsumedWarningsHandler.h"
>> > +#include "clang/Sema/SemaDiagnostic.h"
>> > +#include "llvm/ADT/DenseMap.h"
>> > +#include "llvm/ADT/SmallVector.h"
>> > +#include "llvm/Support/raw_ostream.h"
>> > +
>> > +// TODO: Add support for methods with CallableWhenUnconsumed.
>> > +// TODO: Mark variables as Unknown going into while- or for-loops only
>> > if they
>> > +//       are referenced inside that block. (Deferred)
>> > +// TODO: Add a method(s) to identify which method calls perform what
>> > state
>> > +//       transitions. (Deferred)
>> > +// TODO: Take notes on state transitions to provide better warning
>> > messages.
>> > +//       (Deferred)
>> > +// TODO: Test nested conditionals: A) Checking the same value multiple
>> > times,
>> > +//       and 2) Checking different values. (Deferred)
>> > +// TODO: Test IsFalseVisitor with values in the unknown state.
>> > (Deferred)
>> > +// TODO: Look into combining IsFalseVisitor and TestedVarsVisitor.
>> > (Deferred)
>> > +
>> > +using namespace clang;
>> > +using namespace consumed;
>> > +
>> > +// Key method definition
>> > +ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
>> > +
>> > +static StringRef stateToString(ConsumedState State) {
>> > +  switch (State) {
>> > +  case consumed::CS_None:
>> > +    return "none";
>> > +
>> > +  case consumed::CS_Unknown:
>> > +    return "unknown";
>> > +
>> > +  case consumed::CS_Unconsumed:
>> > +    return "unconsumed";
>> > +
>> > +  case consumed::CS_Consumed:
>> > +    return "consumed";
>> > +  }
>> > +}
>> > +
>> > +namespace {
>> > +class ConsumedStmtVisitor : public
>> > ConstStmtVisitor<ConsumedStmtVisitor> {
>> > +
>> > +  union PropagationUnion {
>> > +    ConsumedState State;
>> > +    const VarDecl *Var;
>> > +  };
>> > +
>> > +  class PropagationInfo {
>> > +    PropagationUnion StateOrVar;
>> > +
>> > +  public:
>> > +    bool IsVar;
>> > +
>> > +    PropagationInfo() : IsVar(false) {
>> > +      StateOrVar.State = consumed::CS_None;
>> > +    }
>> > +
>> > +    PropagationInfo(ConsumedState State) : IsVar(false) {
>> > +      StateOrVar.State = State;
>> > +    }
>> > +
>> > +    PropagationInfo(const VarDecl *Var) : IsVar(true) {
>> > +      StateOrVar.Var = Var;
>> > +    }
>> > +
>> > +    ConsumedState getState() { return StateOrVar.State; };
>> > +
>> > +    const VarDecl * getVar() { return IsVar ? StateOrVar.Var : NULL; };
>> > +  };
>> > +
>> > +  typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
>> > +  typedef std::pair<const Stmt *, PropagationInfo> PairType;
>> > +  typedef MapType::iterator InfoEntry;
>> > +
>> > +  ConsumedAnalyzer &Analyzer;
>> > +  ConsumedStateMap *StateMap;
>> > +  MapType PropagationMap;
>> > +
>> > +  void forwardInfo(const Stmt *From, const Stmt *To);
>> > +  bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
>> > +
>> > +public:
>> > +
>> > +  void Visit(const Stmt *StmtNode);
>> > +
>> > +  void VisitBinaryOperator(const BinaryOperator *BinOp);
>> > +  void VisitCallExpr(const CallExpr *Call);
>> > +  void VisitCastExpr(const CastExpr *Cast);
>> > +  void VisitCXXConstructExpr(const CXXConstructExpr *Call);
>> > +  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
>> > +  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
>> > +  void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
>> > +  void VisitDeclStmt(const DeclStmt *DelcS);
>> > +  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr
>> > *Temp);
>> > +  void VisitMemberExpr(const MemberExpr *MExpr);
>> > +  void VisitUnaryOperator(const UnaryOperator *UOp);
>> > +  void VisitVarDecl(const VarDecl *Var);
>> > +
>> > +  ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap
>> > *StateMap) :
>> > +    Analyzer(Analyzer), StateMap(StateMap) {}
>> > +
>> > +  void reset() {
>> > +    PropagationMap.clear();
>> > +  }
>> > +};
>> > +
>> > +void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To)
>> > {
>> > +  InfoEntry Entry = PropagationMap.find(From);
>> > +
>> > +  if (Entry != PropagationMap.end()) {
>> > +    PropagationMap.insert(PairType(To,
>> > PropagationInfo(Entry->second)));
>> > +  }
>> > +}
>> > +
>> > +bool ConsumedStmtVisitor::isLikeMoveAssignment(
>> > +  const CXXMethodDecl *MethodDecl) {
>> > +
>> > +  return MethodDecl->isMoveAssignmentOperator() ||
>> > +         (MethodDecl->getOverloadedOperator() == OO_Equal &&
>> > +          MethodDecl->getNumParams() == 1 &&
>> > +
>> > MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator
>> > *BinOp) {
>> > +  switch (BinOp->getOpcode()) {
>> > +  case BO_PtrMemD:
>> > +  case BO_PtrMemI:
>> > +    forwardInfo(BinOp->getLHS(), BinOp);
>> > +    break;
>> > +
>> > +  default:
>> > +    break;
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
>> > +  ConstStmtVisitor::Visit(StmtNode);
>> > +
>> > +  for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
>> > +       CE = StmtNode->child_end(); CI != CE; ++CI) {
>> > +
>> > +    PropagationMap.erase(*CI);
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
>> > +  if (const FunctionDecl *FunDecl =
>> > +    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
>> > +
>> > +    // Special case for the std::move function.
>> > +    // TODO: Make this more specific. (Deferred)
>> > +    if (FunDecl->getNameAsString() == "move") {
>> > +      InfoEntry Entry = PropagationMap.find(Call->getArg(0));
>> > +
>> > +      if (Entry != PropagationMap.end()) {
>> > +        PropagationMap.insert(PairType(Call, Entry->second));
>> > +      }
>> > +
>> > +      return;
>> > +    }
>> > +
>> > +    unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
>> > +
>> > +    for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index)
>> > {
>> > +      QualType ParamType = FunDecl->getParamDecl(Index -
>> > Offset)->getType();
>> > +
>> > +      InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
>> > +
>> > +      if (Entry == PropagationMap.end() || !Entry->second.IsVar) {
>> > +        continue;
>> > +      }
>> > +
>> > +      PropagationInfo PState = Entry->second;
>> > +
>> > +      if (ParamType->isRValueReferenceType() ||
>> > +          (ParamType->isLValueReferenceType() &&
>> > +           !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue()))
>> > {
>> > +
>> > +        StateMap->setState(PState.getVar(), consumed::CS_Consumed);
>> > +
>> > +      } else if (!(ParamType.isConstQualified() ||
>> > +                   ((ParamType->isReferenceType() ||
>> > +                     ParamType->isPointerType()) &&
>> > +                    ParamType->getPointeeType().isConstQualified()))) {
>> > +
>> > +        StateMap->setState(PState.getVar(), consumed::CS_Unknown);
>> > +      }
>> > +    }
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
>> > +  InfoEntry Entry = PropagationMap.find(Cast->getSubExpr());
>> > +
>> > +  if (Entry != PropagationMap.end())
>> > +    PropagationMap.insert(PairType(Cast, Entry->second));
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr
>> > *Call) {
>> > +  CXXConstructorDecl *Constructor = Call->getConstructor();
>> > +
>> > +  ASTContext &CurrContext = Analyzer.getSema().getASTContext();
>> > +  QualType ThisType =
>> > Constructor->getThisType(CurrContext)->getPointeeType();
>> > +
>> > +  if (Analyzer.isConsumableType(ThisType)) {
>> > +    if (Constructor->hasAttr<ConsumesAttr>() ||
>> > +        Constructor->isDefaultConstructor()) {
>> > +
>> > +      PropagationMap.insert(PairType(Call,
>> > +        PropagationInfo(consumed::CS_Consumed)));
>> > +
>> > +    } else if (Constructor->isMoveConstructor()) {
>> > +
>> > +      PropagationInfo PState =
>> > +        PropagationMap.find(Call->getArg(0))->second;
>> > +
>> > +      if (PState.IsVar) {
>> > +        const VarDecl* Var = PState.getVar();
>> > +
>> > +        PropagationMap.insert(PairType(Call,
>> > +          PropagationInfo(StateMap->getState(Var))));
>> > +
>> > +        StateMap->setState(Var, consumed::CS_Consumed);
>> > +
>> > +      } else {
>> > +        PropagationMap.insert(PairType(Call, PState));
>> > +      }
>> > +
>> > +    } else if (Constructor->isCopyConstructor()) {
>> > +      MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
>> > +
>> > +      if (Entry != PropagationMap.end())
>> > +        PropagationMap.insert(PairType(Call, Entry->second));
>> > +
>> > +    } else {
>> > +      PropagationMap.insert(PairType(Call,
>> > +        PropagationInfo(consumed::CS_Unconsumed)));
>> > +    }
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
>> > +  const CXXMemberCallExpr *Call) {
>> > +
>> > +  VisitCallExpr(Call);
>> > +
>> > +  InfoEntry Entry =
>> > PropagationMap.find(Call->getCallee()->IgnoreParens());
>> > +
>> > +  if (Entry != PropagationMap.end()) {
>> > +    PropagationInfo PState = Entry->second;
>> > +    if (!PState.IsVar) return;
>> > +
>> > +    const CXXMethodDecl *Method = Call->getMethodDecl();
>> > +
>> > +    if (Method->hasAttr<ConsumesAttr>())
>> > +      StateMap->setState(PState.getVar(), consumed::CS_Consumed);
>> > +    else if (!Method->isConst())
>> > +      StateMap->setState(PState.getVar(), consumed::CS_Unknown);
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
>> > +  const CXXOperatorCallExpr *Call) {
>> > +
>> > +  const FunctionDecl *FunDecl =
>> > +    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
>> > +
>> > +  if (!FunDecl) return;
>> > +
>> > +  if (isa<CXXMethodDecl>(FunDecl) &&
>> > +      isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
>> > +
>> > +    InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
>> > +    InfoEntry REntry = PropagationMap.find(Call->getArg(1));
>> > +
>> > +    PropagationInfo LPState, RPState;
>> > +
>> > +    if (LEntry != PropagationMap.end() &&
>> > +        REntry != PropagationMap.end()) {
>> > +
>> > +      LPState = LEntry->second;
>> > +      RPState = REntry->second;
>> > +
>> > +      if (LPState.IsVar && RPState.IsVar) {
>> > +        StateMap->setState(LPState.getVar(),
>> > +          StateMap->getState(RPState.getVar()));
>> > +
>> > +        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
>> > +
>> > +        PropagationMap.insert(PairType(Call, LPState));
>> > +
>> > +      } else if (LPState.IsVar && !RPState.IsVar) {
>> > +        StateMap->setState(LPState.getVar(), RPState.getState());
>> > +
>> > +        PropagationMap.insert(PairType(Call, LPState));
>> > +
>> > +      } else if (!LPState.IsVar && RPState.IsVar) {
>> > +        PropagationMap.insert(PairType(Call,
>> > +          PropagationInfo(StateMap->getState(RPState.getVar()))));
>> > +
>> > +        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
>> > +
>> > +      } else {
>> > +        PropagationMap.insert(PairType(Call, RPState));
>> > +      }
>> > +
>> > +    } else if (LEntry != PropagationMap.end() &&
>> > +               REntry == PropagationMap.end()) {
>> > +
>> > +      LPState = LEntry->second;
>> > +
>> > +      if (LPState.IsVar) {
>> > +        StateMap->setState(LPState.getVar(), consumed::CS_Unknown);
>> > +
>> > +        PropagationMap.insert(PairType(Call, LPState));
>> > +
>> > +      } else {
>> > +        PropagationMap.insert(PairType(Call,
>> > +          PropagationInfo(consumed::CS_Unknown)));
>> > +      }
>> > +
>> > +    } else if (LEntry == PropagationMap.end() &&
>> > +               REntry != PropagationMap.end()) {
>> > +
>> > +      RPState = REntry->second;
>> > +
>> > +      if (RPState.IsVar) {
>> > +        const VarDecl *Var = RPState.getVar();
>> > +
>> > +        PropagationMap.insert(PairType(Call,
>> > +          PropagationInfo(StateMap->getState(Var))));
>> > +
>> > +        StateMap->setState(Var, consumed::CS_Consumed);
>> > +
>> > +      } else {
>> > +        PropagationMap.insert(PairType(Call, RPState));
>> > +      }
>> > +    }
>> > +
>> > +  } else {
>> > +
>> > +    VisitCallExpr(Call);
>> > +
>> > +    InfoEntry Entry = PropagationMap.find(Call->getArg(0));
>> > +
>> > +    if (Entry != PropagationMap.end()) {
>> > +
>> > +      PropagationInfo PState = Entry->second;
>> > +
>> > +      // TODO: When we support CallableWhenConsumed this will have to
>> > check for
>> > +      //       the different attributes and change the behavior bellow.
>> > +      //       (Deferred)
>> > +      if (FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) {
>> > +        if (PState.IsVar) {
>> > +          const VarDecl *Var = PState.getVar();
>> > +
>> > +          switch (StateMap->getState(Var)) {
>> > +          case CS_Consumed:
>> > +            Analyzer.WarningsHandler.warnUseWhileConsumed(
>> > +              FunDecl->getNameAsString(), Var->getNameAsString(),
>> > +              Call->getExprLoc());
>> > +            break;
>> > +
>> > +          case CS_Unknown:
>> > +            Analyzer.WarningsHandler.warnUseInUnknownState(
>> > +              FunDecl->getNameAsString(), Var->getNameAsString(),
>> > +              Call->getExprLoc());
>> > +            break;
>> > +
>> > +          default:
>> > +            break;
>> > +          }
>> > +
>> > +        } else {
>> > +          switch (PState.getState()) {
>> > +          case CS_Consumed:
>> > +            Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
>> > +              FunDecl->getNameAsString(), Call->getExprLoc());
>> > +            break;
>> > +
>> > +          case CS_Unknown:
>> > +            Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
>> > +              FunDecl->getNameAsString(), Call->getExprLoc());
>> > +            break;
>> > +
>> > +          default:
>> > +            break;
>> > +          }
>> > +        }
>> > +      }
>> > +
>> > +      // Handle non-constant member operators.
>> > +      if (const CXXMethodDecl *MethodDecl =
>> > +        dyn_cast_or_null<CXXMethodDecl>(FunDecl)) {
>> > +
>> > +        if (!MethodDecl->isConst() && PState.IsVar)
>> > +          StateMap->setState(PState.getVar(), consumed::CS_Unknown);
>> > +      }
>> > +    }
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef)
>> > {
>> > +  if (const VarDecl *Var =
>> > dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
>> > +    if (StateMap->getState(Var) != consumed::CS_None)
>> > +      PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
>> > +  for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
>> > +       DE = DeclS->decl_end(); DI != DE; ++DI) {
>> > +
>> > +    if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
>> > +  }
>> > +
>> > +  if (DeclS->isSingleDecl())
>> > +    if (const VarDecl *Var =
>> > dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
>> > +      PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
>> > +  const MaterializeTemporaryExpr *Temp) {
>> > +
>> > +  InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
>> > +
>> > +  if (Entry != PropagationMap.end())
>> > +    PropagationMap.insert(PairType(Temp, Entry->second));
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
>> > +  forwardInfo(MExpr->getBase(), MExpr);
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp)
>> > {
>> > +  if (UOp->getOpcode() == UO_AddrOf) {
>> > +    InfoEntry Entry = PropagationMap.find(UOp->getSubExpr());
>> > +
>> > +    if (Entry != PropagationMap.end())
>> > +      PropagationMap.insert(PairType(UOp, Entry->second));
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
>> > +  if (Analyzer.isConsumableType(Var->getType())) {
>> > +    PropagationInfo PState =
>> > +      PropagationMap.find(Var->getInit())->second;
>> > +
>> > +    StateMap->setState(Var, PState.IsVar ?
>> > +      StateMap->getState(PState.getVar()) : PState.getState());
>> > +  }
>> > +}
>> > +} // end anonymous::ConsumedStmtVisitor
>> > +
>> > +namespace {
>> > +
>> > +// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
>> > +//       if (valid) ...; (Deferred)
>> > +class TestedVarsVisitor : public RecursiveASTVisitor<TestedVarsVisitor>
>> > {
>> > +
>> > +  bool Invert;
>> > +  SourceLocation CurrTestLoc;
>> > +
>> > +  ConsumedStateMap *StateMap;
>> > +
>> > +public:
>> > +  bool IsUsefulConditional;
>> > +  VarTestResult Test;
>> > +
>> > +  TestedVarsVisitor(ConsumedStateMap *StateMap) : Invert(false),
>> > +    StateMap(StateMap), IsUsefulConditional(false) {}
>> > +
>> > +  bool VisitCallExpr(CallExpr *Call);
>> > +  bool VisitDeclRefExpr(DeclRefExpr *DeclRef);
>> > +  bool VisitUnaryOperator(UnaryOperator *UnaryOp);
>> > +};
>> > +
>> > +bool TestedVarsVisitor::VisitCallExpr(CallExpr *Call) {
>> > +  if (const CXXMethodDecl *Method =
>> > +    dyn_cast_or_null<CXXMethodDecl>(Call->getDirectCallee())) {
>> > +
>> > +    if (isTestingFunction(Method)) {
>> > +      CurrTestLoc = Call->getExprLoc();
>> > +      IsUsefulConditional = true;
>> > +      return true;
>> > +    }
>> > +
>> > +    IsUsefulConditional = false;
>> > +  }
>> > +
>> > +  return false;
>> > +}
>> > +
>> > +bool TestedVarsVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
>> > +  if (const VarDecl *Var =
>> > dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) {
>> > +    if (StateMap->getState(Var) != consumed::CS_None) {
>> > +      Test = VarTestResult(Var, CurrTestLoc, !Invert);
>> > +    }
>> > +
>> > +  } else {
>> > +    IsUsefulConditional = false;
>> > +  }
>> > +
>> > +  return IsUsefulConditional;
>> > +}
>> > +
>> > +bool TestedVarsVisitor::VisitUnaryOperator(UnaryOperator *UnaryOp) {
>> > +  if (UnaryOp->getOpcode() == UO_LNot) {
>> > +    Invert = true;
>> > +    TraverseStmt(UnaryOp->getSubExpr());
>> > +
>> > +  } else {
>> > +    IsUsefulConditional = false;
>> > +  }
>> > +
>> > +  return false;
>> > +}
>> > +} // end anonymouse::TestedVarsVisitor
>> > +
>> > +namespace clang {
>> > +namespace consumed {
>> > +
>> > +void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
>> > +                                ConsumedStateMap *StateMap,
>> > +                                bool &AlreadyOwned) {
>> > +
>> > +  if (VisitedBlocks.alreadySet(Block)) return;
>> > +
>> > +  ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
>> > +
>> > +  if (Entry) {
>> > +    Entry->intersect(StateMap);
>> > +
>> > +  } else if (AlreadyOwned) {
>> > +    StateMapsArray[Block->getBlockID()] = new
>> > ConsumedStateMap(*StateMap);
>> > +
>> > +  } else {
>> > +    StateMapsArray[Block->getBlockID()] = StateMap;
>> > +    AlreadyOwned = true;
>> > +  }
>> > +}
>> > +
>> > +void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
>> > +                                ConsumedStateMap *StateMap) {
>> > +
>> > +  if (VisitedBlocks.alreadySet(Block)) {
>> > +    delete StateMap;
>> > +    return;
>> > +  }
>> > +
>> > +  ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
>> > +
>> > +  if (Entry) {
>> > +    Entry->intersect(StateMap);
>> > +    delete StateMap;
>> > +
>> > +  } else {
>> > +    StateMapsArray[Block->getBlockID()] = StateMap;
>> > +  }
>> > +}
>> > +
>> > +ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
>> > +  return StateMapsArray[Block->getBlockID()];
>> > +}
>> > +
>> > +void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
>> > +  VisitedBlocks.insert(Block);
>> > +}
>> > +
>> > +ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
>> > +  MapType::const_iterator Entry = Map.find(Var);
>> > +
>> > +  if (Entry != Map.end()) {
>> > +    return Entry->second;
>> > +
>> > +  } else {
>> > +    return CS_None;
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
>> > +  ConsumedState LocalState;
>> > +
>> > +  for (MapType::const_iterator DMI = Other->Map.begin(),
>> > +       DME = Other->Map.end(); DMI != DME; ++DMI) {
>> > +
>> > +    LocalState = this->getState(DMI->first);
>> > +
>> > +    if (LocalState != CS_None && LocalState != DMI->second)
>> > +      setState(DMI->first, CS_Unknown);
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStateMap::makeUnknown() {
>> > +  PairType Pair;
>> > +
>> > +  for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI
>> > != DME;
>> > +       ++DMI) {
>> > +
>> > +    Pair = *DMI;
>> > +
>> > +    Map.erase(Pair.first);
>> > +    Map.insert(PairType(Pair.first, CS_Unknown));
>> > +  }
>> > +}
>> > +
>> > +void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState
>> > State) {
>> > +  Map[Var] = State;
>> > +}
>> > +
>> > +const Sema & ConsumedAnalyzer::getSema() {
>> > +  return S;
>> > +}
>> > +
>> > +
>> > +bool ConsumedAnalyzer::isConsumableType(QualType Type) {
>> > +  const CXXRecordDecl *RD =
>> > +    dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl());
>> > +
>> > +  if (!RD) return false;
>> > +
>> > +  std::pair<CacheMapType::iterator, bool> Entry =
>> > +    ConsumableTypeCache.insert(std::make_pair(RD, false));
>> > +
>> > +  if (Entry.second)
>> > +    Entry.first->second = hasConsumableAttributes(RD);
>> > +
>> > +  return Entry.first->second;
>> > +}
>> > +
>> > +// TODO: Walk the base classes to see if any of them are unique types.
>> > +//       (Deferred)
>> > +bool ConsumedAnalyzer::hasConsumableAttributes(const CXXRecordDecl *RD)
>> > {
>> > +  for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
>> > +       ME = RD->method_end(); MI != ME; ++MI) {
>> > +
>> > +    for (Decl::attr_iterator AI = (*MI)->attr_begin(), AE =
>> > (*MI)->attr_end();
>> > +         AI != AE; ++AI) {
>> > +
>> > +      switch ((*AI)->getKind()) {
>> > +      case attr::CallableWhenUnconsumed:
>> > +      case attr::TestsUnconsumed:
>> > +        return true;
>> > +
>> > +      default:
>> > +        break;
>> > +      }
>> > +    }
>> > +  }
>> > +
>> > +  return false;
>> > +}
>> > +
>> > +// TODO: Handle other forms of branching with precision, including
>> > while- and
>> > +//       for-loops. (Deferred)
>> > +void ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
>> > +                                  const IfStmt *Terminator) {
>> > +
>> > +  TestedVarsVisitor Visitor(CurrStates);
>> > +  Visitor.TraverseStmt(const_cast<Expr*>(Terminator->getCond()));
>> > +
>> > +  bool HasElse = Terminator->getElse() != NULL;
>> > +
>> > +  ConsumedStateMap *ElseOrMergeStates = new
>> > ConsumedStateMap(*CurrStates);
>> > +
>> > +  if (Visitor.IsUsefulConditional) {
>> > +    ConsumedState VarState = CurrStates->getState(Visitor.Test.Var);
>> > +
>> > +    if (VarState != CS_Unknown) {
>> > +      // FIXME: Make this not warn if the test is from a macro
>> > expansion.
>> > +      //        (Deferred)
>> > +
>> > WarningsHandler.warnUnnecessaryTest(Visitor.Test.Var->getNameAsString(),
>> > +        stateToString(VarState), Visitor.Test.Loc);
>> > +    }
>> > +
>> > +    if (Visitor.Test.UnconsumedInTrueBranch) {
>> > +      CurrStates->setState(Visitor.Test.Var, CS_Unconsumed);
>> > +      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var,
>> > CS_Consumed);
>> > +
>> > +    } else {
>> > +      CurrStates->setState(Visitor.Test.Var, CS_Consumed);
>> > +      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var,
>> > CS_Unconsumed);
>> > +    }
>> > +  }
>> > +
>> > +  CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
>> > +
>> > +  if (*SI)   BlockInfo.addInfo(*SI,        CurrStates);
>> > +  if (*++SI) BlockInfo.addInfo(*SI, ElseOrMergeStates);
>> > +}
>> > +
>> > +void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
>> > +  const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
>> > +
>> > +  if (!D) return;
>> > +
>> > +  BlockInfo = ConsumedBlockInfo(AC.getCFG());
>> > +
>> > +  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
>> > +
>> > +  CurrStates = new ConsumedStateMap();
>> > +
>> > +  // Visit all of the function's basic blocks.
>> > +  for (PostOrderCFGView::iterator I = SortedGraph->begin(),
>> > +       E = SortedGraph->end(); I != E; ++I) {
>> > +
>> > +    const CFGBlock *CurrBlock = *I;
>> > +    BlockInfo.markVisited(CurrBlock);
>> > +
>> > +    if (CurrStates == NULL)
>> > +      CurrStates = BlockInfo.getInfo(CurrBlock);
>> > +
>> > +    ConsumedStmtVisitor Visitor(*this, CurrStates);
>> > +
>> > +    // Visit all of the basic block's statements.
>> > +    for (CFGBlock::const_iterator BI = CurrBlock->begin(),
>> > +         BE = CurrBlock->end(); BI != BE; ++BI) {
>> > +
>> > +      if (BI->getKind() == CFGElement::Statement)
>> > +        Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
>> > +    }
>> > +
>> > +    // TODO: Remove any variables that have reached the end of their
>> > +    //       lifetimes from the state map. (Deferred)
>> > +
>> > +    if (const IfStmt *Terminator =
>> > +      dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
>> > +
>> > +      splitState(CurrBlock, Terminator);
>> > +      CurrStates = NULL;
>> > +
>> > +    } else if (CurrBlock->succ_size() > 1) {
>> > +      CurrStates->makeUnknown();
>> > +
>> > +      bool OwnershipTaken = false;
>> > +
>> > +      for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
>> > +           SE = CurrBlock->succ_end(); SI != SE; ++SI) {
>> > +
>> > +        if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
>> > +      }
>> > +
>> > +      if (!OwnershipTaken)
>> > +        delete CurrStates;
>> > +
>> > +      CurrStates = NULL;
>> > +
>> > +    } else if (CurrBlock->succ_size() == 1 &&
>> > +               (*CurrBlock->succ_begin())->pred_size() > 1) {
>> > +
>> > +      BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
>> > +      CurrStates = NULL;
>> > +    }
>> > +
>> > +    Visitor.reset();
>> > +  } // End of block iterator.
>> > +
>> > +  // Delete the last existing state map.
>> > +  delete CurrStates;
>> > +
>> > +  WarningsHandler.emitDiagnostics();
>> > +}
>> > +
>> > +unsigned checkEnabled(DiagnosticsEngine &D) {
>> > +  return (unsigned)
>> > +    (D.getDiagnosticLevel(diag::warn_use_while_consumed,
>> > SourceLocation()) !=
>> > +     DiagnosticsEngine::Ignored);
>> > +}
>> > +
>> > +bool isTestingFunction(const CXXMethodDecl *Method) {
>> > +  return Method->hasAttr<TestsUnconsumedAttr>();
>> > +}
>> > +
>> > +}} // end namespace clang::consumed
>> >
>> > Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
>> > +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Mon Aug 12 16:20:55
>> > 2013
>> > @@ -25,6 +25,7 @@
>> >  #include "clang/AST/StmtObjC.h"
>> >  #include "clang/AST/StmtVisitor.h"
>> >  #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
>> > +#include "clang/Analysis/Analyses/Consumed.h"
>> >  #include "clang/Analysis/Analyses/ReachableCode.h"
>> >  #include "clang/Analysis/Analyses/ThreadSafety.h"
>> >  #include "clang/Analysis/Analyses/UninitializedValues.h"
>> > @@ -1241,12 +1242,8 @@ private:
>> >  };
>> >  }
>> >
>> > -
>> >
>> > -//===----------------------------------------------------------------------===//
>> > -// -Wthread-safety
>> >
>> > -//===----------------------------------------------------------------------===//
>> >  namespace clang {
>> > -namespace thread_safety {
>> > +namespace {
>> >  typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
>> >  typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
>> >  typedef std::list<DelayedDiag> DiagList;
>> > @@ -1261,7 +1258,13 @@ struct SortDiagBySourceLocation {
>> >      return SM.isBeforeInTranslationUnit(left.first.first,
>> > right.first.first);
>> >    }
>> >  };
>> > +}}
>> >
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +// -Wthread-safety
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +namespace clang {
>> > +namespace thread_safety {
>> >  namespace {
>> >  class ThreadSafetyReporter : public
>> > clang::thread_safety::ThreadSafetyHandler {
>> >    Sema &S;
>> > @@ -1412,6 +1415,119 @@ class ThreadSafetyReporter : public clan
>> >  }
>> >
>> >
>> > //===----------------------------------------------------------------------===//
>> > +// -Wconsumed
>> >
>> > +//===----------------------------------------------------------------------===//
>> > +
>> > +namespace clang {
>> > +namespace consumed {
>> > +namespace {
>> > +class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
>> > +
>> > +  Sema &S;
>> > +  DiagList Warnings;
>> > +
>> > +public:
>> > +
>> > +  ConsumedWarningsHandler(Sema &S) : S(S) {}
>> > +
>> > +  void emitDiagnostics() {
>> > +    Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
>> > +
>> > +    for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
>> > +         I != E; ++I) {
>> > +
>> > +      const OptionalNotes &Notes = I->second;
>> > +      S.Diag(I->first.first, I->first.second);
>> > +
>> > +      for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN;
>> > ++NoteI) {
>> > +        S.Diag(Notes[NoteI].first, Notes[NoteI].second);
>> > +      }
>> > +    }
>> > +  }
>> > +
>> > +  /// Warn about unnecessary-test errors.
>> > +  /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +  /// value.
>> > +  ///
>> > +  /// \param Loc -- The SourceLocation of the unnecessary test.
>> > +  void warnUnnecessaryTest(StringRef VariableName, StringRef
>> > VariableState,
>> > +                           SourceLocation Loc) {
>> > +
>> > +    PartialDiagnosticAt Warning(Loc,
>> > S.PDiag(diag::warn_unnecessary_test) <<
>> > +                                 VariableName << VariableState);
>> > +
>> > +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
>> > +  }
>> > +
>> > +  /// Warn about use-while-consumed errors.
>> > +  /// \param MethodName -- The name of the method that was incorrectly
>> > +  /// invoked.
>> > +  ///
>> > +  /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +  /// value.
>> > +  ///
>> > +  /// \param Loc -- The SourceLocation of the method invocation.
>> > +  void warnUseOfTempWhileConsumed(StringRef MethodName, SourceLocation
>> > Loc) {
>> > +
>> > +    PartialDiagnosticAt Warning(Loc, S.PDiag(
>> > +      diag::warn_use_of_temp_while_consumed) << MethodName);
>> > +
>> > +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
>> > +  }
>> > +
>> > +  /// Warn about use-in-unknown-state errors.
>> > +  /// \param MethodName -- The name of the method that was incorrectly
>> > +  /// invoked.
>> > +  ///
>> > +  /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +  /// value.
>> > +  ///
>> > +  /// \param Loc -- The SourceLocation of the method invocation.
>> > +  void warnUseOfTempInUnknownState(StringRef MethodName, SourceLocation
>> > Loc) {
>> > +
>> > +    PartialDiagnosticAt Warning(Loc, S.PDiag(
>> > +      diag::warn_use_of_temp_in_unknown_state) << MethodName);
>> > +
>> > +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
>> > +  }
>> > +
>> > +  /// Warn about use-while-consumed errors.
>> > +  /// \param MethodName -- The name of the method that was incorrectly
>> > +  /// invoked.
>> > +  ///
>> > +  /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +  /// value.
>> > +  ///
>> > +  /// \param Loc -- The SourceLocation of the method invocation.
>> > +  void warnUseWhileConsumed(StringRef MethodName, StringRef
>> > VariableName,
>> > +                            SourceLocation Loc) {
>> > +
>> > +    PartialDiagnosticAt Warning(Loc,
>> > S.PDiag(diag::warn_use_while_consumed) <<
>> > +                                MethodName << VariableName);
>> > +
>> > +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
>> > +  }
>> > +
>> > +  /// Warn about use-in-unknown-state errors.
>> > +  /// \param MethodName -- The name of the method that was incorrectly
>> > +  /// invoked.
>> > +  ///
>> > +  /// \param VariableName -- The name of the variable that holds the
>> > unique
>> > +  /// value.
>> > +  ///
>> > +  /// \param Loc -- The SourceLocation of the method invocation.
>> > +  void warnUseInUnknownState(StringRef MethodName, StringRef
>> > VariableName,
>> > +                             SourceLocation Loc) {
>> > +
>> > +    PartialDiagnosticAt Warning(Loc,
>> > S.PDiag(diag::warn_use_in_unknown_state) <<
>> > +                                MethodName << VariableName);
>> > +
>> > +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
>> > +  }
>> > +};
>> > +}}}
>> > +
>> >
>> > +//===----------------------------------------------------------------------===//
>> >  // AnalysisBasedWarnings - Worker object used by Sema to execute
>> > analysis-based
>> >  //  warnings on a function, method, or block.
>> >
>> > //===----------------------------------------------------------------------===//
>> > @@ -1420,6 +1536,7 @@ clang::sema::AnalysisBasedWarnings::Poli
>> >    enableCheckFallThrough = 1;
>> >    enableCheckUnreachable = 0;
>> >    enableThreadSafetyAnalysis = 0;
>> > +  enableConsumedAnalysis = 0;
>> >  }
>> >
>> >  clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
>> > @@ -1440,6 +1557,7 @@ clang::sema::AnalysisBasedWarnings::Anal
>> >    DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
>> >      (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
>> >       DiagnosticsEngine::Ignored);
>> > +  DefaultPolicy.enableConsumedAnalysis = consumed::checkEnabled(D);
>> >
>> >  }
>> >
>> > @@ -1501,7 +1619,8 @@ AnalysisBasedWarnings::IssueWarnings(sem
>> >    // prototyping, but we need a way for analyses to say what
>> > expressions they
>> >    // expect to always be CFGElements and then fill in the BuildOptions
>> >    // appropriately.  This is essentially a layering violation.
>> > -  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {
>> > +  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
>> > +      P.enableConsumedAnalysis) {
>> >      // Unreachable code analysis and thread safety require a linearized
>> > CFG.
>> >      AC.getCFGBuildOptions().setAllAlwaysAdd();
>> >    }
>> > @@ -1605,6 +1724,13 @@ AnalysisBasedWarnings::IssueWarnings(sem
>> >      Reporter.emitDiagnostics();
>> >    }
>> >
>> > +  // Check for violations of consumed properties.
>> > +  if (P.enableConsumedAnalysis) {
>> > +    consumed::ConsumedWarningsHandler WarningHandler(S);
>> > +    consumed::ConsumedAnalyzer Analyzer(S, WarningHandler);
>> > +    Analyzer.run(AC);
>> > +  }
>> > +
>> >    if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
>> >        != DiagnosticsEngine::Ignored ||
>> >
>> > Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
>> >
>> > Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=188206&r1=188205&r2=188206&view=diff
>> >
>> > ==============================================================================
>> > --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
>> > +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Aug 12 16:20:55 2013
>> > @@ -997,6 +997,69 @@ static void handleLocksExcludedAttr(Sema
>> >                                 Attr.getAttributeSpellingListIndex()));
>> >  }
>> >
>> > +static void handleConsumesAttr(Sema &S, Decl *D,
>> > +                               const AttributeList &Attr) {
>> > +  assert(!Attr.isInvalid());
>>
>> The assert is superfluous here and elsewhere (see ProcessDeclAttribute
>> where invalid attributes are early-returned).
>>
>> > +  if (!checkAttributeNumArgs(S, Attr, 0)) return;
>> > +
>> > +  if (!(isa<CXXMethodDecl>(D) || isa<CXXConstructorDecl>(D))) {
>> > +    S.Diag(Attr.getLoc(),
>> > diag::warn_uniqueness_attribute_wrong_decl_type) <<
>> > +      Attr.getName();
>> > +    return;
>> > +  }
>>
>> Please update the attribute's subjects to match the predicate.  Also,
>> is this really only valid for C++ functions?  The given warning seems
>> to imply non-instance methods are also acceptable targets.  If this
>> really is for C++ only methods, ensure the warning is updated to have
>> the proper wording.  This also applies elsewhere.
>>
>> > +
>> > +  D->addAttr(::new (S.Context)
>> > +             ConsumesAttr(Attr.getRange(), S.Context,
>> > +              Attr.getAttributeSpellingListIndex()));
>> > +}
>> > +
>> > +static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D,
>> > +                                             const AttributeList &Attr)
>> > {
>> > +  assert(!Attr.isInvalid());
>> > +  if (!checkAttributeNumArgs(S, Attr, 0)) return;
>> > +
>> > +  if (!isa<CXXMethodDecl>(D)) {
>> > +    S.Diag(Attr.getLoc(),
>> > diag::warn_uniqueness_attribute_wrong_decl_type) <<
>> > +      Attr.getName();
>> > +    return;
>> > +  }
>> > +
>> > +  D->addAttr(::new (S.Context)
>> > +             CallableWhenUnconsumedAttr(Attr.getRange(), S.Context,
>> > +              Attr.getAttributeSpellingListIndex()));
>> > +}
>> > +
>> > +static void handleTestsConsumedAttr(Sema &S, Decl *D,
>> > +                                    const AttributeList &Attr) {
>> > +  assert(!Attr.isInvalid());
>> > +  if (!checkAttributeNumArgs(S, Attr, 0)) return;
>> > +
>> > +  if (!isa<CXXMethodDecl>(D)) {
>> > +    S.Diag(Attr.getLoc(),
>> > diag::warn_uniqueness_attribute_wrong_decl_type) <<
>> > +      Attr.getName();
>> > +    return;
>> > +  }
>> > +
>> > +  D->addAttr(::new (S.Context)
>> > +             TestsConsumedAttr(Attr.getRange(), S.Context,
>> > +              Attr.getAttributeSpellingListIndex()));
>> > +}
>> > +
>> > +static void handleTestsUnconsumedAttr(Sema &S, Decl *D,
>> > +                                      const AttributeList &Attr) {
>> > +  assert(!Attr.isInvalid());
>> > +  if (!checkAttributeNumArgs(S, Attr, 0)) return;
>> > +
>> > +  if (!isa<CXXMethodDecl>(D)) {
>> > +    S.Diag(Attr.getLoc(),
>> > diag::warn_uniqueness_attribute_wrong_decl_type) <<
>> > +      Attr.getName();
>> > +    return;
>> > +  }
>> > +
>> > +  D->addAttr(::new (S.Context)
>> > +             TestsUnconsumedAttr(Attr.getRange(), S.Context,
>> > +              Attr.getAttributeSpellingListIndex()));
>> > +}
>> >
>> >  static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
>> >                                      const AttributeList &Attr) {
>> > @@ -4952,6 +5015,20 @@ static void ProcessInheritableDeclAttr(S
>> >      handleAcquiredAfterAttr(S, D, Attr);
>> >      break;
>> >
>> > +  // Uniqueness analysis attributes.
>> > +  case AttributeList::AT_Consumes:
>> > +    handleConsumesAttr(S, D, Attr);
>> > +    break;
>> > +  case AttributeList::AT_CallableWhenUnconsumed:
>> > +    handleCallableWhenUnconsumedAttr(S, D, Attr);
>> > +    break;
>> > +  case AttributeList::AT_TestsConsumed:
>> > +    handleTestsConsumedAttr(S, D, Attr);
>> > +    break;
>> > +  case AttributeList::AT_TestsUnconsumed:
>> > +    handleTestsUnconsumedAttr(S, D, Attr);
>> > +    break;
>> > +
>> >    // Type safety attributes.
>> >    case AttributeList::AT_ArgumentWithTypeTag:
>> >      handleArgumentWithTypeTagAttr(S, D, Attr);
>> >
>> > Added: cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp (added)
>> > +++ cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp Mon Aug 12
>> > 16:20:55 2013
>> > @@ -0,0 +1,123 @@
>> > +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed-strict -std=c++11
>> > %s
>> > +
>> > +#define CALLABLE_WHEN_UNCONSUMED __attribute__
>> > ((callable_when_unconsumed))
>> > +#define CONSUMES __attribute__ ((consumes))
>> > +#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed))
>> > +
>> > +typedef decltype(nullptr) nullptr_t;
>> > +
>> > +template <typename T>
>> > +class Bar {
>> > +  T var;
>> > +
>> > +  public:
>> > +  Bar(void);
>> > +  Bar(T val);
>> > +  Bar(Bar<T> &other);
>> > +  Bar(Bar<T> &&other);
>> > +
>> > +  Bar<T>& operator=(Bar<T>  &other);
>> > +  Bar<T>& operator=(Bar<T> &&other);
>> > +  Bar<T>& operator=(nullptr_t);
>> > +
>> > +  template <typename U>
>> > +  Bar<T>& operator=(Bar<U>  &other);
>> > +
>> > +  template <typename U>
>> > +  Bar<T>& operator=(Bar<U> &&other);
>> > +
>> > +  void operator*(void) const CALLABLE_WHEN_UNCONSUMED;
>> > +
>> > +  bool isValid(void) const TESTS_UNCONSUMED;
>> > +
>> > +  void constCall(void) const;
>> > +  void nonconstCall(void);
>> > +
>> > +  void consume(void) CONSUMES;
>> > +};
>> > +
>> > +void baf0(Bar<int>  &var);
>> > +void baf1(Bar<int>  *var);
>> > +
>> > +void testIfStmt(void) {
>> > +  Bar<int> var;
>> > +
>> > +  if (var.isValid()) { // expected-warning {{unnecessary test. Variable
>> > 'var' is known to be in the 'consumed' state}}
>> > +
>> > +    // Empty
>> > +
>> > +  } else {
>> > +    // Empty
>> > +  }
>> > +}
>> > +
>> > +void testConditionalMerge(void) {
>> > +  Bar<int> var;
>> > +
>> > +  if (var.isValid()) {// expected-warning {{unnecessary test. Variable
>> > 'var' is known to be in the 'consumed' state}}
>> > +
>> > +    // Empty
>> > +  }
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +
>> > +  if (var.isValid()) {
>> > +    // Empty
>> > +
>> > +  } else {
>> > +    // Empty
>> > +  }
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> > +
>> > +void testCallingConventions(void) {
>> > +  Bar<int> var(42);
>> > +
>> > +  baf0(var);
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +
>> > +  var = Bar<int>(42);
>> > +  baf1(&var);
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> > +
>> > +void testMoveAsignmentish(void) {
>> > +  Bar<int> var;
>> > +
>> > +  var = nullptr;
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> > +
>> > +void testConstAndNonConstMemberFunctions(void) {
>> > +  Bar<int> var(42);
>> > +
>> > +  var.constCall();
>> > +  *var;
>> > +
>> > +  var.nonconstCall();
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> > +
>> > +void testSimpleForLoop(void) {
>> > +  Bar<int> var;
>> > +
>> > +  for (int i = 0; i < 10; ++i) {
>> > +    *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +  }
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> > +
>> > +void testSimpleWhileLoop(void) {
>> > +  int i = 0;
>> > +
>> > +  Bar<int> var;
>> > +
>> > +  while (i < 10) {
>> > +    *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +    ++i;
>> > +  }
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in an unknown state}}
>> > +}
>> >
>> > Added: cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp (added)
>> > +++ cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp Mon Aug 12
>> > 16:20:55 2013
>> > @@ -0,0 +1,188 @@
>> > +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s
>> > +
>> > +#define CALLABLE_WHEN_UNCONSUMED __attribute__
>> > ((callable_when_unconsumed))
>> > +#define CONSUMES __attribute__ ((consumes))
>> > +#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed))
>> > +
>> > +typedef decltype(nullptr) nullptr_t;
>> > +
>> > +template <typename T>
>> > +class Bar {
>> > +  T var;
>> > +
>> > +  public:
>> > +  Bar(void);
>> > +  Bar(nullptr_t p) CONSUMES;
>> > +  Bar(T val);
>> > +  Bar(Bar<T> &other);
>> > +  Bar(Bar<T> &&other);
>> > +
>> > +  Bar<T>& operator=(Bar<T>  &other);
>> > +  Bar<T>& operator=(Bar<T> &&other);
>> > +  Bar<T>& operator=(nullptr_t);
>> > +
>> > +  template <typename U>
>> > +  Bar<T>& operator=(Bar<U>  &other);
>> > +
>> > +  template <typename U>
>> > +  Bar<T>& operator=(Bar<U> &&other);
>> > +
>> > +  void operator*(void) const CALLABLE_WHEN_UNCONSUMED;
>> > +
>> > +  bool isValid(void) const TESTS_UNCONSUMED;
>> > +  operator bool() const TESTS_UNCONSUMED;
>> > +
>> > +  void constCall(void) const;
>> > +  void nonconstCall(void);
>> > +
>> > +  void consume(void) CONSUMES;
>> > +};
>> > +
>> > +void baf0(const Bar<int>  var);
>> > +void baf1(const Bar<int> &var);
>> > +void baf2(const Bar<int> *var);
>> > +
>> > +void baf3(Bar<int> &&var);
>> > +
>> > +void testInitialization(void) {
>> > +  Bar<int> var0;
>> > +  Bar<int> var1 = Bar<int>();
>> > +
>> > +  var0 = Bar<int>();
>> > +
>> > +  *var0; // expected-warning {{invocation of method 'operator*' on
>> > object 'var0' while it is in the 'consumed' state}}
>> > +  *var1; // expected-warning {{invocation of method 'operator*' on
>> > object 'var1' while it is in the 'consumed' state}}
>> > +
>> > +  if (var0.isValid()) {
>> > +    *var0;
>> > +    *var1;  // expected-warning {{invocation of method 'operator*' on
>> > object 'var1' while it is in the 'consumed' state}}
>> > +
>> > +  } else {
>> > +    *var0;  // expected-warning {{invocation of method 'operator*' on
>> > object 'var0' while it is in the 'consumed' state}}
>> > +  }
>> > +}
>> > +
>> > +void testSimpleRValueRefs(void) {
>> > +  Bar<int> var0;
>> > +  Bar<int> var1(42);
>> > +
>> > +  *var0; // expected-warning {{invocation of method 'operator*' on
>> > object 'var0' while it is in the 'consumed' state}}
>> > +  *var1;
>> > +
>> > +  var0 = static_cast<Bar<int>&&>(var1);
>> > +
>> > +  *var0;
>> > +  *var1; // expected-warning {{invocation of method 'operator*' on
>> > object 'var1' while it is in the 'consumed' state}}
>> > +}
>> > +
>> > +void testIfStmt(void) {
>> > +  Bar<int> var;
>> > +
>> > +  if (var.isValid()) {
>> > +    // Empty
>> > +
>> > +  } else {
>> > +    *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +  }
>> > +
>> > +  if (!var.isValid()) {
>> > +    *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +
>> > +  } else {
>> > +    *var;
>> > +  }
>> > +
>> > +  if (var) {
>> > +    // Empty
>> > +
>> > +  } else {
>> > +    *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +  }
>> > +}
>> > +
>> > +void testCallingConventions(void) {
>> > +  Bar<int> var(42);
>> > +
>> > +  baf0(var);
>> > +  *var;
>> > +
>> > +  baf1(var);
>> > +  *var;
>> > +
>> > +  baf2(&var);
>> > +  *var;
>> > +
>> > +  baf3(static_cast<Bar<int>&&>(var));
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +}
>> > +
>> > +void testMoveAsignmentish(void) {
>> > +  Bar<int>  var0;
>> > +  Bar<long> var1(42);
>> > +
>> > +  *var0; // expected-warning {{invocation of method 'operator*' on
>> > object 'var0' while it is in the 'consumed' state}}
>> > +  *var1;
>> > +
>> > +  var0 = static_cast<Bar<long>&&>(var1);
>> > +
>> > +  *var0;
>> > +  *var1; // expected-warning {{invocation of method 'operator*' on
>> > object 'var1' while it is in the 'consumed' state}}
>> > +}
>> > +
>> > +void testConditionalMerge(void) {
>> > +  Bar<int> var;
>> > +
>> > +  if (var.isValid()) {
>> > +    // Empty
>> > +  }
>> > +
>> > +  *var;
>> > +
>> > +  if (var.isValid()) {
>> > +    // Empty
>> > +
>> > +  } else {
>> > +    // Empty
>> > +  }
>> > +
>> > +  *var;
>> > +}
>> > +
>> > +void testConsumes0(void) {
>> > +  Bar<int> var(42);
>> > +
>> > +  *var;
>> > +
>> > +  var.consume();
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +}
>> > +
>> > +void testConsumes1(void) {
>> > +  Bar<int> var(nullptr);
>> > +
>> > +  *var; // expected-warning {{invocation of method 'operator*' on
>> > object 'var' while it is in the 'consumed' state}}
>> > +}
>> > +
>> > +void testSimpleForLoop(void) {
>> > +  Bar<int> var;
>> > +
>> > +  for (int i = 0; i < 10; ++i) {
>> > +    *var;
>> > +  }
>> > +
>> > +  *var;
>> > +}
>> > +
>> > +void testSimpleWhileLoop(void) {
>> > +  int i = 0;
>> > +
>> > +  Bar<int> var;
>> > +
>> > +  while (i < 10) {
>> > +    *var;
>> > +    ++i;
>> > +  }
>> > +
>> > +  *var;
>> > +}
>> >
>> > Added: cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp
>> > URL:
>> > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp?rev=188206&view=auto
>> >
>> > ==============================================================================
>> > --- cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp (added)
>> > +++ cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp Mon Aug 12 16:20:55
>> > 2013
>> > @@ -0,0 +1,29 @@
>> > +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s
>> > +
>> > +#define CONSUMES                  __attribute__ ((consumes))
>> > +#define TESTS_UNCONSUMED          __attribute__ ((tests_unconsumed))
>> > +#define CALLABLE_WHEN_UNCONSUMED  __attribute__
>> > ((callable_when_unconsumed))
>> > +
>> > +class AttrTester0 {
>> > +  void Consumes(void)        __attribute__ ((consumes(42))); //
>> > expected-error {{attribute takes no arguments}}
>> > +  bool TestsUnconsumed(void) __attribute__ ((tests_unconsumed(42))); //
>> > expected-error {{attribute takes no arguments}}
>> > +  void CallableWhenUnconsumed(void)
>> > +    __attribute__ ((callable_when_unconsumed(42))); // expected-error
>> > {{attribute takes no arguments}}
>> > +};
>> > +
>> > +int var0 CONSUMES; // expected-warning {{'consumes' attribute only
>> > applies to methods}}
>> > +int var1 TESTS_UNCONSUMED; // expected-warning {{'tests_unconsumed'
>> > attribute only applies to methods}}
>> > +int var2 CALLABLE_WHEN_UNCONSUMED; // expected-warning
>> > {{'callable_when_unconsumed' attribute only applies to methods}}
>> > +
>> > +void function0(void) CONSUMES; // expected-warning {{'consumes'
>> > attribute only applies to methods}}
>> > +void function1(void) TESTS_UNCONSUMED; // expected-warning
>> > {{'tests_unconsumed' attribute only applies to methods}}
>> > +void function2(void) CALLABLE_WHEN_UNCONSUMED; // expected-warning
>> > {{'callable_when_unconsumed' attribute only applies to methods}}
>> > +
>> > +class AttrTester1 {
>> > +  void consumes(void)        CONSUMES;
>> > +  bool testsUnconsumed(void) TESTS_UNCONSUMED;
>> > +};
>> > +
>> > +class AttrTester2 {
>> > +  void callableWhenUnconsumed(void) CALLABLE_WHEN_UNCONSUMED;
>> > +};
>> >
>> >
>> > _______________________________________________
>> > cfe-commits mailing list
>> > cfe-commits at cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>> ~Aaron
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>



More information about the cfe-commits mailing list