diff options
Diffstat (limited to 'include/clang/Analysis')
| -rw-r--r-- | include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h | 4 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/Consumed.h | 60 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/Dominators.h | 2 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 2 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/LiveVariables.h | 34 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/ReachableCode.h | 2 | ||||
| -rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafetyCommon.h | 2 | ||||
| -rw-r--r-- | include/clang/Analysis/AnalysisDeclContext.h | 12 | ||||
| -rw-r--r-- | include/clang/Analysis/CFG.h | 144 | ||||
| -rw-r--r-- | include/clang/Analysis/CFGStmtMap.h | 8 | ||||
| -rw-r--r-- | include/clang/Analysis/CloneDetection.h | 2 | ||||
| -rw-r--r-- | include/clang/Analysis/ConstructionContext.h | 265 | ||||
| -rw-r--r-- | include/clang/Analysis/DomainSpecific/CocoaConventions.h | 10 | ||||
| -rw-r--r-- | include/clang/Analysis/DomainSpecific/ObjCNoReturn.h | 4 | ||||
| -rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 28 | ||||
| -rw-r--r-- | include/clang/Analysis/Support/BumpVector.h | 52 |
16 files changed, 404 insertions, 227 deletions
diff --git a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h index da59514c4fa6..49da6815ace9 100644 --- a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h +++ b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h @@ -23,7 +23,7 @@ namespace clang { class CFG; class CFGBlock; - + // A class that performs reachability queries for CFGBlocks. Several internal // checks in this checker require reachability information. The requests all // tend to have a common destination, so we lazily do a predecessor search @@ -45,7 +45,7 @@ public: private: void mapReachability(const CFGBlock *Dst); }; - + } // namespace clang #endif // LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h index 6003d665fd88..5a70989e5087 100644 --- a/include/clang/Analysis/Analyses/Consumed.h +++ b/include/clang/Analysis/Analyses/Consumed.h @@ -38,18 +38,18 @@ class Stmt; class VarDecl; namespace consumed { - + class ConsumedStmtVisitor; enum ConsumedState { // No state information for the given variable. CS_None, - + CS_Unknown, CS_Unconsumed, CS_Consumed }; - + using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>; using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>; using DiagList = std::list<DelayedDiag>; @@ -60,7 +60,7 @@ namespace consumed { /// Emit the warnings and notes left by the analysis. virtual void emitDiagnostics() {} - + /// Warn that a variable's state doesn't match at the entry and exit /// of a loop. /// @@ -70,7 +70,7 @@ namespace consumed { /// state. virtual void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName) {} - + /// Warn about parameter typestate mismatches upon return. /// /// \param Loc -- The SourceLocation of the return statement. @@ -84,22 +84,22 @@ namespace consumed { StringRef VariableName, StringRef ExpectedState, StringRef ObservedState) {} - + // FIXME: Add documentation. virtual void warnParamTypestateMismatch(SourceLocation LOC, StringRef ExpectedState, StringRef ObservedState) {} - + // FIXME: This can be removed when the attr propagation fix for templated // classes lands. /// Warn about return typestates set for unconsumable types. - /// + /// /// \param Loc -- The location of the attributes. /// /// \param TypeName -- The name of the unconsumable type. virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName) {} - + /// Warn about return typestate mismatches. /// /// \param Loc -- The SourceLocation of the return statement. @@ -144,71 +144,71 @@ namespace consumed { using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>; using TmpMapType = llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>; - + protected: bool Reachable = true; const Stmt *From = nullptr; VarMapType VarMap; TmpMapType TmpMap; - + public: ConsumedStateMap() = default; ConsumedStateMap(const ConsumedStateMap &Other) : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), TmpMap() {} - + /// Warn if any of the parameters being tracked are not in the state /// they were declared to be in upon return from a function. void checkParamsForReturnTypestate(SourceLocation BlameLoc, ConsumedWarningsHandlerBase &WarningsHandler) const; - + /// Clear the TmpMap. void clearTemporaries(); - + /// Get the consumed state of a given variable. ConsumedState getState(const VarDecl *Var) const; - + /// Get the consumed state of a given temporary value. ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; - + /// Merge this state map with another map. void intersect(const ConsumedStateMap &Other); void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, ConsumedWarningsHandlerBase &WarningsHandler); - + /// Return true if this block is reachable. bool isReachable() const { return Reachable; } - + /// Mark the block as unreachable. void markUnreachable(); - + /// Set the source for a decision about the branching of states. /// \param Source -- The statement that was the origin of a branching /// decision. void setSource(const Stmt *Source) { this->From = Source; } - + /// Set the consumed state of a given variable. void setState(const VarDecl *Var, ConsumedState State); - + /// Set the consumed state of a given temporary value. void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); - + /// Remove the temporary value from our state map. void remove(const CXXBindTemporaryExpr *Tmp); - + /// Tests to see if there is a mismatch in the states stored in two /// maps. /// /// \param Other -- The second map to compare against. bool operator!=(const ConsumedStateMap *Other) const; }; - + class ConsumedBlockInfo { std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray; std::vector<unsigned int> VisitOrder; - + public: ConsumedBlockInfo() = default; @@ -218,7 +218,7 @@ namespace consumed { for (const auto BI : *SortedGraph) VisitOrder[BI->getBlockID()] = VisitOrderCounter++; } - + bool allBackEdgesVisited(const CFGBlock *CurrBlock, const CFGBlock *TargetBlock); @@ -228,7 +228,7 @@ namespace consumed { std::unique_ptr<ConsumedStateMap> StateMap); ConsumedStateMap* borrowInfo(const CFGBlock *Block); - + void discardInfo(const CFGBlock *Block); std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block); @@ -243,12 +243,12 @@ namespace consumed { std::unique_ptr<ConsumedStateMap> CurrStates; ConsumedState ExpectedReturnState; - + void determineExpectedReturnState(AnalysisDeclContext &AC, const FunctionDecl *D); bool splitState(const CFGBlock *CurrBlock, const ConsumedStmtVisitor &Visitor); - + public: ConsumedWarningsHandlerBase &WarningsHandler; @@ -256,7 +256,7 @@ namespace consumed { : WarningsHandler(WarningsHandler) {} ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } - + /// Check a function's CFG for consumed violations. /// /// We traverse the blocks in the CFG, keeping track of the state of each diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h index a9cdc5560bc0..021e98dcd885 100644 --- a/include/clang/Analysis/Analyses/Dominators.h +++ b/include/clang/Analysis/Analyses/Dominators.h @@ -20,7 +20,7 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/GenericDomTree.h" -#include "llvm/Support/GenericDomTreeConstruction.h" +#include "llvm/Support/GenericDomTreeConstruction.h" #include "llvm/Support/raw_ostream.h" // FIXME: There is no good reason for the domtree to require a print method diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 6f8bb9b4095f..598d341ac829 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -236,7 +236,7 @@ public: const char *toString() const; bool isPrintfKind() const { return IsPrintf; } - + Optional<ConversionSpecifier> getStandardSpecifier() const; protected: diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 21c3ba255c36..0cb500fffb95 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -25,7 +25,7 @@ class CFGBlock; class Stmt; class DeclRefExpr; class SourceManager; - + class LiveVariables : public ManagedAnalysis { public: class LivenessValues { @@ -34,7 +34,7 @@ public: llvm::ImmutableSet<const Stmt *> liveStmts; llvm::ImmutableSet<const VarDecl *> liveDecls; llvm::ImmutableSet<const BindingDecl *> liveBindings; - + bool equals(const LivenessValues &V) const; LivenessValues() @@ -48,21 +48,21 @@ public: bool isLive(const Stmt *S) const; bool isLive(const VarDecl *D) const; - - friend class LiveVariables; + + friend class LiveVariables; }; - + class Observer { virtual void anchor(); public: virtual ~Observer() {} - + /// A callback invoked right before invoking the /// liveness transfer function on the given statement. virtual void observeStmt(const Stmt *S, const CFGBlock *currentBlock, const LivenessValues& V) {} - + /// Called when the live variables analysis registers /// that a variable is killed. virtual void observerKill(const DeclRefExpr *DR) {} @@ -73,47 +73,47 @@ public: /// Compute the liveness information for a given CFG. static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext, bool killAtAssign); - + /// Return true if a variable is live at the end of a /// specified block. bool isLive(const CFGBlock *B, const VarDecl *D); - + /// Returns true if a variable is live at the beginning of the /// the statement. This query only works if liveness information /// has been recorded at the statement level (see runOnAllBlocks), and /// only returns liveness information for block-level expressions. bool isLive(const Stmt *S, const VarDecl *D); - + /// Returns true the block-level expression "value" is live /// before the given block-level expression (see runOnAllBlocks). bool isLive(const Stmt *Loc, const Stmt *StmtVal); - + /// Print to stderr the liveness information associated with /// each basic block. void dumpBlockLiveness(const SourceManager& M); void runOnAllBlocks(Observer &obs); - + static LiveVariables *create(AnalysisDeclContext &analysisContext) { return computeLiveness(analysisContext, true); } - + static const void *getTag(); - + private: LiveVariables(void *impl); void *impl; }; - + class RelaxedLiveVariables : public LiveVariables { public: static LiveVariables *create(AnalysisDeclContext &analysisContext) { return computeLiveness(analysisContext, false); } - + static const void *getTag(); }; - + } // end namespace clang #endif diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h index 4c523bfc8b56..d79f1b03df7b 100644 --- a/include/clang/Analysis/Analyses/ReachableCode.h +++ b/include/clang/Analysis/Analyses/ReachableCode.h @@ -57,7 +57,7 @@ public: }; /// ScanReachableFromBlock - Mark all blocks reachable from Start. -/// Returns the total number of blocks that were marked reachable. +/// Returns the total number of blocks that were marked reachable. unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable); diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 580872e17ef4..599c164923cb 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -500,7 +500,7 @@ private: std::vector<til::BasicBlock *> BlockMap; // Extra information per BB. Indexed by clang BlockID. - std::vector<BlockInfo> BBInfo; + std::vector<BlockInfo> BBInfo; LVarDefinitionMap CurrentLVarMap; std::vector<til::Phi *> CurrentArguments; diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h index 8c391b5ee1e5..19531d92e645 100644 --- a/include/clang/Analysis/AnalysisDeclContext.h +++ b/include/clang/Analysis/AnalysisDeclContext.h @@ -111,7 +111,7 @@ public: AnalysisDeclContextManager *getManager() const { return Manager; } - + /// Return the build options used to construct the CFG. CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; @@ -190,7 +190,7 @@ public: const Stmt *S, const CFGBlock *Blk, unsigned Idx); - + const BlockInvocationContext * getBlockInvocationContext(const LocationContext *parent, const BlockDecl *BD, @@ -359,7 +359,7 @@ class BlockInvocationContext : public LocationContext { friend class LocationContextManager; const BlockDecl *BD; - + // FIXME: Come up with a more type-safe way to model context-sensitivity. const void *ContextData; @@ -372,7 +372,7 @@ public: ~BlockInvocationContext() override = default; const BlockDecl *getBlockDecl() const { return BD; } - + const void *getContextData() const { return ContextData; } void Profile(llvm::FoldingSetNodeID &ID) override; @@ -403,7 +403,7 @@ public: const ScopeContext *getScope(AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s); - + const BlockInvocationContext * getBlockInvocationContext(AnalysisDeclContext *ctx, const LocationContext *parent, @@ -463,7 +463,7 @@ public: CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } - + /// Return true if faux bodies should be synthesized for well-known /// functions. bool synthesizeBodies() const { return SynthesizeBodies; } diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index f25789822d16..bf81d8358a54 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -15,9 +15,10 @@ #ifndef LLVM_CLANG_ANALYSIS_CFG_H #define LLVM_CLANG_ANALYSIS_CFG_H -#include "clang/AST/ExprCXX.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/Analysis/ConstructionContext.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" @@ -51,7 +52,7 @@ class FieldDecl; class LangOptions; class VarDecl; -/// CFGElement - Represents a top-level expression in a basic block. +/// Represents a top-level expression in a basic block. class CFGElement { public: enum Kind { @@ -144,9 +145,9 @@ protected: CFGStmt() = default; }; -/// CFGConstructor - Represents C++ constructor call. Maintains information -/// necessary to figure out what memory is being initialized by the -/// constructor expression. For now this is only used by the analyzer's CFG. +/// Represents C++ constructor call. Maintains information necessary to figure +/// out what memory is being initialized by the constructor expression. For now +/// this is only used by the analyzer's CFG. class CFGConstructor : public CFGStmt { public: explicit CFGConstructor(CXXConstructExpr *CE, const ConstructionContext *C) @@ -169,30 +170,34 @@ private: } }; -/// CFGCXXRecordTypedCall - Represents a function call that returns a C++ object -/// by value. This, like constructor, requires a construction context in order -/// to understand the storage of the returned object . In C such tracking is not -/// necessary because no additional effort is required for destroying the object -/// or modeling copy elision. Like CFGConstructor, this element is for now only -/// used by the analyzer's CFG. +/// Represents a function call that returns a C++ object by value. This, like +/// constructor, requires a construction context in order to understand the +/// storage of the returned object . In C such tracking is not necessary because +/// no additional effort is required for destroying the object or modeling copy +/// elision. Like CFGConstructor, this element is for now only used by the +/// analyzer's CFG. class CFGCXXRecordTypedCall : public CFGStmt { public: /// Returns true when call expression \p CE needs to be represented /// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt. - static bool isCXXRecordTypedCall(CallExpr *CE, const ASTContext &ACtx) { - return CE->getCallReturnType(ACtx).getCanonicalType()->getAsCXXRecordDecl(); + static bool isCXXRecordTypedCall(Expr *E) { + assert(isa<CallExpr>(E) || isa<ObjCMessageExpr>(E)); + // There is no such thing as reference-type expression. If the function + // returns a reference, it'll return the respective lvalue or xvalue + // instead, and we're only interested in objects. + return !E->isGLValue() && + E->getType().getCanonicalType()->getAsCXXRecordDecl(); } - explicit CFGCXXRecordTypedCall(CallExpr *CE, const ConstructionContext *C) - : CFGStmt(CE, CXXRecordTypedCall) { - // FIXME: This is not protected against squeezing a non-record-typed-call - // into the constructor. An assertion would require passing an ASTContext - // which would mean paying for something we don't use. + explicit CFGCXXRecordTypedCall(Expr *E, const ConstructionContext *C) + : CFGStmt(E, CXXRecordTypedCall) { + assert(isCXXRecordTypedCall(E)); assert(C && (isa<TemporaryObjectConstructionContext>(C) || // These are possible in C++17 due to mandatory copy elision. isa<ReturnedValueConstructionContext>(C) || isa<VariableConstructionContext>(C) || - isa<ConstructorInitializerConstructionContext>(C))); + isa<ConstructorInitializerConstructionContext>(C) || + isa<ArgumentConstructionContext>(C))); Data2.setPointer(const_cast<ConstructionContext *>(C)); } @@ -210,8 +215,8 @@ private: } }; -/// CFGInitializer - Represents C++ base or member initializer from -/// constructor's initialization list. +/// Represents C++ base or member initializer from constructor's initialization +/// list. class CFGInitializer : public CFGElement { public: explicit CFGInitializer(CXXCtorInitializer *initializer) @@ -231,7 +236,7 @@ private: } }; -/// CFGNewAllocator - Represents C++ allocator call. +/// Represents C++ allocator call. class CFGNewAllocator : public CFGElement { public: explicit CFGNewAllocator(const CXXNewExpr *S) @@ -349,8 +354,8 @@ private: } }; -/// CFGImplicitDtor - Represents C++ object destructor implicitly generated -/// by compiler on various occasions. +/// Represents C++ object destructor implicitly generated by compiler on various +/// occasions. class CFGImplicitDtor : public CFGElement { protected: CFGImplicitDtor() = default; @@ -373,9 +378,9 @@ private: } }; -/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated -/// for automatic object or temporary bound to const reference at the point -/// of leaving its local scope. +/// Represents C++ object destructor implicitly generated for automatic object +/// or temporary bound to const reference at the point of leaving its local +/// scope. class CFGAutomaticObjDtor: public CFGImplicitDtor { public: CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt) @@ -400,8 +405,7 @@ private: } }; -/// CFGDeleteDtor - Represents C++ object destructor generated -/// from a call to delete. +/// Represents C++ object destructor generated from a call to delete. class CFGDeleteDtor : public CFGImplicitDtor { public: CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE) @@ -426,8 +430,8 @@ private: } }; -/// CFGBaseDtor - Represents C++ object destructor implicitly generated for -/// base object in destructor. +/// Represents C++ object destructor implicitly generated for base object in +/// destructor. class CFGBaseDtor : public CFGImplicitDtor { public: CFGBaseDtor(const CXXBaseSpecifier *base) @@ -447,8 +451,8 @@ private: } }; -/// CFGMemberDtor - Represents C++ object destructor implicitly generated for -/// member object in destructor. +/// Represents C++ object destructor implicitly generated for member object in +/// destructor. class CFGMemberDtor : public CFGImplicitDtor { public: CFGMemberDtor(const FieldDecl *field) @@ -468,8 +472,8 @@ private: } }; -/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated -/// at the end of full expression for temporary object. +/// Represents C++ object destructor implicitly generated at the end of full +/// expression for temporary object. class CFGTemporaryDtor : public CFGImplicitDtor { public: CFGTemporaryDtor(CXXBindTemporaryExpr *expr) @@ -489,7 +493,7 @@ private: } }; -/// CFGTerminator - Represents CFGBlock terminator statement. +/// Represents CFGBlock terminator statement. /// /// TemporaryDtorsBranch bit is set to true if the terminator marks a branch /// in control flow of destructors of temporaries. In this case terminator @@ -520,7 +524,7 @@ public: explicit operator bool() const { return getStmt(); } }; -/// CFGBlock - Represents a single basic block in a source-level CFG. +/// Represents a single basic block in a source-level CFG. /// It consists of: /// /// (1) A set of statements/expressions (which may contain subexpressions). @@ -588,26 +592,24 @@ class CFGBlock { bool empty() const { return Impl.empty(); } }; - /// Stmts - The set of statements in the basic block. + /// The set of statements in the basic block. ElementList Elements; - /// Label - An (optional) label that prefixes the executable - /// statements in the block. When this variable is non-NULL, it is - /// either an instance of LabelStmt, SwitchCase or CXXCatchStmt. + /// An (optional) label that prefixes the executable statements in the block. + /// When this variable is non-NULL, it is either an instance of LabelStmt, + /// SwitchCase or CXXCatchStmt. Stmt *Label = nullptr; - /// Terminator - The terminator for a basic block that - /// indicates the type of control-flow that occurs between a block - /// and its successors. + /// The terminator for a basic block that indicates the type of control-flow + /// that occurs between a block and its successors. CFGTerminator Terminator; - /// LoopTarget - Some blocks are used to represent the "loop edge" to - /// the start of a loop from within the loop body. This Stmt* will be - /// refer to the loop statement for such blocks (and be null otherwise). + /// Some blocks are used to represent the "loop edge" to the start of a loop + /// from within the loop body. This Stmt* will be refer to the loop statement + /// for such blocks (and be null otherwise). const Stmt *LoopTarget = nullptr; - /// BlockID - A numerical ID assigned to a CFGBlock during construction - /// of the CFG. + /// A numerical ID assigned to a CFGBlock during construction of the CFG. unsigned BlockID; public: @@ -629,7 +631,7 @@ public: public: /// Construct an AdjacentBlock with a possibly unreachable block. AdjacentBlock(CFGBlock *B, bool IsReachable); - + /// Construct an AdjacentBlock with a reachable block and an alternate /// unreachable block. AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock); @@ -665,13 +667,12 @@ public: }; private: - /// Predecessors/Successors - Keep track of the predecessor / successor - /// CFG blocks. + /// Keep track of the predecessor / successor CFG blocks. using AdjacentBlocks = BumpVector<AdjacentBlock>; AdjacentBlocks Preds; AdjacentBlocks Succs; - /// NoReturn - This bit is set when the basic block contains a function call + /// This bit is set when the basic block contains a function call /// or implicit destructor that is attributed as 'noreturn'. In that case, /// control cannot technically ever proceed past this block. All such blocks /// will have a single immediate successor: the exit block. This allows them @@ -682,7 +683,7 @@ private: /// storage if the memory usage of CFGBlock becomes an issue. unsigned HasNoReturnElement : 1; - /// Parent - The parent CFG that owns this CFGBlock. + /// The parent CFG that owns this CFGBlock. CFG *Parent; public: @@ -878,10 +879,10 @@ public: Elements.push_back(CFGConstructor(CE, CC), C); } - void appendCXXRecordTypedCall(CallExpr *CE, + void appendCXXRecordTypedCall(Expr *E, const ConstructionContext *CC, BumpVectorContext &C) { - Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C); + Elements.push_back(CFGCXXRecordTypedCall(E, CC), C); } void appendInitializer(CXXCtorInitializer *initializer, @@ -992,7 +993,7 @@ public: bool isAlwaysTrue) {} }; -/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// Represents a source-level, intra-procedural CFG that represents the /// control-flow of a Stmt. The Stmt can represent an entire function body, /// or a single expression. A CFG will always contain one empty block that /// represents the Exit point of the CFG. A CFG will also contain a designated @@ -1044,21 +1045,21 @@ public: } }; - /// buildCFG - Builds a CFG from an AST. + /// Builds a CFG from an AST. static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C, const BuildOptions &BO); - /// createBlock - Create a new block in the CFG. The CFG owns the block; - /// the caller should not directly free it. + /// Create a new block in the CFG. The CFG owns the block; the caller should + /// not directly free it. CFGBlock *createBlock(); - /// setEntry - Set the entry block of the CFG. This is typically used - /// only during CFG construction. Most CFG clients expect that the - /// entry block has no predecessors and contains no statements. + /// Set the entry block of the CFG. This is typically used only during CFG + /// construction. Most CFG clients expect that the entry block has no + /// predecessors and contains no statements. void setEntry(CFGBlock *B) { Entry = B; } - /// setIndirectGotoBlock - Set the block used for indirect goto jumps. - /// This is typically used only during CFG construction. + /// Set the block used for indirect goto jumps. This is typically used only + /// during CFG construction. void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; } //===--------------------------------------------------------------------===// @@ -1152,8 +1153,8 @@ public: template <typename CALLBACK> void VisitBlockStmts(CALLBACK& O) const { - for (const_iterator I=begin(), E=end(); I != E; ++I) - for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); + for (const_iterator I = begin(), E = end(); I != E; ++I) + for (CFGBlock::const_iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) { if (Optional<CFGStmt> stmt = BI->getAs<CFGStmt>()) O(const_cast<Stmt*>(stmt->getStmt())); @@ -1164,13 +1165,12 @@ public: // CFG Introspection. //===--------------------------------------------------------------------===// - /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which - /// start at 0). + /// Returns the total number of BlockIDs allocated (which start at 0). unsigned getNumBlockIDs() const { return NumBlockIDs; } - /// size - Return the total number of CFGBlocks within the CFG - /// This is simply a renaming of the getNumBlockIDs(). This is necessary - /// because the dominator implementation needs such an interface. + /// Return the total number of CFGBlocks within the CFG This is simply a + /// renaming of the getNumBlockIDs(). This is necessary because the dominator + /// implementation needs such an interface. unsigned size() const { return NumBlockIDs; } //===--------------------------------------------------------------------===// diff --git a/include/clang/Analysis/CFGStmtMap.h b/include/clang/Analysis/CFGStmtMap.h index 4dfa91df0f42..78e637daf379 100644 --- a/include/clang/Analysis/CFGStmtMap.h +++ b/include/clang/Analysis/CFGStmtMap.h @@ -19,20 +19,18 @@ namespace clang { -class CFG; -class CFGBlock; class ParentMap; class Stmt; class CFGStmtMap { ParentMap *PM; void *M; - + CFGStmtMap(ParentMap *pm, void *m) : PM(pm), M(m) {} - + public: ~CFGStmtMap(); - + /// Returns a new CFGMap for the given CFG. It is the caller's /// responsibility to 'delete' this object when done using it. static CFGStmtMap *Build(CFG* C, ParentMap *PM); diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h index 955777a11a65..915ec58a5144 100644 --- a/include/clang/Analysis/CloneDetection.h +++ b/include/clang/Analysis/CloneDetection.h @@ -332,7 +332,7 @@ struct FilenamePatternConstraint { StringRef IgnoredFilesPattern; std::shared_ptr<llvm::Regex> IgnoredFilesRegex; - FilenamePatternConstraint(StringRef IgnoredFilesPattern) + FilenamePatternConstraint(StringRef IgnoredFilesPattern) : IgnoredFilesPattern(IgnoredFilesPattern) { IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" + IgnoredFilesPattern.str() + "$)"); diff --git a/include/clang/Analysis/ConstructionContext.h b/include/clang/Analysis/ConstructionContext.h index 40cb0e7e5dda..aee67865df25 100644 --- a/include/clang/Analysis/ConstructionContext.h +++ b/include/clang/Analysis/ConstructionContext.h @@ -22,66 +22,201 @@ namespace clang { -/// Construction context is a linked list of multiple layers. Layers are -/// created gradually while traversing the AST, and layers that represent -/// the outmost AST nodes are built first, while the node that immediately -/// contains the constructor would be built last and capture the previous -/// layers as its parents. Construction context captures the last layer -/// (which has links to the previous layers) and classifies the seemingly -/// arbitrary chain of layers into one of the possible ways of constructing -/// an object in C++ for user-friendly experience. -class ConstructionContextLayer { +/// Represents a single point (AST node) in the program that requires attention +/// during construction of an object. ConstructionContext would be represented +/// as a list of such items. +class ConstructionContextItem { public: - typedef llvm::PointerUnion<Stmt *, CXXCtorInitializer *> TriggerTy; + enum ItemKind { + VariableKind, + NewAllocatorKind, + ReturnKind, + MaterializationKind, + TemporaryDestructorKind, + ElidedDestructorKind, + ElidableConstructorKind, + ArgumentKind, + STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind, + STATEMENT_WITH_INDEX_KIND_END=ArgumentKind, + STATEMENT_KIND_BEGIN = VariableKind, + STATEMENT_KIND_END = ArgumentKind, + InitializerKind, + INITIALIZER_KIND_BEGIN=InitializerKind, + INITIALIZER_KIND_END=InitializerKind + }; + + LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) { + switch (K) { + case VariableKind: return "construct into local variable"; + case NewAllocatorKind: return "construct into new-allocator"; + case ReturnKind: return "construct into return address"; + case MaterializationKind: return "materialize temporary"; + case TemporaryDestructorKind: return "destroy temporary"; + case ElidedDestructorKind: return "elide destructor"; + case ElidableConstructorKind: return "elide constructor"; + case ArgumentKind: return "construct into argument"; + case InitializerKind: return "construct into member variable"; + }; + llvm_unreachable("Unknown ItemKind"); + } private: + const void *const Data; + const ItemKind Kind; + const unsigned Index = 0; + + bool hasStatement() const { + return Kind >= STATEMENT_KIND_BEGIN && + Kind <= STATEMENT_KIND_END; + } + + bool hasIndex() const { + return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN && + Kind >= STATEMENT_WITH_INDEX_KIND_END; + } + + bool hasInitializer() const { + return Kind >= INITIALIZER_KIND_BEGIN && + Kind <= INITIALIZER_KIND_END; + } + +public: + // ConstructionContextItem should be simple enough so that it was easy to + // re-construct it from the AST node it captures. For that reason we provide + // simple implicit conversions from all sorts of supported AST nodes. + ConstructionContextItem(const DeclStmt *DS) + : Data(DS), Kind(VariableKind) {} + + ConstructionContextItem(const CXXNewExpr *NE) + : Data(NE), Kind(NewAllocatorKind) {} + + ConstructionContextItem(const ReturnStmt *RS) + : Data(RS), Kind(ReturnKind) {} + + ConstructionContextItem(const MaterializeTemporaryExpr *MTE) + : Data(MTE), Kind(MaterializationKind) {} + + ConstructionContextItem(const CXXBindTemporaryExpr *BTE, + bool IsElided = false) + : Data(BTE), + Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {} + + ConstructionContextItem(const CXXConstructExpr *CE) + : Data(CE), Kind(ElidableConstructorKind) {} + + ConstructionContextItem(const CallExpr *CE, unsigned Index) + : Data(CE), Kind(ArgumentKind), Index(Index) {} + + ConstructionContextItem(const CXXConstructExpr *CE, unsigned Index) + : Data(CE), Kind(ArgumentKind), Index(Index) {} + + ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index) + : Data(ME), Kind(ArgumentKind), Index(Index) {} + + // A polymorphic version of the previous calls with dynamic type check. + ConstructionContextItem(const Expr *E, unsigned Index) + : Data(E), Kind(ArgumentKind), Index(Index) { + assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || + isa<ObjCMessageExpr>(E)); + } + + ConstructionContextItem(const CXXCtorInitializer *Init) + : Data(Init), Kind(InitializerKind), Index(0) {} + + ItemKind getKind() const { return Kind; } + + LLVM_DUMP_METHOD StringRef getKindAsString() const { + return getKindAsString(getKind()); + } + /// The construction site - the statement that triggered the construction /// for one of its parts. For instance, stack variable declaration statement /// triggers construction of itself or its elements if it's an array, /// new-expression triggers construction of the newly allocated object(s). - TriggerTy Trigger; + const Stmt *getStmt() const { + assert(hasStatement()); + return static_cast<const Stmt *>(Data); + } + + const Stmt *getStmtOrNull() const { + return hasStatement() ? getStmt() : nullptr; + } + + /// The construction site is not necessarily a statement. It may also be a + /// CXXCtorInitializer, which means that a member variable is being + /// constructed during initialization of the object that contains it. + const CXXCtorInitializer *getCXXCtorInitializer() const { + assert(hasInitializer()); + return static_cast<const CXXCtorInitializer *>(Data); + } - /// Sometimes a single trigger is not enough to describe the construction - /// site. In this case we'd have a chain of "partial" construction context - /// layers. - /// Some examples: - /// - A constructor within in an aggregate initializer list within a variable - /// would have a construction context of the initializer list with - /// the parent construction context of a variable. - /// - A constructor for a temporary that needs to be both destroyed - /// and materialized into an elidable copy constructor would have a - /// construction context of a CXXBindTemporaryExpr with the parent - /// construction context of a MaterializeTemproraryExpr. - /// Not all of these are currently supported. + /// If a single trigger statement triggers multiple constructors, they are + /// usually being enumerated. This covers function argument constructors + /// triggered by a call-expression and items in an initializer list triggered + /// by an init-list-expression. + unsigned getIndex() const { + // This is a fairly specific request. Let's make sure the user knows + // what he's doing. + assert(hasIndex()); + return Index; + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Data); + ID.AddInteger(Kind); + ID.AddInteger(Index); + } + + bool operator==(const ConstructionContextItem &Other) const { + // For most kinds the Index comparison is trivially true, but + // checking kind separately doesn't seem to be less expensive + // than checking Index. Same in operator<(). + return std::make_tuple(Data, Kind, Index) == + std::make_tuple(Other.Data, Other.Kind, Other.Index); + } + + bool operator<(const ConstructionContextItem &Other) const { + return std::make_tuple(Data, Kind, Index) < + std::make_tuple(Other.Data, Other.Kind, Other.Index); + } +}; + +/// Construction context can be seen as a linked list of multiple layers. +/// Sometimes a single trigger is not enough to describe the construction +/// site. That's what causing us to have a chain of "partial" construction +/// context layers. Some examples: +/// - A constructor within in an aggregate initializer list within a variable +/// would have a construction context of the initializer list with +/// the parent construction context of a variable. +/// - A constructor for a temporary that needs to be both destroyed +/// and materialized into an elidable copy constructor would have a +/// construction context of a CXXBindTemporaryExpr with the parent +/// construction context of a MaterializeTemproraryExpr. +/// Not all of these are currently supported. +/// Layers are created gradually while traversing the AST, and layers that +/// represent the outmost AST nodes are built first, while the node that +/// immediately contains the constructor would be built last and capture the +/// previous layers as its parents. Construction context captures the last layer +/// (which has links to the previous layers) and classifies the seemingly +/// arbitrary chain of layers into one of the possible ways of constructing +/// an object in C++ for user-friendly experience. +class ConstructionContextLayer { const ConstructionContextLayer *Parent = nullptr; + ConstructionContextItem Item; - ConstructionContextLayer(TriggerTy Trigger, - const ConstructionContextLayer *Parent) - : Trigger(Trigger), Parent(Parent) {} + ConstructionContextLayer(ConstructionContextItem Item, + const ConstructionContextLayer *Parent) + : Parent(Parent), Item(Item) {} public: static const ConstructionContextLayer * - create(BumpVectorContext &C, TriggerTy Trigger, + create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent = nullptr); + const ConstructionContextItem &getItem() const { return Item; } const ConstructionContextLayer *getParent() const { return Parent; } bool isLast() const { return !Parent; } - const Stmt *getTriggerStmt() const { - return Trigger.dyn_cast<Stmt *>(); - } - - const CXXCtorInitializer *getTriggerInit() const { - return Trigger.dyn_cast<CXXCtorInitializer *>(); - } - - /// Returns true if these layers are equal as individual layers, even if - /// their parents are different. - bool isSameLayer(const ConstructionContextLayer *Other) const { - assert(Other); - return (Trigger == Other->Trigger); - } - /// See if Other is a proper initial segment of this construction context /// in terms of the parent chain - i.e. a few first parents coincide and /// then the other context terminates but our context goes further - i.e., @@ -114,7 +249,8 @@ public: SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind, RETURNED_VALUE_BEGIN = SimpleReturnedValueKind, - RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind + RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind, + ArgumentKind }; protected: @@ -132,6 +268,23 @@ private: return new (CC) T(Args...); } + // A sub-routine of createFromLayers() that deals with temporary objects + // that need to be materialized. The BTE argument is for the situation when + // the object also needs to be bound for destruction. + static const ConstructionContext *createMaterializedTemporaryFromLayers( + BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, + const CXXBindTemporaryExpr *BTE, + const ConstructionContextLayer *ParentLayer); + + // A sub-routine of createFromLayers() that deals with temporary objects + // that need to be bound for destruction. Automatically finds out if the + // object also needs to be materialized and delegates to + // createMaterializedTemporaryFromLayers() if necessary. + static const ConstructionContext * + createBoundTemporaryFromLayers( + BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, + const ConstructionContextLayer *ParentLayer); + public: /// Consume the construction context layer, together with its parent layers, /// and wrap it up into a complete construction context. May return null @@ -469,6 +622,32 @@ public: } }; +class ArgumentConstructionContext : public ConstructionContext { + const Expr *CE; // The call of which the context is an argument. + unsigned Index; // Which argument we're constructing. + const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed. + + friend class ConstructionContext; // Allows to create<>() itself. + + explicit ArgumentConstructionContext(const Expr *CE, unsigned Index, + const CXXBindTemporaryExpr *BTE) + : ConstructionContext(ArgumentKind), CE(CE), + Index(Index), BTE(BTE) { + assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) || + isa<ObjCMessageExpr>(CE)); + // BTE is optional. + } + +public: + const Expr *getCallLikeExpr() const { return CE; } + unsigned getIndex() const { return Index; } + const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } + + static bool classof(const ConstructionContext *CC) { + return CC->getKind() == ArgumentKind; + } +}; + } // end namespace clang #endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index 8b3fcff52d08..9326d1abbac1 100644 --- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements cocoa naming convention analysis. +// This file implements cocoa naming convention analysis. // //===----------------------------------------------------------------------===// @@ -20,20 +20,20 @@ namespace clang { class FunctionDecl; class QualType; - + namespace ento { namespace cocoa { - + bool isRefType(QualType RetTy, StringRef Prefix, StringRef Name = StringRef()); - + bool isCocoaObjectRef(QualType T); } namespace coreFoundation { bool isCFObjectRef(QualType T); - + bool followsCreateRule(const FunctionDecl *FD); } diff --git a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h index f9e800a4a412..e304d83615d4 100644 --- a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h +++ b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h @@ -21,7 +21,7 @@ namespace clang { class ASTContext; class ObjCMessageExpr; - + class ObjCNoReturn { /// Cached "raise" selector. Selector RaiseSel; @@ -36,7 +36,7 @@ class ObjCNoReturn { public: ObjCNoReturn(ASTContext &C); - + /// Return true if the given message expression is known to never /// return. bool isImplicitNoReturn(const ObjCMessageExpr *ME); diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index e8f0d61617eb..25ae93fae6b8 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -33,7 +33,7 @@ namespace clang { class AnalysisDeclContext; class FunctionDecl; class LocationContext; - + /// ProgramPoints can be "tagged" as representing points specific to a given /// analysis entity. Tags are abstract annotations, with an associated /// description and potentially other information. @@ -41,12 +41,12 @@ class ProgramPointTag { public: ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} virtual ~ProgramPointTag(); - virtual StringRef getTagDescription() const = 0; + virtual StringRef getTagDescription() const = 0; protected: /// Used to implement 'isKind' in subclasses. const void *getTagKind() { return TagKind; } - + private: const void *TagKind; }; @@ -111,7 +111,7 @@ protected: assert(getLocationContext() == l); assert(getData1() == P); } - + ProgramPoint(const void *P1, const void *P2, Kind k, @@ -223,7 +223,7 @@ class BlockEntrance : public ProgramPoint { public: BlockEntrance(const CFGBlock *B, const LocationContext *L, const ProgramPointTag *tag = nullptr) - : ProgramPoint(B, BlockEntranceKind, L, tag) { + : ProgramPoint(B, BlockEntranceKind, L, tag) { assert(B && "BlockEntrance requires non-null block"); } @@ -235,7 +235,7 @@ public: const CFGBlock *B = getBlock(); return B->empty() ? Optional<CFGElement>() : B->front(); } - + private: friend class ProgramPoint; BlockEntrance() = default; @@ -350,7 +350,7 @@ protected: LocationCheck(const Stmt *S, const LocationContext *L, ProgramPoint::Kind K, const ProgramPointTag *tag) : StmtPoint(S, nullptr, K, L, tag) {} - + private: friend class ProgramPoint; static bool isKind(const ProgramPoint &location) { @@ -358,13 +358,13 @@ private: return k == PreLoadKind || k == PreStoreKind; } }; - + class PreLoad : public LocationCheck { public: PreLoad(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag = nullptr) : LocationCheck(S, L, PreLoadKind, tag) {} - + private: friend class ProgramPoint; PreLoad() = default; @@ -378,7 +378,7 @@ public: PreStore(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag = nullptr) : LocationCheck(S, L, PreStoreKind, tag) {} - + private: friend class ProgramPoint; PreStore() = default; @@ -405,7 +405,7 @@ private: class PostStore : public PostStmt { public: /// Construct the post store point. - /// \param Loc can be used to store the information about the location + /// \param Loc can be used to store the information about the location /// used in the form it was uttered in the code. PostStore(const Stmt *S, const LocationContext *L, const void *Loc, const ProgramPointTag *tag = nullptr) @@ -479,7 +479,7 @@ public: BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) : ProgramPoint(B1, B2, BlockEdgeKind, L) { assert(B1 && "BlockEdge: source block must be non-null"); - assert(B2 && "BlockEdge: destination block must be non-null"); + assert(B2 && "BlockEdge: destination block must be non-null"); } const CFGBlock *getSrc() const { @@ -603,7 +603,7 @@ private: /// CallEnter uses the caller's location context. class CallEnter : public ProgramPoint { public: - CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, + CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, const LocationContext *callerCtx) : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {} @@ -749,7 +749,7 @@ static bool isEqual(const clang::ProgramPoint &L, } }; - + template <> struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index 5940520855ef..00a7417e20f9 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -29,7 +29,7 @@ #include <type_traits> namespace clang { - + class BumpVectorContext { llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc; @@ -47,15 +47,15 @@ public: /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the /// BumpVectorContext object is destroyed. BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {} - + ~BumpVectorContext() { if (Alloc.getInt()) delete Alloc.getPointer(); } - + llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); } }; - + template<typename T> class BumpVector { T *Begin = nullptr; @@ -67,34 +67,34 @@ public: explicit BumpVector(BumpVectorContext &C, unsigned N) { reserve(C, N); } - + ~BumpVector() { if (std::is_class<T>::value) { // Destroy the constructed elements in the vector. destroy_range(Begin, End); } } - + using size_type = size_t; using difference_type = ptrdiff_t; using value_type = T; using iterator = T *; using const_iterator = const T *; - + using const_reverse_iterator = std::reverse_iterator<const_iterator>; using reverse_iterator = std::reverse_iterator<iterator>; - + using reference = T &; using const_reference = const T &; using pointer = T *; using const_pointer = const T *; - + // forward iterator creation methods. iterator begin() { return Begin; } const_iterator begin() const { return Begin; } iterator end() { return End; } const_iterator end() const { return End; } - + // reverse iterator creation methods. reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } @@ -102,7 +102,7 @@ public: const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - + bool empty() const { return Begin == End; } size_type size() const { return End-Begin; } @@ -114,49 +114,49 @@ public: assert(Begin + idx < End); return Begin[idx]; } - + reference front() { return begin()[0]; } const_reference front() const { return begin()[0]; } - + reference back() { return end()[-1]; } const_reference back() const { return end()[-1]; } - + void pop_back() { --End; End->~T(); } - + T pop_back_val() { T Result = back(); pop_back(); return Result; } - + void clear() { if (std::is_class<T>::value) { destroy_range(Begin, End); } End = Begin; } - + /// data - Return a pointer to the vector's buffer, even if empty(). pointer data() { return pointer(Begin); } - + /// data - Return a pointer to the vector's buffer, even if empty(). const_pointer data() const { return const_pointer(Begin); } - + void push_back(const_reference Elt, BumpVectorContext &C) { if (End < Capacity) { Retry: @@ -165,7 +165,7 @@ public: return; } grow(C); - goto Retry; + goto Retry; } /// insert - Insert some number of copies of element into a position. Return @@ -193,18 +193,18 @@ public: /// capacity - Return the total number of elements in the currently allocated /// buffer. - size_t capacity() const { return Capacity - Begin; } - + size_t capacity() const { return Capacity - Begin; } + private: /// grow - double the size of the allocated memory, guaranteeing space for at /// least one more element or MinSize if specified. void grow(BumpVectorContext &C, size_type MinSize = 1); - + void construct_range(T *S, T *E, const T &Elt) { for (; S != E; ++S) new (S) T(Elt); } - + void destroy_range(T *S, T *E) { while (S != E) { --E; @@ -220,7 +220,7 @@ private: } } }; - + // Define this out-of-line to dissuade the C++ compiler from inlining it. template <typename T> void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { @@ -232,7 +232,7 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { // Allocate the memory from the BumpPtrAllocator. T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity); - + // Copy the elements over. if (Begin != End) { if (std::is_class<T>::value) { |
