<div dir="ltr"><div>Thanks for the feedback.  I've made the appropriate fixes and they will be in the next patch submission.<br><br></div>- Chris<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Aug 12, 2013 at 4:39 PM, Aaron Ballman <span dir="ltr"><<a href="mailto:aaron@aaronballman.com" target="_blank">aaron@aaronballman.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Mon, Aug 12, 2013 at 5:20 PM, DeLesley Hutchins <<a href="mailto:delesley@google.com">delesley@google.com</a>> wrote:<br>

> Author: delesley<br>
> Date: Mon Aug 12 16:20:55 2013<br>
> New Revision: 188206<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=188206&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=188206&view=rev</a><br>
> Log:<br>
> Patch by Chris Wailes <<a href="mailto:chris.wailes@gmail.com">chris.wailes@gmail.com</a>>.<br>
> Reviewed by delesley, dblaikie.<br>
><br>
> Add the annotations and code needed to support a basic 'consumed' analysis.<br>
><br>
> Summary:<br>
> This new analysis is based on academic literature on linear types.  It tracks<br>
> the state of a value, either as unconsumed, consumed, or unknown.  Methods are<br>
> then annotated as CallableWhenUnconsumed, and when an annotated method is<br>
> called while the value is in the 'consumed' state a warning is issued.  A value<br>
> may be tested in the conditional statement of an if-statement; when this occurs<br>
> we know the state of the value in the different branches, and this information<br>
> is added to our analysis.  The code is still highly experimental, and the names<br>
> of annotations or the algorithm may be subject to change.<br>
><br>
> Added:<br>
>     cfe/trunk/include/clang/Analysis/Analyses/Consumed.h<br>
>     cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h<br>
>     cfe/trunk/lib/Analysis/Consumed.cpp<br>
>     cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp<br>
>     cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp<br>
>     cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp<br>
> Modified:<br>
>     cfe/trunk/include/clang/Basic/Attr.td<br>
>     cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
>     cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h<br>
>     cfe/trunk/lib/Analysis/CMakeLists.txt<br>
>     cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp<br>
>     cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
><br>
> Added: cfe/trunk/include/clang/Analysis/Analyses/Consumed.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/Consumed.h?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/Consumed.h?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Analysis/Analyses/Consumed.h (added)<br>
> +++ cfe/trunk/include/clang/Analysis/Analyses/Consumed.h Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,140 @@<br>
> +//===- Consumed.h ----------------------------------------------*- C++ --*-===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +// A intra-procedural analysis for checking consumed properties.  This is based,<br>
> +// in part, on research on linear types.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef LLVM_CLANG_CONSUMED_H<br>
> +#define LLVM_CLANG_CONSUMED_H<br>
> +<br>
> +#include "clang/AST/DeclCXX.h"<br>
> +#include "clang/AST/ExprCXX.h"<br>
> +#include "clang/AST/StmtCXX.h"<br>
> +#include "clang/Analysis/AnalysisContext.h"<br>
> +#include "clang/Analysis/Analyses/PostOrderCFGView.h"<br>
> +#include "clang/Basic/SourceLocation.h"<br>
> +#include "clang/Sema/ConsumedWarningsHandler.h"<br>
> +#include "clang/Sema/Sema.h"<br>
> +<br>
> +namespace clang {<br>
> +namespace consumed {<br>
> +<br>
> +  enum ConsumedState {<br>
> +    // No state information for the given variable.<br>
> +    CS_None,<br>
> +<br>
> +    CS_Unknown,<br>
> +    CS_Unconsumed,<br>
> +    CS_Consumed<br>
> +  };<br>
> +<br>
> +  class ConsumedStateMap {<br>
> +<br>
> +    typedef llvm::DenseMap<const VarDecl *, ConsumedState> MapType;<br>
> +    typedef std::pair<const VarDecl *, ConsumedState> PairType;<br>
> +<br>
> +  protected:<br>
> +<br>
> +    MapType Map;<br>
> +<br>
> +  public:<br>
> +    /// \brief Get the consumed state of a given variable.<br>
> +    ConsumedState getState(const VarDecl *Var);<br>
> +<br>
> +    /// \brief Merge this state map with another map.<br>
> +    void intersect(const ConsumedStateMap *Other);<br>
> +<br>
> +    /// \brief Mark all variables as unknown.<br>
> +    void makeUnknown();<br>
> +<br>
> +    /// \brief Set the consumed state of a given variable.<br>
> +    void setState(const VarDecl *Var, ConsumedState State);<br>
> +  };<br>
> +<br>
> +  class ConsumedBlockInfo {<br>
> +<br>
> +    ConsumedStateMap **StateMapsArray;<br>
> +    PostOrderCFGView::CFGBlockSet VisitedBlocks;<br>
> +<br>
> +  public:<br>
> +<br>
> +    ConsumedBlockInfo() : StateMapsArray(NULL) {}<br>
> +<br>
> +    ConsumedBlockInfo(const CFG *CFGraph)<br>
> +      : StateMapsArray(new ConsumedStateMap*[CFGraph->getNumBlockIDs()]()),<br>
> +        VisitedBlocks(CFGraph) {}<br>
> +<br>
> +    void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,<br>
> +                 bool &AlreadyOwned);<br>
> +    void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap);<br>
> +<br>
> +    ConsumedStateMap* getInfo(const CFGBlock *Block);<br>
> +<br>
> +    void markVisited(const CFGBlock *Block);<br>
> +  };<br>
> +<br>
> +  struct VarTestResult {<br>
> +    const VarDecl *Var;<br>
> +    SourceLocation Loc;<br>
> +    bool UnconsumedInTrueBranch;<br>
> +<br>
> +    VarTestResult() : Var(NULL), Loc(), UnconsumedInTrueBranch(true) {}<br>
> +<br>
> +    VarTestResult(const VarDecl *Var, SourceLocation Loc,<br>
> +                  bool UnconsumedInTrueBranch)<br>
> +      : Var(Var), Loc(Loc), UnconsumedInTrueBranch(UnconsumedInTrueBranch) {}<br>
> +  };<br>
> +<br>
> +  /// A class that handles the analysis of uniqueness violations.<br>
> +  class ConsumedAnalyzer {<br>
> +<br>
> +    typedef llvm::DenseMap<const CXXRecordDecl *, bool> CacheMapType;<br>
> +    typedef std::pair<const CXXRecordDecl *, bool> CachePairType;<br>
> +<br>
> +    Sema &S;<br>
> +<br>
> +    ConsumedBlockInfo BlockInfo;<br>
> +    ConsumedStateMap *CurrStates;<br>
> +<br>
> +    CacheMapType ConsumableTypeCache;<br>
> +<br>
> +    bool hasConsumableAttributes(const CXXRecordDecl *RD);<br>
> +    void splitState(const CFGBlock *CurrBlock, const IfStmt *Terminator);<br>
> +<br>
> +  public:<br>
> +<br>
> +    ConsumedWarningsHandlerBase &WarningsHandler;<br>
> +<br>
> +    ConsumedAnalyzer(Sema &S, ConsumedWarningsHandlerBase &WarningsHandler)<br>
> +        : S(S), WarningsHandler(WarningsHandler) {}<br>
> +<br>
> +    /// \brief Get a constant reference to the Sema object.<br>
> +    const Sema & getSema(void);<br>
> +<br>
> +    /// \brief Check to see if the type is a consumable type.<br>
> +    bool isConsumableType(QualType Type);<br>
> +<br>
> +    /// \brief Check a function's CFG for consumed violations.<br>
> +    ///<br>
> +    /// We traverse the blocks in the CFG, keeping track of the state of each<br>
> +    /// value who's type has uniquness annotations.  If methods are invoked in<br>
> +    /// the wrong state a warning is issued.  Each block in the CFG is traversed<br>
> +    /// exactly once.<br>
> +    void run(AnalysisDeclContext &AC);<br>
> +  };<br>
> +<br>
> +  unsigned checkEnabled(DiagnosticsEngine &D);<br>
> +  /// \brief Check to see if a function tests an object's validity.<br>
> +  bool isTestingFunction(const CXXMethodDecl *MethodDecl);<br>
> +<br>
> +}} // end namespace clang::consumed<br>
> +<br>
> +#endif<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/Attr.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/Attr.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/Attr.td Mon Aug 12 16:20:55 2013<br>
> @@ -918,6 +918,28 @@ def SharedLocksRequired : InheritableAtt<br>
>    let TemplateDependent = 1;<br>
>  }<br>
><br>
> +// C/C++ consumed attributes.<br>
> +<br>
> +def CallableWhenUnconsumed : InheritableAttr {<br>
> +  let Spellings = [GNU<"callable_when_unconsumed">];<br>
> +  let Subjects = [CXXMethod];<br>
> +}<br>
> +<br>
> +def TestsUnconsumed : InheritableAttr {<br>
> +  let Spellings = [GNU<"tests_unconsumed">];<br>
> +  let Subjects = [CXXMethod];<br>
> +}<br>
> +<br>
> +def Consumes : InheritableAttr {<br>
> +  let Spellings = [GNU<"consumes">];<br>
> +  let Subjects = [CXXMethod];<br>
> +}<br>
> +<br>
> +def TestsConsumed : InheritableAttr {<br>
> +  let Spellings = [GNU<"tests_consumed">];<br>
> +  let Subjects = [CXXMethod];<br>
> +}<br>
> +<br>
>  // Type safety attributes for `void *' pointers and type tags.<br>
><br>
>  def ArgumentWithTypeTag : InheritableAttr {<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Aug 12 16:20:55 2013<br>
> @@ -478,6 +478,10 @@ def ThreadSafety : DiagGroup<"thread-saf<br>
>                                ThreadSafetyPrecise]>;<br>
>  def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">;<br>
><br>
> +// Uniqueness Analysis warnings<br>
> +def Consumed       : DiagGroup<"consumed">;<br>
> +def ConsumedStrict : DiagGroup<"consumed-strict", [Consumed]>;<br>
> +<br>
>  // Note that putting warnings in -Wall will not disable them by default. If a<br>
>  // warning should be active _only_ when -Wall is passed in, mark it as<br>
>  // DefaultIgnore in addition to putting it here.<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Aug 12 16:20:55 2013<br>
> @@ -2178,6 +2178,28 @@ def note_found_mutex_near_match : Note<"<br>
>  def warn_thread_safety_beta : Warning<<br>
>    "Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore;<br>
><br>
> +// Consumed warnings<br>
> +def warn_use_while_consumed : Warning<<br>
> +  "invocation of method '%0' on object '%1' while it is in the 'consumed' "<br>
> +  "state">, InGroup<Consumed>, DefaultIgnore;<br>
> +def warn_use_of_temp_while_consumed : Warning<<br>
> +  "invocation of method '%0' on a temporary object while it is in the "<br>
> +  "'consumed' state">, InGroup<Consumed>, DefaultIgnore;<br>
> +def warn_uniqueness_attribute_wrong_decl_type : Warning<<br>
> +  "%0 attribute only applies to methods">,<br>
> +  InGroup<Consumed>, DefaultIgnore;<br>
<br>
</div></div>Please use warn_attribute_wrong_decl_type instead.<br>
<div><div class="h5"><br>
> +<br>
> +// ConsumedStrict warnings<br>
> +def warn_use_in_unknown_state : Warning<<br>
> +  "invocation of method '%0' on object '%1' while it is in an unknown state">,<br>
> +  InGroup<ConsumedStrict>, DefaultIgnore;<br>
> +def warn_use_of_temp_in_unknown_state : Warning<<br>
> +  "invocation of method '%0' on a temporary object while it is in an unknown "<br>
> +  "state">, InGroup<ConsumedStrict>, DefaultIgnore;<br>
> +def warn_unnecessary_test : Warning<<br>
> +  "unnecessary test. Variable '%0' is known to be in the '%1' state">,<br>
> +  InGroup<ConsumedStrict>, DefaultIgnore;<br>
> +<br>
>  def warn_impcast_vector_scalar : Warning<<br>
>    "implicit conversion turns vector to scalar: %0 to %1">,<br>
>    InGroup<Conversion>, DefaultIgnore;<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/AnalysisBasedWarnings.h Mon Aug 12 16:20:55 2013<br>
> @@ -38,6 +38,7 @@ public:<br>
>      unsigned enableCheckFallThrough : 1;<br>
>      unsigned enableCheckUnreachable : 1;<br>
>      unsigned enableThreadSafetyAnalysis : 1;<br>
> +    unsigned enableConsumedAnalysis : 1;<br>
>    public:<br>
>      Policy();<br>
>      void disableCheckFallThrough() { enableCheckFallThrough = 0; }<br>
><br>
> Added: cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h (added)<br>
> +++ cfe/trunk/include/clang/Sema/ConsumedWarningsHandler.h Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,98 @@<br>
> +//===- ConsumedWarningsHandler.h -------------------------------*- C++ --*-===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +// A handler class for warnings issued by the consumed analysis.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef LLVM_CLANG_CONSUMED_WARNING_HANDLER_H<br>
> +#define LLVM_CLANG_CONSUMED_WARNING_HANDLER_H<br>
> +<br>
> +#include <list><br>
> +#include <utility><br>
> +<br>
> +#include "clang/Basic/SourceLocation.h"<br>
> +#include "clang/Sema/Sema.h"<br>
> +#include "llvm/ADT/SmallVector.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> +<br>
> +namespace clang {<br>
> +namespace consumed {<br>
> +<br>
> +  typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;<br>
> +  typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;<br>
> +  typedef std::list<DelayedDiag> DiagList;<br>
> +<br>
> +  class ConsumedWarningsHandlerBase {<br>
> +<br>
> +  public:<br>
> +<br>
> +    virtual ~ConsumedWarningsHandlerBase();<br>
> +<br>
> +    /// \brief Emit the warnings and notes left by the analysis.<br>
> +    virtual void emitDiagnostics() {}<br>
> +<br>
> +    /// Warn about unnecessary-test errors.<br>
> +    /// \param VariableName -- The name of the variable that holds the unique<br>
> +    /// value.<br>
> +    ///<br>
> +    /// \param Loc -- The SourceLocation of the unnecessary test.<br>
> +    virtual void warnUnnecessaryTest(StringRef VariableName,<br>
> +                                     StringRef VariableState,<br>
> +                                     SourceLocation Loc) {}<br>
> +<br>
> +    /// Warn about use-while-consumed errors.<br>
> +    /// \param MethodName -- The name of the method that was incorrectly<br>
> +    /// invoked.<br>
> +    ///<br>
> +    /// \param VariableName -- The name of the variable that holds the unique<br>
> +    /// value.<br>
> +    ///<br>
> +    /// \param Loc -- The SourceLocation of the method invocation.<br>
> +    virtual void warnUseOfTempWhileConsumed(StringRef MethodName,<br>
> +                                            SourceLocation Loc) {}<br>
> +<br>
> +    /// Warn about use-in-unknown-state errors.<br>
> +    /// \param MethodName -- The name of the method that was incorrectly<br>
> +    /// invoked.<br>
> +    ///<br>
> +    /// \param VariableName -- The name of the variable that holds the unique<br>
> +    /// value.<br>
> +    ///<br>
> +    /// \param Loc -- The SourceLocation of the method invocation.<br>
> +    virtual void warnUseOfTempInUnknownState(StringRef MethodName,<br>
> +                                             SourceLocation Loc) {}<br>
> +<br>
> +    /// Warn about use-while-consumed errors.<br>
> +    /// \param MethodName -- The name of the method that was incorrectly<br>
> +    /// invoked.<br>
> +    ///<br>
> +    /// \param VariableName -- The name of the variable that holds the unique<br>
> +    /// value.<br>
> +    ///<br>
> +    /// \param Loc -- The SourceLocation of the method invocation.<br>
> +    virtual void warnUseWhileConsumed(StringRef MethodName,<br>
> +                                      StringRef VariableName,<br>
> +                                      SourceLocation Loc) {}<br>
> +<br>
> +    /// Warn about use-in-unknown-state errors.<br>
> +    /// \param MethodName -- The name of the method that was incorrectly<br>
> +    /// invoked.<br>
> +    ///<br>
> +    /// \param VariableName -- The name of the variable that holds the unique<br>
> +    /// value.<br>
> +    ///<br>
> +    /// \param Loc -- The SourceLocation of the method invocation.<br>
> +    virtual void warnUseInUnknownState(StringRef MethodName,<br>
> +                                       StringRef VariableName,<br>
> +                                       SourceLocation Loc) {}<br>
> +  };<br>
> +}} // end clang::consumed<br>
> +<br>
> +#endif<br>
><br>
> Modified: cfe/trunk/lib/Analysis/CMakeLists.txt<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)<br>
> +++ cfe/trunk/lib/Analysis/CMakeLists.txt Mon Aug 12 16:20:55 2013<br>
> @@ -6,6 +6,7 @@ add_clang_library(clangAnalysis<br>
>    CFGStmtMap.cpp<br>
>    CallGraph.cpp<br>
>    CocoaConventions.cpp<br>
> +  Consumed.cpp<br>
>    Dominators.cpp<br>
>    FormatString.cpp<br>
>    LiveVariables.cpp<br>
><br>
> Added: cfe/trunk/lib/Analysis/Consumed.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Consumed.cpp?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Consumed.cpp?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Analysis/Consumed.cpp (added)<br>
> +++ cfe/trunk/lib/Analysis/Consumed.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,802 @@<br>
> +//===- Consumed.cpp --------------------------------------------*- C++ --*-===//<br>
> +//<br>
> +//                     The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +//<br>
> +// A intra-procedural analysis for checking consumed properties.  This is based,<br>
> +// in part, on research on linear types.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#include "clang/AST/ASTContext.h"<br>
> +#include "clang/AST/Attr.h"<br>
> +#include "clang/AST/DeclCXX.h"<br>
> +#include "clang/AST/ExprCXX.h"<br>
> +#include "clang/AST/RecursiveASTVisitor.h"<br>
> +#include "clang/AST/StmtVisitor.h"<br>
> +#include "clang/AST/StmtCXX.h"<br>
> +#include "clang/AST/Type.h"<br>
> +#include "clang/Analysis/Analyses/PostOrderCFGView.h"<br>
> +#include "clang/Analysis/AnalysisContext.h"<br>
> +#include "clang/Analysis/CFG.h"<br>
> +#include "clang/Analysis/Analyses/Consumed.h"<br>
> +#include "clang/Basic/OperatorKinds.h"<br>
> +#include "clang/Basic/SourceLocation.h"<br>
> +#include "clang/Sema/ConsumedWarningsHandler.h"<br>
> +#include "clang/Sema/SemaDiagnostic.h"<br>
> +#include "llvm/ADT/DenseMap.h"<br>
> +#include "llvm/ADT/SmallVector.h"<br>
> +#include "llvm/Support/raw_ostream.h"<br>
> +<br>
> +// TODO: Add support for methods with CallableWhenUnconsumed.<br>
> +// TODO: Mark variables as Unknown going into while- or for-loops only if they<br>
> +//       are referenced inside that block. (Deferred)<br>
> +// TODO: Add a method(s) to identify which method calls perform what state<br>
> +//       transitions. (Deferred)<br>
> +// TODO: Take notes on state transitions to provide better warning messages.<br>
> +//       (Deferred)<br>
> +// TODO: Test nested conditionals: A) Checking the same value multiple times,<br>
> +//       and 2) Checking different values. (Deferred)<br>
> +// TODO: Test IsFalseVisitor with values in the unknown state. (Deferred)<br>
> +// TODO: Look into combining IsFalseVisitor and TestedVarsVisitor. (Deferred)<br>
> +<br>
> +using namespace clang;<br>
> +using namespace consumed;<br>
> +<br>
> +// Key method definition<br>
> +ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}<br>
> +<br>
> +static StringRef stateToString(ConsumedState State) {<br>
> +  switch (State) {<br>
> +  case consumed::CS_None:<br>
> +    return "none";<br>
> +<br>
> +  case consumed::CS_Unknown:<br>
> +    return "unknown";<br>
> +<br>
> +  case consumed::CS_Unconsumed:<br>
> +    return "unconsumed";<br>
> +<br>
> +  case consumed::CS_Consumed:<br>
> +    return "consumed";<br>
> +  }<br>
> +}<br>
> +<br>
> +namespace {<br>
> +class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {<br>
> +<br>
> +  union PropagationUnion {<br>
> +    ConsumedState State;<br>
> +    const VarDecl *Var;<br>
> +  };<br>
> +<br>
> +  class PropagationInfo {<br>
> +    PropagationUnion StateOrVar;<br>
> +<br>
> +  public:<br>
> +    bool IsVar;<br>
> +<br>
> +    PropagationInfo() : IsVar(false) {<br>
> +      StateOrVar.State = consumed::CS_None;<br>
> +    }<br>
> +<br>
> +    PropagationInfo(ConsumedState State) : IsVar(false) {<br>
> +      StateOrVar.State = State;<br>
> +    }<br>
> +<br>
> +    PropagationInfo(const VarDecl *Var) : IsVar(true) {<br>
> +      StateOrVar.Var = Var;<br>
> +    }<br>
> +<br>
> +    ConsumedState getState() { return StateOrVar.State; };<br>
> +<br>
> +    const VarDecl * getVar() { return IsVar ? StateOrVar.Var : NULL; };<br>
> +  };<br>
> +<br>
> +  typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;<br>
> +  typedef std::pair<const Stmt *, PropagationInfo> PairType;<br>
> +  typedef MapType::iterator InfoEntry;<br>
> +<br>
> +  ConsumedAnalyzer &Analyzer;<br>
> +  ConsumedStateMap *StateMap;<br>
> +  MapType PropagationMap;<br>
> +<br>
> +  void forwardInfo(const Stmt *From, const Stmt *To);<br>
> +  bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);<br>
> +<br>
> +public:<br>
> +<br>
> +  void Visit(const Stmt *StmtNode);<br>
> +<br>
> +  void VisitBinaryOperator(const BinaryOperator *BinOp);<br>
> +  void VisitCallExpr(const CallExpr *Call);<br>
> +  void VisitCastExpr(const CastExpr *Cast);<br>
> +  void VisitCXXConstructExpr(const CXXConstructExpr *Call);<br>
> +  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);<br>
> +  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);<br>
> +  void VisitDeclRefExpr(const DeclRefExpr *DeclRef);<br>
> +  void VisitDeclStmt(const DeclStmt *DelcS);<br>
> +  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);<br>
> +  void VisitMemberExpr(const MemberExpr *MExpr);<br>
> +  void VisitUnaryOperator(const UnaryOperator *UOp);<br>
> +  void VisitVarDecl(const VarDecl *Var);<br>
> +<br>
> +  ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap) :<br>
> +    Analyzer(Analyzer), StateMap(StateMap) {}<br>
> +<br>
> +  void reset() {<br>
> +    PropagationMap.clear();<br>
> +  }<br>
> +};<br>
> +<br>
> +void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {<br>
> +  InfoEntry Entry = PropagationMap.find(From);<br>
> +<br>
> +  if (Entry != PropagationMap.end()) {<br>
> +    PropagationMap.insert(PairType(To, PropagationInfo(Entry->second)));<br>
> +  }<br>
> +}<br>
> +<br>
> +bool ConsumedStmtVisitor::isLikeMoveAssignment(<br>
> +  const CXXMethodDecl *MethodDecl) {<br>
> +<br>
> +  return MethodDecl->isMoveAssignmentOperator() ||<br>
> +         (MethodDecl->getOverloadedOperator() == OO_Equal &&<br>
> +          MethodDecl->getNumParams() == 1 &&<br>
> +          MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {<br>
> +  switch (BinOp->getOpcode()) {<br>
> +  case BO_PtrMemD:<br>
> +  case BO_PtrMemI:<br>
> +    forwardInfo(BinOp->getLHS(), BinOp);<br>
> +    break;<br>
> +<br>
> +  default:<br>
> +    break;<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {<br>
> +  ConstStmtVisitor::Visit(StmtNode);<br>
> +<br>
> +  for (Stmt::const_child_iterator CI = StmtNode->child_begin(),<br>
> +       CE = StmtNode->child_end(); CI != CE; ++CI) {<br>
> +<br>
> +    PropagationMap.erase(*CI);<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {<br>
> +  if (const FunctionDecl *FunDecl =<br>
> +    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {<br>
> +<br>
> +    // Special case for the std::move function.<br>
> +    // TODO: Make this more specific. (Deferred)<br>
> +    if (FunDecl->getNameAsString() == "move") {<br>
> +      InfoEntry Entry = PropagationMap.find(Call->getArg(0));<br>
> +<br>
> +      if (Entry != PropagationMap.end()) {<br>
> +        PropagationMap.insert(PairType(Call, Entry->second));<br>
> +      }<br>
> +<br>
> +      return;<br>
> +    }<br>
> +<br>
> +    unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();<br>
> +<br>
> +    for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {<br>
> +      QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();<br>
> +<br>
> +      InfoEntry Entry = PropagationMap.find(Call->getArg(Index));<br>
> +<br>
> +      if (Entry == PropagationMap.end() || !Entry->second.IsVar) {<br>
> +        continue;<br>
> +      }<br>
> +<br>
> +      PropagationInfo PState = Entry->second;<br>
> +<br>
> +      if (ParamType->isRValueReferenceType() ||<br>
> +          (ParamType->isLValueReferenceType() &&<br>
> +           !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {<br>
> +<br>
> +        StateMap->setState(PState.getVar(), consumed::CS_Consumed);<br>
> +<br>
> +      } else if (!(ParamType.isConstQualified() ||<br>
> +                   ((ParamType->isReferenceType() ||<br>
> +                     ParamType->isPointerType()) &&<br>
> +                    ParamType->getPointeeType().isConstQualified()))) {<br>
> +<br>
> +        StateMap->setState(PState.getVar(), consumed::CS_Unknown);<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {<br>
> +  InfoEntry Entry = PropagationMap.find(Cast->getSubExpr());<br>
> +<br>
> +  if (Entry != PropagationMap.end())<br>
> +    PropagationMap.insert(PairType(Cast, Entry->second));<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {<br>
> +  CXXConstructorDecl *Constructor = Call->getConstructor();<br>
> +<br>
> +  ASTContext &CurrContext = Analyzer.getSema().getASTContext();<br>
> +  QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();<br>
> +<br>
> +  if (Analyzer.isConsumableType(ThisType)) {<br>
> +    if (Constructor->hasAttr<ConsumesAttr>() ||<br>
> +        Constructor->isDefaultConstructor()) {<br>
> +<br>
> +      PropagationMap.insert(PairType(Call,<br>
> +        PropagationInfo(consumed::CS_Consumed)));<br>
> +<br>
> +    } else if (Constructor->isMoveConstructor()) {<br>
> +<br>
> +      PropagationInfo PState =<br>
> +        PropagationMap.find(Call->getArg(0))->second;<br>
> +<br>
> +      if (PState.IsVar) {<br>
> +        const VarDecl* Var = PState.getVar();<br>
> +<br>
> +        PropagationMap.insert(PairType(Call,<br>
> +          PropagationInfo(StateMap->getState(Var))));<br>
> +<br>
> +        StateMap->setState(Var, consumed::CS_Consumed);<br>
> +<br>
> +      } else {<br>
> +        PropagationMap.insert(PairType(Call, PState));<br>
> +      }<br>
> +<br>
> +    } else if (Constructor->isCopyConstructor()) {<br>
> +      MapType::iterator Entry = PropagationMap.find(Call->getArg(0));<br>
> +<br>
> +      if (Entry != PropagationMap.end())<br>
> +        PropagationMap.insert(PairType(Call, Entry->second));<br>
> +<br>
> +    } else {<br>
> +      PropagationMap.insert(PairType(Call,<br>
> +        PropagationInfo(consumed::CS_Unconsumed)));<br>
> +    }<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitCXXMemberCallExpr(<br>
> +  const CXXMemberCallExpr *Call) {<br>
> +<br>
> +  VisitCallExpr(Call);<br>
> +<br>
> +  InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());<br>
> +<br>
> +  if (Entry != PropagationMap.end()) {<br>
> +    PropagationInfo PState = Entry->second;<br>
> +    if (!PState.IsVar) return;<br>
> +<br>
> +    const CXXMethodDecl *Method = Call->getMethodDecl();<br>
> +<br>
> +    if (Method->hasAttr<ConsumesAttr>())<br>
> +      StateMap->setState(PState.getVar(), consumed::CS_Consumed);<br>
> +    else if (!Method->isConst())<br>
> +      StateMap->setState(PState.getVar(), consumed::CS_Unknown);<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(<br>
> +  const CXXOperatorCallExpr *Call) {<br>
> +<br>
> +  const FunctionDecl *FunDecl =<br>
> +    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());<br>
> +<br>
> +  if (!FunDecl) return;<br>
> +<br>
> +  if (isa<CXXMethodDecl>(FunDecl) &&<br>
> +      isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {<br>
> +<br>
> +    InfoEntry LEntry = PropagationMap.find(Call->getArg(0));<br>
> +    InfoEntry REntry = PropagationMap.find(Call->getArg(1));<br>
> +<br>
> +    PropagationInfo LPState, RPState;<br>
> +<br>
> +    if (LEntry != PropagationMap.end() &&<br>
> +        REntry != PropagationMap.end()) {<br>
> +<br>
> +      LPState = LEntry->second;<br>
> +      RPState = REntry->second;<br>
> +<br>
> +      if (LPState.IsVar && RPState.IsVar) {<br>
> +        StateMap->setState(LPState.getVar(),<br>
> +          StateMap->getState(RPState.getVar()));<br>
> +<br>
> +        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);<br>
> +<br>
> +        PropagationMap.insert(PairType(Call, LPState));<br>
> +<br>
> +      } else if (LPState.IsVar && !RPState.IsVar) {<br>
> +        StateMap->setState(LPState.getVar(), RPState.getState());<br>
> +<br>
> +        PropagationMap.insert(PairType(Call, LPState));<br>
> +<br>
> +      } else if (!LPState.IsVar && RPState.IsVar) {<br>
> +        PropagationMap.insert(PairType(Call,<br>
> +          PropagationInfo(StateMap->getState(RPState.getVar()))));<br>
> +<br>
> +        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);<br>
> +<br>
> +      } else {<br>
> +        PropagationMap.insert(PairType(Call, RPState));<br>
> +      }<br>
> +<br>
> +    } else if (LEntry != PropagationMap.end() &&<br>
> +               REntry == PropagationMap.end()) {<br>
> +<br>
> +      LPState = LEntry->second;<br>
> +<br>
> +      if (LPState.IsVar) {<br>
> +        StateMap->setState(LPState.getVar(), consumed::CS_Unknown);<br>
> +<br>
> +        PropagationMap.insert(PairType(Call, LPState));<br>
> +<br>
> +      } else {<br>
> +        PropagationMap.insert(PairType(Call,<br>
> +          PropagationInfo(consumed::CS_Unknown)));<br>
> +      }<br>
> +<br>
> +    } else if (LEntry == PropagationMap.end() &&<br>
> +               REntry != PropagationMap.end()) {<br>
> +<br>
> +      RPState = REntry->second;<br>
> +<br>
> +      if (RPState.IsVar) {<br>
> +        const VarDecl *Var = RPState.getVar();<br>
> +<br>
> +        PropagationMap.insert(PairType(Call,<br>
> +          PropagationInfo(StateMap->getState(Var))));<br>
> +<br>
> +        StateMap->setState(Var, consumed::CS_Consumed);<br>
> +<br>
> +      } else {<br>
> +        PropagationMap.insert(PairType(Call, RPState));<br>
> +      }<br>
> +    }<br>
> +<br>
> +  } else {<br>
> +<br>
> +    VisitCallExpr(Call);<br>
> +<br>
> +    InfoEntry Entry = PropagationMap.find(Call->getArg(0));<br>
> +<br>
> +    if (Entry != PropagationMap.end()) {<br>
> +<br>
> +      PropagationInfo PState = Entry->second;<br>
> +<br>
> +      // TODO: When we support CallableWhenConsumed this will have to check for<br>
> +      //       the different attributes and change the behavior bellow.<br>
> +      //       (Deferred)<br>
> +      if (FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) {<br>
> +        if (PState.IsVar) {<br>
> +          const VarDecl *Var = PState.getVar();<br>
> +<br>
> +          switch (StateMap->getState(Var)) {<br>
> +          case CS_Consumed:<br>
> +            Analyzer.WarningsHandler.warnUseWhileConsumed(<br>
> +              FunDecl->getNameAsString(), Var->getNameAsString(),<br>
> +              Call->getExprLoc());<br>
> +            break;<br>
> +<br>
> +          case CS_Unknown:<br>
> +            Analyzer.WarningsHandler.warnUseInUnknownState(<br>
> +              FunDecl->getNameAsString(), Var->getNameAsString(),<br>
> +              Call->getExprLoc());<br>
> +            break;<br>
> +<br>
> +          default:<br>
> +            break;<br>
> +          }<br>
> +<br>
> +        } else {<br>
> +          switch (PState.getState()) {<br>
> +          case CS_Consumed:<br>
> +            Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(<br>
> +              FunDecl->getNameAsString(), Call->getExprLoc());<br>
> +            break;<br>
> +<br>
> +          case CS_Unknown:<br>
> +            Analyzer.WarningsHandler.warnUseOfTempInUnknownState(<br>
> +              FunDecl->getNameAsString(), Call->getExprLoc());<br>
> +            break;<br>
> +<br>
> +          default:<br>
> +            break;<br>
> +          }<br>
> +        }<br>
> +      }<br>
> +<br>
> +      // Handle non-constant member operators.<br>
> +      if (const CXXMethodDecl *MethodDecl =<br>
> +        dyn_cast_or_null<CXXMethodDecl>(FunDecl)) {<br>
> +<br>
> +        if (!MethodDecl->isConst() && PState.IsVar)<br>
> +          StateMap->setState(PState.getVar(), consumed::CS_Unknown);<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {<br>
> +  if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))<br>
> +    if (StateMap->getState(Var) != consumed::CS_None)<br>
> +      PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {<br>
> +  for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),<br>
> +       DE = DeclS->decl_end(); DI != DE; ++DI) {<br>
> +<br>
> +    if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));<br>
> +  }<br>
> +<br>
> +  if (DeclS->isSingleDecl())<br>
> +    if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))<br>
> +      PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(<br>
> +  const MaterializeTemporaryExpr *Temp) {<br>
> +<br>
> +  InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());<br>
> +<br>
> +  if (Entry != PropagationMap.end())<br>
> +    PropagationMap.insert(PairType(Temp, Entry->second));<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {<br>
> +  forwardInfo(MExpr->getBase(), MExpr);<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {<br>
> +  if (UOp->getOpcode() == UO_AddrOf) {<br>
> +    InfoEntry Entry = PropagationMap.find(UOp->getSubExpr());<br>
> +<br>
> +    if (Entry != PropagationMap.end())<br>
> +      PropagationMap.insert(PairType(UOp, Entry->second));<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {<br>
> +  if (Analyzer.isConsumableType(Var->getType())) {<br>
> +    PropagationInfo PState =<br>
> +      PropagationMap.find(Var->getInit())->second;<br>
> +<br>
> +    StateMap->setState(Var, PState.IsVar ?<br>
> +      StateMap->getState(PState.getVar()) : PState.getState());<br>
> +  }<br>
> +}<br>
> +} // end anonymous::ConsumedStmtVisitor<br>
> +<br>
> +namespace {<br>
> +<br>
> +// TODO: Handle variable definitions, e.g. bool valid = x.isValid();<br>
> +//       if (valid) ...; (Deferred)<br>
> +class TestedVarsVisitor : public RecursiveASTVisitor<TestedVarsVisitor> {<br>
> +<br>
> +  bool Invert;<br>
> +  SourceLocation CurrTestLoc;<br>
> +<br>
> +  ConsumedStateMap *StateMap;<br>
> +<br>
> +public:<br>
> +  bool IsUsefulConditional;<br>
> +  VarTestResult Test;<br>
> +<br>
> +  TestedVarsVisitor(ConsumedStateMap *StateMap) : Invert(false),<br>
> +    StateMap(StateMap), IsUsefulConditional(false) {}<br>
> +<br>
> +  bool VisitCallExpr(CallExpr *Call);<br>
> +  bool VisitDeclRefExpr(DeclRefExpr *DeclRef);<br>
> +  bool VisitUnaryOperator(UnaryOperator *UnaryOp);<br>
> +};<br>
> +<br>
> +bool TestedVarsVisitor::VisitCallExpr(CallExpr *Call) {<br>
> +  if (const CXXMethodDecl *Method =<br>
> +    dyn_cast_or_null<CXXMethodDecl>(Call->getDirectCallee())) {<br>
> +<br>
> +    if (isTestingFunction(Method)) {<br>
> +      CurrTestLoc = Call->getExprLoc();<br>
> +      IsUsefulConditional = true;<br>
> +      return true;<br>
> +    }<br>
> +<br>
> +    IsUsefulConditional = false;<br>
> +  }<br>
> +<br>
> +  return false;<br>
> +}<br>
> +<br>
> +bool TestedVarsVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {<br>
> +  if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) {<br>
> +    if (StateMap->getState(Var) != consumed::CS_None) {<br>
> +      Test = VarTestResult(Var, CurrTestLoc, !Invert);<br>
> +    }<br>
> +<br>
> +  } else {<br>
> +    IsUsefulConditional = false;<br>
> +  }<br>
> +<br>
> +  return IsUsefulConditional;<br>
> +}<br>
> +<br>
> +bool TestedVarsVisitor::VisitUnaryOperator(UnaryOperator *UnaryOp) {<br>
> +  if (UnaryOp->getOpcode() == UO_LNot) {<br>
> +    Invert = true;<br>
> +    TraverseStmt(UnaryOp->getSubExpr());<br>
> +<br>
> +  } else {<br>
> +    IsUsefulConditional = false;<br>
> +  }<br>
> +<br>
> +  return false;<br>
> +}<br>
> +} // end anonymouse::TestedVarsVisitor<br>
> +<br>
> +namespace clang {<br>
> +namespace consumed {<br>
> +<br>
> +void ConsumedBlockInfo::addInfo(const CFGBlock *Block,<br>
> +                                ConsumedStateMap *StateMap,<br>
> +                                bool &AlreadyOwned) {<br>
> +<br>
> +  if (VisitedBlocks.alreadySet(Block)) return;<br>
> +<br>
> +  ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];<br>
> +<br>
> +  if (Entry) {<br>
> +    Entry->intersect(StateMap);<br>
> +<br>
> +  } else if (AlreadyOwned) {<br>
> +    StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);<br>
> +<br>
> +  } else {<br>
> +    StateMapsArray[Block->getBlockID()] = StateMap;<br>
> +    AlreadyOwned = true;<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedBlockInfo::addInfo(const CFGBlock *Block,<br>
> +                                ConsumedStateMap *StateMap) {<br>
> +<br>
> +  if (VisitedBlocks.alreadySet(Block)) {<br>
> +    delete StateMap;<br>
> +    return;<br>
> +  }<br>
> +<br>
> +  ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];<br>
> +<br>
> +  if (Entry) {<br>
> +    Entry->intersect(StateMap);<br>
> +    delete StateMap;<br>
> +<br>
> +  } else {<br>
> +    StateMapsArray[Block->getBlockID()] = StateMap;<br>
> +  }<br>
> +}<br>
> +<br>
> +ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {<br>
> +  return StateMapsArray[Block->getBlockID()];<br>
> +}<br>
> +<br>
> +void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {<br>
> +  VisitedBlocks.insert(Block);<br>
> +}<br>
> +<br>
> +ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {<br>
> +  MapType::const_iterator Entry = Map.find(Var);<br>
> +<br>
> +  if (Entry != Map.end()) {<br>
> +    return Entry->second;<br>
> +<br>
> +  } else {<br>
> +    return CS_None;<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {<br>
> +  ConsumedState LocalState;<br>
> +<br>
> +  for (MapType::const_iterator DMI = Other->Map.begin(),<br>
> +       DME = Other->Map.end(); DMI != DME; ++DMI) {<br>
> +<br>
> +    LocalState = this->getState(DMI->first);<br>
> +<br>
> +    if (LocalState != CS_None && LocalState != DMI->second)<br>
> +      setState(DMI->first, CS_Unknown);<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStateMap::makeUnknown() {<br>
> +  PairType Pair;<br>
> +<br>
> +  for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;<br>
> +       ++DMI) {<br>
> +<br>
> +    Pair = *DMI;<br>
> +<br>
> +    Map.erase(Pair.first);<br>
> +    Map.insert(PairType(Pair.first, CS_Unknown));<br>
> +  }<br>
> +}<br>
> +<br>
> +void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {<br>
> +  Map[Var] = State;<br>
> +}<br>
> +<br>
> +const Sema & ConsumedAnalyzer::getSema() {<br>
> +  return S;<br>
> +}<br>
> +<br>
> +<br>
> +bool ConsumedAnalyzer::isConsumableType(QualType Type) {<br>
> +  const CXXRecordDecl *RD =<br>
> +    dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl());<br>
> +<br>
> +  if (!RD) return false;<br>
> +<br>
> +  std::pair<CacheMapType::iterator, bool> Entry =<br>
> +    ConsumableTypeCache.insert(std::make_pair(RD, false));<br>
> +<br>
> +  if (Entry.second)<br>
> +    Entry.first->second = hasConsumableAttributes(RD);<br>
> +<br>
> +  return Entry.first->second;<br>
> +}<br>
> +<br>
> +// TODO: Walk the base classes to see if any of them are unique types.<br>
> +//       (Deferred)<br>
> +bool ConsumedAnalyzer::hasConsumableAttributes(const CXXRecordDecl *RD) {<br>
> +  for (CXXRecordDecl::method_iterator MI = RD->method_begin(),<br>
> +       ME = RD->method_end(); MI != ME; ++MI) {<br>
> +<br>
> +    for (Decl::attr_iterator AI = (*MI)->attr_begin(), AE = (*MI)->attr_end();<br>
> +         AI != AE; ++AI) {<br>
> +<br>
> +      switch ((*AI)->getKind()) {<br>
> +      case attr::CallableWhenUnconsumed:<br>
> +      case attr::TestsUnconsumed:<br>
> +        return true;<br>
> +<br>
> +      default:<br>
> +        break;<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +<br>
> +  return false;<br>
> +}<br>
> +<br>
> +// TODO: Handle other forms of branching with precision, including while- and<br>
> +//       for-loops. (Deferred)<br>
> +void ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,<br>
> +                                  const IfStmt *Terminator) {<br>
> +<br>
> +  TestedVarsVisitor Visitor(CurrStates);<br>
> +  Visitor.TraverseStmt(const_cast<Expr*>(Terminator->getCond()));<br>
> +<br>
> +  bool HasElse = Terminator->getElse() != NULL;<br>
> +<br>
> +  ConsumedStateMap *ElseOrMergeStates = new ConsumedStateMap(*CurrStates);<br>
> +<br>
> +  if (Visitor.IsUsefulConditional) {<br>
> +    ConsumedState VarState = CurrStates->getState(Visitor.Test.Var);<br>
> +<br>
> +    if (VarState != CS_Unknown) {<br>
> +      // FIXME: Make this not warn if the test is from a macro expansion.<br>
> +      //        (Deferred)<br>
> +      WarningsHandler.warnUnnecessaryTest(Visitor.Test.Var->getNameAsString(),<br>
> +        stateToString(VarState), Visitor.Test.Loc);<br>
> +    }<br>
> +<br>
> +    if (Visitor.Test.UnconsumedInTrueBranch) {<br>
> +      CurrStates->setState(Visitor.Test.Var, CS_Unconsumed);<br>
> +      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Consumed);<br>
> +<br>
> +    } else {<br>
> +      CurrStates->setState(Visitor.Test.Var, CS_Consumed);<br>
> +      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Unconsumed);<br>
> +    }<br>
> +  }<br>
> +<br>
> +  CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();<br>
> +<br>
> +  if (*SI)   BlockInfo.addInfo(*SI,        CurrStates);<br>
> +  if (*++SI) BlockInfo.addInfo(*SI, ElseOrMergeStates);<br>
> +}<br>
> +<br>
> +void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {<br>
> +  const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());<br>
> +<br>
> +  if (!D) return;<br>
> +<br>
> +  BlockInfo = ConsumedBlockInfo(AC.getCFG());<br>
> +<br>
> +  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();<br>
> +<br>
> +  CurrStates = new ConsumedStateMap();<br>
> +<br>
> +  // Visit all of the function's basic blocks.<br>
> +  for (PostOrderCFGView::iterator I = SortedGraph->begin(),<br>
> +       E = SortedGraph->end(); I != E; ++I) {<br>
> +<br>
> +    const CFGBlock *CurrBlock = *I;<br>
> +    BlockInfo.markVisited(CurrBlock);<br>
> +<br>
> +    if (CurrStates == NULL)<br>
> +      CurrStates = BlockInfo.getInfo(CurrBlock);<br>
> +<br>
> +    ConsumedStmtVisitor Visitor(*this, CurrStates);<br>
> +<br>
> +    // Visit all of the basic block's statements.<br>
> +    for (CFGBlock::const_iterator BI = CurrBlock->begin(),<br>
> +         BE = CurrBlock->end(); BI != BE; ++BI) {<br>
> +<br>
> +      if (BI->getKind() == CFGElement::Statement)<br>
> +        Visitor.Visit(BI->castAs<CFGStmt>().getStmt());<br>
> +    }<br>
> +<br>
> +    // TODO: Remove any variables that have reached the end of their<br>
> +    //       lifetimes from the state map. (Deferred)<br>
> +<br>
> +    if (const IfStmt *Terminator =<br>
> +      dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {<br>
> +<br>
> +      splitState(CurrBlock, Terminator);<br>
> +      CurrStates = NULL;<br>
> +<br>
> +    } else if (CurrBlock->succ_size() > 1) {<br>
> +      CurrStates->makeUnknown();<br>
> +<br>
> +      bool OwnershipTaken = false;<br>
> +<br>
> +      for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),<br>
> +           SE = CurrBlock->succ_end(); SI != SE; ++SI) {<br>
> +<br>
> +        if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);<br>
> +      }<br>
> +<br>
> +      if (!OwnershipTaken)<br>
> +        delete CurrStates;<br>
> +<br>
> +      CurrStates = NULL;<br>
> +<br>
> +    } else if (CurrBlock->succ_size() == 1 &&<br>
> +               (*CurrBlock->succ_begin())->pred_size() > 1) {<br>
> +<br>
> +      BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);<br>
> +      CurrStates = NULL;<br>
> +    }<br>
> +<br>
> +    Visitor.reset();<br>
> +  } // End of block iterator.<br>
> +<br>
> +  // Delete the last existing state map.<br>
> +  delete CurrStates;<br>
> +<br>
> +  WarningsHandler.emitDiagnostics();<br>
> +}<br>
> +<br>
> +unsigned checkEnabled(DiagnosticsEngine &D) {<br>
> +  return (unsigned)<br>
> +    (D.getDiagnosticLevel(diag::warn_use_while_consumed, SourceLocation()) !=<br>
> +     DiagnosticsEngine::Ignored);<br>
> +}<br>
> +<br>
> +bool isTestingFunction(const CXXMethodDecl *Method) {<br>
> +  return Method->hasAttr<TestsUnconsumedAttr>();<br>
> +}<br>
> +<br>
> +}} // end namespace clang::consumed<br>
><br>
> Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -25,6 +25,7 @@<br>
>  #include "clang/AST/StmtObjC.h"<br>
>  #include "clang/AST/StmtVisitor.h"<br>
>  #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"<br>
> +#include "clang/Analysis/Analyses/Consumed.h"<br>
>  #include "clang/Analysis/Analyses/ReachableCode.h"<br>
>  #include "clang/Analysis/Analyses/ThreadSafety.h"<br>
>  #include "clang/Analysis/Analyses/UninitializedValues.h"<br>
> @@ -1241,12 +1242,8 @@ private:<br>
>  };<br>
>  }<br>
><br>
> -<br>
> -//===----------------------------------------------------------------------===//<br>
> -// -Wthread-safety<br>
> -//===----------------------------------------------------------------------===//<br>
>  namespace clang {<br>
> -namespace thread_safety {<br>
> +namespace {<br>
>  typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;<br>
>  typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;<br>
>  typedef std::list<DelayedDiag> DiagList;<br>
> @@ -1261,7 +1258,13 @@ struct SortDiagBySourceLocation {<br>
>      return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);<br>
>    }<br>
>  };<br>
> +}}<br>
><br>
> +//===----------------------------------------------------------------------===//<br>
> +// -Wthread-safety<br>
> +//===----------------------------------------------------------------------===//<br>
> +namespace clang {<br>
> +namespace thread_safety {<br>
>  namespace {<br>
>  class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {<br>
>    Sema &S;<br>
> @@ -1412,6 +1415,119 @@ class ThreadSafetyReporter : public clan<br>
>  }<br>
><br>
>  //===----------------------------------------------------------------------===//<br>
> +// -Wconsumed<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +namespace clang {<br>
> +namespace consumed {<br>
> +namespace {<br>
> +class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {<br>
> +<br>
> +  Sema &S;<br>
> +  DiagList Warnings;<br>
> +<br>
> +public:<br>
> +<br>
> +  ConsumedWarningsHandler(Sema &S) : S(S) {}<br>
> +<br>
> +  void emitDiagnostics() {<br>
> +    Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));<br>
> +<br>
> +    for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();<br>
> +         I != E; ++I) {<br>
> +<br>
> +      const OptionalNotes &Notes = I->second;<br>
> +      S.Diag(I->first.first, I->first.second);<br>
> +<br>
> +      for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI) {<br>
> +        S.Diag(Notes[NoteI].first, Notes[NoteI].second);<br>
> +      }<br>
> +    }<br>
> +  }<br>
> +<br>
> +  /// Warn about unnecessary-test errors.<br>
> +  /// \param VariableName -- The name of the variable that holds the unique<br>
> +  /// value.<br>
> +  ///<br>
> +  /// \param Loc -- The SourceLocation of the unnecessary test.<br>
> +  void warnUnnecessaryTest(StringRef VariableName, StringRef VariableState,<br>
> +                           SourceLocation Loc) {<br>
> +<br>
> +    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unnecessary_test) <<<br>
> +                                 VariableName << VariableState);<br>
> +<br>
> +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));<br>
> +  }<br>
> +<br>
> +  /// Warn about use-while-consumed errors.<br>
> +  /// \param MethodName -- The name of the method that was incorrectly<br>
> +  /// invoked.<br>
> +  ///<br>
> +  /// \param VariableName -- The name of the variable that holds the unique<br>
> +  /// value.<br>
> +  ///<br>
> +  /// \param Loc -- The SourceLocation of the method invocation.<br>
> +  void warnUseOfTempWhileConsumed(StringRef MethodName, SourceLocation Loc) {<br>
> +<br>
> +    PartialDiagnosticAt Warning(Loc, S.PDiag(<br>
> +      diag::warn_use_of_temp_while_consumed) << MethodName);<br>
> +<br>
> +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));<br>
> +  }<br>
> +<br>
> +  /// Warn about use-in-unknown-state errors.<br>
> +  /// \param MethodName -- The name of the method that was incorrectly<br>
> +  /// invoked.<br>
> +  ///<br>
> +  /// \param VariableName -- The name of the variable that holds the unique<br>
> +  /// value.<br>
> +  ///<br>
> +  /// \param Loc -- The SourceLocation of the method invocation.<br>
> +  void warnUseOfTempInUnknownState(StringRef MethodName, SourceLocation Loc) {<br>
> +<br>
> +    PartialDiagnosticAt Warning(Loc, S.PDiag(<br>
> +      diag::warn_use_of_temp_in_unknown_state) << MethodName);<br>
> +<br>
> +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));<br>
> +  }<br>
> +<br>
> +  /// Warn about use-while-consumed errors.<br>
> +  /// \param MethodName -- The name of the method that was incorrectly<br>
> +  /// invoked.<br>
> +  ///<br>
> +  /// \param VariableName -- The name of the variable that holds the unique<br>
> +  /// value.<br>
> +  ///<br>
> +  /// \param Loc -- The SourceLocation of the method invocation.<br>
> +  void warnUseWhileConsumed(StringRef MethodName, StringRef VariableName,<br>
> +                            SourceLocation Loc) {<br>
> +<br>
> +    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_while_consumed) <<<br>
> +                                MethodName << VariableName);<br>
> +<br>
> +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));<br>
> +  }<br>
> +<br>
> +  /// Warn about use-in-unknown-state errors.<br>
> +  /// \param MethodName -- The name of the method that was incorrectly<br>
> +  /// invoked.<br>
> +  ///<br>
> +  /// \param VariableName -- The name of the variable that holds the unique<br>
> +  /// value.<br>
> +  ///<br>
> +  /// \param Loc -- The SourceLocation of the method invocation.<br>
> +  void warnUseInUnknownState(StringRef MethodName, StringRef VariableName,<br>
> +                             SourceLocation Loc) {<br>
> +<br>
> +    PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_unknown_state) <<<br>
> +                                MethodName << VariableName);<br>
> +<br>
> +    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));<br>
> +  }<br>
> +};<br>
> +}}}<br>
> +<br>
> +//===----------------------------------------------------------------------===//<br>
>  // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based<br>
>  //  warnings on a function, method, or block.<br>
>  //===----------------------------------------------------------------------===//<br>
> @@ -1420,6 +1536,7 @@ clang::sema::AnalysisBasedWarnings::Poli<br>
>    enableCheckFallThrough = 1;<br>
>    enableCheckUnreachable = 0;<br>
>    enableThreadSafetyAnalysis = 0;<br>
> +  enableConsumedAnalysis = 0;<br>
>  }<br>
><br>
>  clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)<br>
> @@ -1440,6 +1557,7 @@ clang::sema::AnalysisBasedWarnings::Anal<br>
>    DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)<br>
>      (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=<br>
>       DiagnosticsEngine::Ignored);<br>
> +  DefaultPolicy.enableConsumedAnalysis = consumed::checkEnabled(D);<br>
><br>
>  }<br>
><br>
> @@ -1501,7 +1619,8 @@ AnalysisBasedWarnings::IssueWarnings(sem<br>
>    // prototyping, but we need a way for analyses to say what expressions they<br>
>    // expect to always be CFGElements and then fill in the BuildOptions<br>
>    // appropriately.  This is essentially a layering violation.<br>
> -  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {<br>
> +  if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||<br>
> +      P.enableConsumedAnalysis) {<br>
>      // Unreachable code analysis and thread safety require a linearized CFG.<br>
>      AC.getCFGBuildOptions().setAllAlwaysAdd();<br>
>    }<br>
> @@ -1605,6 +1724,13 @@ AnalysisBasedWarnings::IssueWarnings(sem<br>
>      Reporter.emitDiagnostics();<br>
>    }<br>
><br>
> +  // Check for violations of consumed properties.<br>
> +  if (P.enableConsumedAnalysis) {<br>
> +    consumed::ConsumedWarningsHandler WarningHandler(S);<br>
> +    consumed::ConsumedAnalyzer Analyzer(S, WarningHandler);<br>
> +    Analyzer.run(AC);<br>
> +  }<br>
> +<br>
>    if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())<br>
>        != DiagnosticsEngine::Ignored ||<br>
>        Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=188206&r1=188205&r2=188206&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=188206&r1=188205&r2=188206&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -997,6 +997,69 @@ static void handleLocksExcludedAttr(Sema<br>
>                                 Attr.getAttributeSpellingListIndex()));<br>
>  }<br>
><br>
> +static void handleConsumesAttr(Sema &S, Decl *D,<br>
> +                               const AttributeList &Attr) {<br>
> +  assert(!Attr.isInvalid());<br>
<br>
</div></div>The assert is superfluous here and elsewhere (see ProcessDeclAttribute<br>
where invalid attributes are early-returned).<br>
<div class="im"><br>
> +  if (!checkAttributeNumArgs(S, Attr, 0)) return;<br>
> +<br>
> +  if (!(isa<CXXMethodDecl>(D) || isa<CXXConstructorDecl>(D))) {<br>
> +    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<<br>
> +      Attr.getName();<br>
> +    return;<br>
> +  }<br>
<br>
</div>Please update the attribute's subjects to match the predicate.  Also,<br>
is this really only valid for C++ functions?  The given warning seems<br>
to imply non-instance methods are also acceptable targets.  If this<br>
really is for C++ only methods, ensure the warning is updated to have<br>
the proper wording.  This also applies elsewhere.<br>
<div class="HOEnZb"><div class="h5"><br>
> +<br>
> +  D->addAttr(::new (S.Context)<br>
> +             ConsumesAttr(Attr.getRange(), S.Context,<br>
> +              Attr.getAttributeSpellingListIndex()));<br>
> +}<br>
> +<br>
> +static void handleCallableWhenUnconsumedAttr(Sema &S, Decl *D,<br>
> +                                             const AttributeList &Attr) {<br>
> +  assert(!Attr.isInvalid());<br>
> +  if (!checkAttributeNumArgs(S, Attr, 0)) return;<br>
> +<br>
> +  if (!isa<CXXMethodDecl>(D)) {<br>
> +    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<<br>
> +      Attr.getName();<br>
> +    return;<br>
> +  }<br>
> +<br>
> +  D->addAttr(::new (S.Context)<br>
> +             CallableWhenUnconsumedAttr(Attr.getRange(), S.Context,<br>
> +              Attr.getAttributeSpellingListIndex()));<br>
> +}<br>
> +<br>
> +static void handleTestsConsumedAttr(Sema &S, Decl *D,<br>
> +                                    const AttributeList &Attr) {<br>
> +  assert(!Attr.isInvalid());<br>
> +  if (!checkAttributeNumArgs(S, Attr, 0)) return;<br>
> +<br>
> +  if (!isa<CXXMethodDecl>(D)) {<br>
> +    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<<br>
> +      Attr.getName();<br>
> +    return;<br>
> +  }<br>
> +<br>
> +  D->addAttr(::new (S.Context)<br>
> +             TestsConsumedAttr(Attr.getRange(), S.Context,<br>
> +              Attr.getAttributeSpellingListIndex()));<br>
> +}<br>
> +<br>
> +static void handleTestsUnconsumedAttr(Sema &S, Decl *D,<br>
> +                                      const AttributeList &Attr) {<br>
> +  assert(!Attr.isInvalid());<br>
> +  if (!checkAttributeNumArgs(S, Attr, 0)) return;<br>
> +<br>
> +  if (!isa<CXXMethodDecl>(D)) {<br>
> +    S.Diag(Attr.getLoc(), diag::warn_uniqueness_attribute_wrong_decl_type) <<<br>
> +      Attr.getName();<br>
> +    return;<br>
> +  }<br>
> +<br>
> +  D->addAttr(::new (S.Context)<br>
> +             TestsUnconsumedAttr(Attr.getRange(), S.Context,<br>
> +              Attr.getAttributeSpellingListIndex()));<br>
> +}<br>
><br>
>  static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,<br>
>                                      const AttributeList &Attr) {<br>
> @@ -4952,6 +5015,20 @@ static void ProcessInheritableDeclAttr(S<br>
>      handleAcquiredAfterAttr(S, D, Attr);<br>
>      break;<br>
><br>
> +  // Uniqueness analysis attributes.<br>
> +  case AttributeList::AT_Consumes:<br>
> +    handleConsumesAttr(S, D, Attr);<br>
> +    break;<br>
> +  case AttributeList::AT_CallableWhenUnconsumed:<br>
> +    handleCallableWhenUnconsumedAttr(S, D, Attr);<br>
> +    break;<br>
> +  case AttributeList::AT_TestsConsumed:<br>
> +    handleTestsConsumedAttr(S, D, Attr);<br>
> +    break;<br>
> +  case AttributeList::AT_TestsUnconsumed:<br>
> +    handleTestsUnconsumedAttr(S, D, Attr);<br>
> +    break;<br>
> +<br>
>    // Type safety attributes.<br>
>    case AttributeList::AT_ArgumentWithTypeTag:<br>
>      handleArgumentWithTypeTagAttr(S, D, Attr);<br>
><br>
> Added: cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp (added)<br>
> +++ cfe/trunk/test/SemaCXX/warn-consumed-analysis-strict.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,123 @@<br>
> +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed-strict -std=c++11 %s<br>
> +<br>
> +#define CALLABLE_WHEN_UNCONSUMED __attribute__ ((callable_when_unconsumed))<br>
> +#define CONSUMES __attribute__ ((consumes))<br>
> +#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed))<br>
> +<br>
> +typedef decltype(nullptr) nullptr_t;<br>
> +<br>
> +template <typename T><br>
> +class Bar {<br>
> +  T var;<br>
> +<br>
> +  public:<br>
> +  Bar(void);<br>
> +  Bar(T val);<br>
> +  Bar(Bar<T> &other);<br>
> +  Bar(Bar<T> &&other);<br>
> +<br>
> +  Bar<T>& operator=(Bar<T>  &other);<br>
> +  Bar<T>& operator=(Bar<T> &&other);<br>
> +  Bar<T>& operator=(nullptr_t);<br>
> +<br>
> +  template <typename U><br>
> +  Bar<T>& operator=(Bar<U>  &other);<br>
> +<br>
> +  template <typename U><br>
> +  Bar<T>& operator=(Bar<U> &&other);<br>
> +<br>
> +  void operator*(void) const CALLABLE_WHEN_UNCONSUMED;<br>
> +<br>
> +  bool isValid(void) const TESTS_UNCONSUMED;<br>
> +<br>
> +  void constCall(void) const;<br>
> +  void nonconstCall(void);<br>
> +<br>
> +  void consume(void) CONSUMES;<br>
> +};<br>
> +<br>
> +void baf0(Bar<int>  &var);<br>
> +void baf1(Bar<int>  *var);<br>
> +<br>
> +void testIfStmt(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  if (var.isValid()) { // expected-warning {{unnecessary test. Variable 'var' is known to be in the 'consumed' state}}<br>
> +<br>
> +    // Empty<br>
> +<br>
> +  } else {<br>
> +    // Empty<br>
> +  }<br>
> +}<br>
> +<br>
> +void testConditionalMerge(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  if (var.isValid()) {// expected-warning {{unnecessary test. Variable 'var' is known to be in the 'consumed' state}}<br>
> +<br>
> +    // Empty<br>
> +  }<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +<br>
> +  if (var.isValid()) {<br>
> +    // Empty<br>
> +<br>
> +  } else {<br>
> +    // Empty<br>
> +  }<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
> +<br>
> +void testCallingConventions(void) {<br>
> +  Bar<int> var(42);<br>
> +<br>
> +  baf0(var);<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +<br>
> +  var = Bar<int>(42);<br>
> +  baf1(&var);<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
> +<br>
> +void testMoveAsignmentish(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  var = nullptr;<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
> +<br>
> +void testConstAndNonConstMemberFunctions(void) {<br>
> +  Bar<int> var(42);<br>
> +<br>
> +  var.constCall();<br>
> +  *var;<br>
> +<br>
> +  var.nonconstCall();<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
> +<br>
> +void testSimpleForLoop(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  for (int i = 0; i < 10; ++i) {<br>
> +    *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +  }<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
> +<br>
> +void testSimpleWhileLoop(void) {<br>
> +  int i = 0;<br>
> +<br>
> +  Bar<int> var;<br>
> +<br>
> +  while (i < 10) {<br>
> +    *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +    ++i;<br>
> +  }<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}}<br>
> +}<br>
><br>
> Added: cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp (added)<br>
> +++ cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,188 @@<br>
> +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s<br>
> +<br>
> +#define CALLABLE_WHEN_UNCONSUMED __attribute__ ((callable_when_unconsumed))<br>
> +#define CONSUMES __attribute__ ((consumes))<br>
> +#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed))<br>
> +<br>
> +typedef decltype(nullptr) nullptr_t;<br>
> +<br>
> +template <typename T><br>
> +class Bar {<br>
> +  T var;<br>
> +<br>
> +  public:<br>
> +  Bar(void);<br>
> +  Bar(nullptr_t p) CONSUMES;<br>
> +  Bar(T val);<br>
> +  Bar(Bar<T> &other);<br>
> +  Bar(Bar<T> &&other);<br>
> +<br>
> +  Bar<T>& operator=(Bar<T>  &other);<br>
> +  Bar<T>& operator=(Bar<T> &&other);<br>
> +  Bar<T>& operator=(nullptr_t);<br>
> +<br>
> +  template <typename U><br>
> +  Bar<T>& operator=(Bar<U>  &other);<br>
> +<br>
> +  template <typename U><br>
> +  Bar<T>& operator=(Bar<U> &&other);<br>
> +<br>
> +  void operator*(void) const CALLABLE_WHEN_UNCONSUMED;<br>
> +<br>
> +  bool isValid(void) const TESTS_UNCONSUMED;<br>
> +  operator bool() const TESTS_UNCONSUMED;<br>
> +<br>
> +  void constCall(void) const;<br>
> +  void nonconstCall(void);<br>
> +<br>
> +  void consume(void) CONSUMES;<br>
> +};<br>
> +<br>
> +void baf0(const Bar<int>  var);<br>
> +void baf1(const Bar<int> &var);<br>
> +void baf2(const Bar<int> *var);<br>
> +<br>
> +void baf3(Bar<int> &&var);<br>
> +<br>
> +void testInitialization(void) {<br>
> +  Bar<int> var0;<br>
> +  Bar<int> var1 = Bar<int>();<br>
> +<br>
> +  var0 = Bar<int>();<br>
> +<br>
> +  *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}<br>
> +  *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}<br>
> +<br>
> +  if (var0.isValid()) {<br>
> +    *var0;<br>
> +    *var1;  // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}<br>
> +<br>
> +  } else {<br>
> +    *var0;  // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}<br>
> +  }<br>
> +}<br>
> +<br>
> +void testSimpleRValueRefs(void) {<br>
> +  Bar<int> var0;<br>
> +  Bar<int> var1(42);<br>
> +<br>
> +  *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}<br>
> +  *var1;<br>
> +<br>
> +  var0 = static_cast<Bar<int>&&>(var1);<br>
> +<br>
> +  *var0;<br>
> +  *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}<br>
> +}<br>
> +<br>
> +void testIfStmt(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  if (var.isValid()) {<br>
> +    // Empty<br>
> +<br>
> +  } else {<br>
> +    *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +  }<br>
> +<br>
> +  if (!var.isValid()) {<br>
> +    *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +<br>
> +  } else {<br>
> +    *var;<br>
> +  }<br>
> +<br>
> +  if (var) {<br>
> +    // Empty<br>
> +<br>
> +  } else {<br>
> +    *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +  }<br>
> +}<br>
> +<br>
> +void testCallingConventions(void) {<br>
> +  Bar<int> var(42);<br>
> +<br>
> +  baf0(var);<br>
> +  *var;<br>
> +<br>
> +  baf1(var);<br>
> +  *var;<br>
> +<br>
> +  baf2(&var);<br>
> +  *var;<br>
> +<br>
> +  baf3(static_cast<Bar<int>&&>(var));<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +}<br>
> +<br>
> +void testMoveAsignmentish(void) {<br>
> +  Bar<int>  var0;<br>
> +  Bar<long> var1(42);<br>
> +<br>
> +  *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}<br>
> +  *var1;<br>
> +<br>
> +  var0 = static_cast<Bar<long>&&>(var1);<br>
> +<br>
> +  *var0;<br>
> +  *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}<br>
> +}<br>
> +<br>
> +void testConditionalMerge(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  if (var.isValid()) {<br>
> +    // Empty<br>
> +  }<br>
> +<br>
> +  *var;<br>
> +<br>
> +  if (var.isValid()) {<br>
> +    // Empty<br>
> +<br>
> +  } else {<br>
> +    // Empty<br>
> +  }<br>
> +<br>
> +  *var;<br>
> +}<br>
> +<br>
> +void testConsumes0(void) {<br>
> +  Bar<int> var(42);<br>
> +<br>
> +  *var;<br>
> +<br>
> +  var.consume();<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +}<br>
> +<br>
> +void testConsumes1(void) {<br>
> +  Bar<int> var(nullptr);<br>
> +<br>
> +  *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}<br>
> +}<br>
> +<br>
> +void testSimpleForLoop(void) {<br>
> +  Bar<int> var;<br>
> +<br>
> +  for (int i = 0; i < 10; ++i) {<br>
> +    *var;<br>
> +  }<br>
> +<br>
> +  *var;<br>
> +}<br>
> +<br>
> +void testSimpleWhileLoop(void) {<br>
> +  int i = 0;<br>
> +<br>
> +  Bar<int> var;<br>
> +<br>
> +  while (i < 10) {<br>
> +    *var;<br>
> +    ++i;<br>
> +  }<br>
> +<br>
> +  *var;<br>
> +}<br>
><br>
> Added: cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp?rev=188206&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp?rev=188206&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp (added)<br>
> +++ cfe/trunk/test/SemaCXX/warn-consumed-parsing.cpp Mon Aug 12 16:20:55 2013<br>
> @@ -0,0 +1,29 @@<br>
> +// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s<br>
> +<br>
> +#define CONSUMES                  __attribute__ ((consumes))<br>
> +#define TESTS_UNCONSUMED          __attribute__ ((tests_unconsumed))<br>
> +#define CALLABLE_WHEN_UNCONSUMED  __attribute__ ((callable_when_unconsumed))<br>
> +<br>
> +class AttrTester0 {<br>
> +  void Consumes(void)        __attribute__ ((consumes(42))); // expected-error {{attribute takes no arguments}}<br>
> +  bool TestsUnconsumed(void) __attribute__ ((tests_unconsumed(42))); // expected-error {{attribute takes no arguments}}<br>
> +  void CallableWhenUnconsumed(void)<br>
> +    __attribute__ ((callable_when_unconsumed(42))); // expected-error {{attribute takes no arguments}}<br>
> +};<br>
> +<br>
> +int var0 CONSUMES; // expected-warning {{'consumes' attribute only applies to methods}}<br>
> +int var1 TESTS_UNCONSUMED; // expected-warning {{'tests_unconsumed' attribute only applies to methods}}<br>
> +int var2 CALLABLE_WHEN_UNCONSUMED; // expected-warning {{'callable_when_unconsumed' attribute only applies to methods}}<br>
> +<br>
> +void function0(void) CONSUMES; // expected-warning {{'consumes' attribute only applies to methods}}<br>
> +void function1(void) TESTS_UNCONSUMED; // expected-warning {{'tests_unconsumed' attribute only applies to methods}}<br>
> +void function2(void) CALLABLE_WHEN_UNCONSUMED; // expected-warning {{'callable_when_unconsumed' attribute only applies to methods}}<br>
> +<br>
> +class AttrTester1 {<br>
> +  void consumes(void)        CONSUMES;<br>
> +  bool testsUnconsumed(void) TESTS_UNCONSUMED;<br>
> +};<br>
> +<br>
> +class AttrTester2 {<br>
> +  void callableWhenUnconsumed(void) CALLABLE_WHEN_UNCONSUMED;<br>
> +};<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">~Aaron<br>
</font></span><div class="HOEnZb"><div class="h5">_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br></div>