r188206 - Patch by Chris Wailes <chris.wailes at gmail.com>.
Aaron Ballman
aaron at aaronballman.com
Thu Aug 15 17:58:41 PDT 2013
I agree, a separate patch would be beneficial (keeps the patches
on-point, too). If you submit it, I'll be happy to review.
Thanks!
~Aaron
On Tue, Aug 13, 2013 at 5:16 PM, Eric Christopher <echristo at gmail.com> wrote:
> 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