Import Clang r73954.
This commit is contained in:
parent
8927c19a5e
commit
da468bf93e
@ -647,6 +647,13 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
// Move to DeclGroup when it is implemented.
|
||||
SourceLocation TypeSpecStartLoc;
|
||||
|
||||
/// \brief End part of this FunctionDecl's source range.
|
||||
///
|
||||
/// We could compute the full range in getSourceRange(). However, when we're
|
||||
/// dealing with a function definition deserialized from a PCH/AST file,
|
||||
/// we can only compute the full range once the function body has been
|
||||
/// de-serialized, so it's far better to have the (sometimes-redundant)
|
||||
/// EndRangeLoc.
|
||||
SourceLocation EndRangeLoc;
|
||||
|
||||
/// \brief The template or declaration that this declaration
|
||||
@ -687,7 +694,6 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
return SourceRange(getLocation(), EndRangeLoc);
|
||||
}
|
||||
void setLocEnd(SourceLocation E) {
|
||||
assert(getLocation() <= E && "Invalid end location");
|
||||
EndRangeLoc = E;
|
||||
}
|
||||
|
||||
|
@ -283,6 +283,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// copy constructor that accepts a const-qualified argument.
|
||||
bool hasConstCopyConstructor(ASTContext &Context) const;
|
||||
|
||||
/// getCopyConstructor - Returns the copy constructor for this class
|
||||
CXXConstructorDecl *getCopyConstructor(ASTContext &Context,
|
||||
unsigned TypeQuals) const;
|
||||
|
||||
/// hasConstCopyAssignment - Determines whether this class has a
|
||||
/// copy assignment operator that accepts a const-qualified argument.
|
||||
bool hasConstCopyAssignment(ASTContext &Context) const;
|
||||
@ -642,18 +646,13 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
/// ImplicitMustBeDefined - Implicit constructor was used to create an
|
||||
/// object of its class type. It must be defined.
|
||||
bool ImplicitMustBeDefined : 1;
|
||||
|
||||
/// FIXME: Add support for base and member initializers.
|
||||
|
||||
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isExplicit, bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline),
|
||||
Explicit(isExplicit), ImplicitlyDefined(false),
|
||||
ImplicitMustBeDefined(false) {
|
||||
Explicit(isExplicit), ImplicitlyDefined(false) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
@ -683,17 +682,6 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
"Can only set the implicit-definition flag once the constructor has been defined");
|
||||
ImplicitlyDefined = ID;
|
||||
}
|
||||
|
||||
/// isImplicitMustBeDefined - Whether a definition must be synthesized for
|
||||
/// the implicit constructor.
|
||||
bool isImplicitMustBeDefined() const {
|
||||
return isImplicit() && ImplicitMustBeDefined;
|
||||
}
|
||||
|
||||
/// setImplicitMustBeDefined - constructor must be implicitly defined.
|
||||
void setImplicitMustBeDefined() {
|
||||
ImplicitMustBeDefined = true;
|
||||
}
|
||||
|
||||
/// isDefaultConstructor - Whether this constructor is a default
|
||||
/// constructor (C++ [class.ctor]p5), which can be used to
|
||||
|
@ -469,10 +469,6 @@ class TemplateArgument {
|
||||
/// occur in a non-dependent, canonical template argument list.
|
||||
TemplateArgument(Expr *E);
|
||||
|
||||
/// \brief Construct a template argument pack.
|
||||
TemplateArgument(SourceLocation Loc, TemplateArgument *Args,
|
||||
unsigned NumArgs, bool CopyArgs);
|
||||
|
||||
/// \brief Copy constructor for a template argument.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
if (Kind == Integral) {
|
||||
@ -587,6 +583,9 @@ class TemplateArgument {
|
||||
/// \brief Retrieve the location where the template argument starts.
|
||||
SourceLocation getLocation() const { return StartLoc; }
|
||||
|
||||
/// \brief Construct a template argument pack.
|
||||
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
|
||||
|
||||
/// \brief Used to insert TemplateArguments into FoldingSets.
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddInteger(Kind);
|
||||
@ -622,47 +621,51 @@ class TemplateArgument {
|
||||
|
||||
/// \brief A helper class for making template argument lists.
|
||||
class TemplateArgumentListBuilder {
|
||||
/// FlatArgs - contains the template arguments in flat form.
|
||||
llvm::SmallVector<TemplateArgument, 16> FlatArgs;
|
||||
|
||||
llvm::SmallVector<TemplateArgument, 16> StructuredArgs;
|
||||
|
||||
ASTContext &Context;
|
||||
TemplateArgument *StructuredArgs;
|
||||
unsigned MaxStructuredArgs;
|
||||
unsigned NumStructuredArgs;
|
||||
|
||||
TemplateArgument *FlatArgs;
|
||||
unsigned MaxFlatArgs;
|
||||
unsigned NumFlatArgs;
|
||||
|
||||
bool AddingToPack;
|
||||
unsigned PackBeginIndex;
|
||||
|
||||
/// isAddingFromParameterPack - Returns whether we're adding arguments from
|
||||
/// a parameter pack.
|
||||
bool isAddingFromParameterPack() const {
|
||||
return PackBeginIndex != std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
public:
|
||||
TemplateArgumentListBuilder(ASTContext &Context) : Context(Context),
|
||||
PackBeginIndex(std::numeric_limits<unsigned>::max()) { }
|
||||
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
|
||||
unsigned NumTemplateArgs)
|
||||
: StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
|
||||
NumStructuredArgs(0), FlatArgs(0),
|
||||
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
|
||||
AddingToPack(false), PackBeginIndex(0) { }
|
||||
|
||||
size_t structuredSize() const {
|
||||
assert(!isAddingFromParameterPack() &&
|
||||
"Size is not valid when adding from a parameter pack");
|
||||
|
||||
return StructuredArgs.size();
|
||||
}
|
||||
|
||||
size_t flatSize() const { return FlatArgs.size(); }
|
||||
void Append(const TemplateArgument& Arg);
|
||||
void BeginPack();
|
||||
void EndPack();
|
||||
|
||||
void push_back(const TemplateArgument& Arg);
|
||||
void ReleaseArgs();
|
||||
|
||||
/// BeginParameterPack - Start adding arguments from a parameter pack.
|
||||
void BeginParameterPack();
|
||||
|
||||
/// EndParameterPack - Finish adding arguments from a parameter pack.
|
||||
void EndParameterPack();
|
||||
|
||||
const TemplateArgument *getFlatArgumentList() const {
|
||||
return FlatArgs.data();
|
||||
unsigned flatSize() const {
|
||||
return NumFlatArgs;
|
||||
}
|
||||
TemplateArgument *getFlatArgumentList() {
|
||||
return FlatArgs.data();
|
||||
const TemplateArgument *getFlatArguments() const {
|
||||
return FlatArgs;
|
||||
}
|
||||
|
||||
unsigned structuredSize() const {
|
||||
// If we don't have any structured args, just reuse the flat size.
|
||||
if (!StructuredArgs)
|
||||
return flatSize();
|
||||
|
||||
return NumStructuredArgs;
|
||||
}
|
||||
const TemplateArgument *getStructuredArguments() const {
|
||||
// If we don't have any structured args, just reuse the flat args.
|
||||
if (!StructuredArgs)
|
||||
return getFlatArguments();
|
||||
|
||||
return StructuredArgs;
|
||||
}
|
||||
};
|
||||
|
||||
@ -676,22 +679,25 @@ class TemplateArgumentList {
|
||||
///
|
||||
/// The integer value will be non-zero to indicate that this
|
||||
/// template argument list does not own the pointer.
|
||||
llvm::PointerIntPair<TemplateArgument *, 1> Arguments;
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
|
||||
|
||||
/// \brief The number of template arguments in this template
|
||||
/// argument list.
|
||||
unsigned NumArguments;
|
||||
unsigned NumFlatArguments;
|
||||
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
|
||||
unsigned NumStructuredArguments;
|
||||
|
||||
public:
|
||||
TemplateArgumentList(ASTContext &Context,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
bool CopyArgs, bool FlattenArgs);
|
||||
bool TakeArgs);
|
||||
|
||||
~TemplateArgumentList();
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
const TemplateArgument &get(unsigned Idx) const {
|
||||
assert(Idx < NumArguments && "Invalid template argument index");
|
||||
assert(Idx < NumFlatArguments && "Invalid template argument index");
|
||||
return getFlatArgumentList()[Idx];
|
||||
}
|
||||
|
||||
@ -700,15 +706,15 @@ class TemplateArgumentList {
|
||||
|
||||
/// \brief Retrieve the number of template arguments in this
|
||||
/// template argument list.
|
||||
unsigned size() const { return NumArguments; }
|
||||
unsigned size() const { return NumFlatArguments; }
|
||||
|
||||
/// \brief Retrieve the number of template arguments in the
|
||||
/// flattened template argument list.
|
||||
unsigned flat_size() const { return NumArguments; }
|
||||
unsigned flat_size() const { return NumFlatArguments; }
|
||||
|
||||
/// \brief Retrieve the flattened template argument list.
|
||||
const TemplateArgument *getFlatArgumentList() const {
|
||||
return Arguments.getPointer();
|
||||
return FlatArguments.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace clang {
|
||||
|
||||
class EnvironmentManager;
|
||||
class BasicValueFactory;
|
||||
class ValueManager;
|
||||
class LiveVariables;
|
||||
|
||||
class Environment {
|
||||
@ -71,8 +71,8 @@ class Environment {
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal GetSVal(const Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
SVal GetBlkExprSVal(const Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const;
|
||||
SVal GetBlkExprSVal(const Stmt* Ex, ValueManager& ValMgr) const;
|
||||
|
||||
/// Profile - Profile the contents of an Environment object for use
|
||||
/// in a FoldingSet.
|
||||
|
@ -481,11 +481,6 @@ class GRExprEngine {
|
||||
return N == EntryNode ? CleanedState : N->getState();
|
||||
}
|
||||
|
||||
public:
|
||||
inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLoc::MakeVal(getBasicVals(), X, Ex->getType());
|
||||
}
|
||||
|
||||
public:
|
||||
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
|
@ -532,7 +532,7 @@ class GRStateManager {
|
||||
|
||||
// Methods that query & manipulate the Environment.
|
||||
SVal GetSVal(const GRState* St, const Stmt* Ex) {
|
||||
return St->getEnvironment().GetSVal(Ex, getBasicVals());
|
||||
return St->getEnvironment().GetSVal(Ex, ValueMgr);
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const GRState* state, const Stmt *S) {
|
||||
@ -546,7 +546,7 @@ class GRStateManager {
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, const Stmt* Ex) {
|
||||
return St->getEnvironment().GetBlkExprSVal(Ex, getBasicVals());
|
||||
return St->getEnvironment().GetBlkExprSVal(Ex, ValueMgr);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, const Stmt* Ex, SVal V,
|
||||
@ -613,7 +613,7 @@ class GRStateManager {
|
||||
// We only want to do fetches from regions that we can actually bind
|
||||
// values. For example, SymbolicRegions of type 'id<...>' cannot
|
||||
// have direct bindings (but their can be bindings on their subregions).
|
||||
if (!R->isBoundable(getContext()))
|
||||
if (!R->isBoundable())
|
||||
return UnknownVal();
|
||||
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
|
@ -59,11 +59,14 @@ class MemRegion : public llvm::FoldingSetNode {
|
||||
protected:
|
||||
MemRegion(Kind k) : kind(k) {}
|
||||
virtual ~MemRegion();
|
||||
ASTContext &getContext() const;
|
||||
|
||||
public:
|
||||
// virtual MemExtent getExtent(MemRegionManager& mrm) const = 0;
|
||||
virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
|
||||
|
||||
|
||||
virtual MemRegionManager* getMemRegionManager() const = 0;
|
||||
|
||||
std::string getString() const;
|
||||
|
||||
virtual void print(llvm::raw_ostream& os) const;
|
||||
@ -72,7 +75,7 @@ class MemRegion : public llvm::FoldingSetNode {
|
||||
|
||||
template<typename RegionTy> const RegionTy* getAs() const;
|
||||
|
||||
virtual bool isBoundable(ASTContext&) const { return true; }
|
||||
virtual bool isBoundable() const { return true; }
|
||||
|
||||
static bool classof(const MemRegion*) { return true; }
|
||||
};
|
||||
@ -81,14 +84,23 @@ class MemRegion : public llvm::FoldingSetNode {
|
||||
/// for example, the set of global variables, the stack frame, etc.
|
||||
class MemSpaceRegion : public MemRegion {
|
||||
friend class MemRegionManager;
|
||||
MemSpaceRegion() : MemRegion(MemSpaceRegionKind) {}
|
||||
|
||||
protected:
|
||||
MemRegionManager *Mgr;
|
||||
|
||||
MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind),
|
||||
Mgr(mgr) {}
|
||||
|
||||
MemRegionManager* getMemRegionManager() const {
|
||||
return Mgr;
|
||||
}
|
||||
|
||||
public:
|
||||
//RegionExtent getExtent() const { return UndefinedExtent(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
bool isBoundable(ASTContext &) const { return false; }
|
||||
bool isBoundable() const { return false; }
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == MemSpaceRegionKind;
|
||||
@ -101,11 +113,12 @@ class SubRegion : public MemRegion {
|
||||
protected:
|
||||
const MemRegion* superRegion;
|
||||
SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
|
||||
|
||||
public:
|
||||
const MemRegion* getSuperRegion() const {
|
||||
return superRegion;
|
||||
}
|
||||
|
||||
MemRegionManager* getMemRegionManager() const;
|
||||
|
||||
bool isSubRegionOf(const MemRegion* R) const;
|
||||
|
||||
@ -123,7 +136,7 @@ class AllocaRegion : public SubRegion {
|
||||
// memory allocated by alloca at the same call site.
|
||||
const Expr* Ex;
|
||||
|
||||
AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion* superRegion)
|
||||
AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
|
||||
: SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
|
||||
|
||||
public:
|
||||
@ -133,7 +146,7 @@ class AllocaRegion : public SubRegion {
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
|
||||
unsigned Cnt);
|
||||
unsigned Cnt, const MemRegion *superRegion);
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
@ -164,8 +177,8 @@ class TypedRegion : public SubRegion {
|
||||
return getLocationType(C)->getDesugaredType();
|
||||
}
|
||||
|
||||
bool isBoundable(ASTContext &C) const {
|
||||
return !getValueType(C).isNull();
|
||||
bool isBoundable() const {
|
||||
return !getValueType(getContext()).isNull();
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
@ -229,14 +242,14 @@ class CodeTextRegion : public TypedRegion {
|
||||
return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data));
|
||||
}
|
||||
|
||||
bool isBoundable(ASTContext&) const { return false; }
|
||||
bool isBoundable() const { return false; }
|
||||
|
||||
virtual void print(llvm::raw_ostream& os) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const void* data, QualType t);
|
||||
const void* data, QualType t, const MemRegion*);
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == CodeTextRegionKind;
|
||||
@ -262,7 +275,9 @@ class SymbolicRegion : public SubRegion {
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym);
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
SymbolRef sym,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
@ -277,7 +292,7 @@ class StringRegion : public TypedRegion {
|
||||
const StringLiteral* Str;
|
||||
protected:
|
||||
|
||||
StringRegion(const StringLiteral* str, MemRegion* sreg)
|
||||
StringRegion(const StringLiteral* str, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, StringRegionKind), Str(str) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
@ -327,7 +342,7 @@ class TypedViewRegion : public TypedRegion {
|
||||
return PTy->getPointeeType();
|
||||
}
|
||||
|
||||
bool isBoundable(ASTContext &C) const {
|
||||
bool isBoundable() const {
|
||||
return isa<PointerType>(LValueType);
|
||||
}
|
||||
|
||||
@ -399,8 +414,8 @@ class VarRegion : public DeclRegion {
|
||||
VarRegion(const VarDecl* vd, const MemRegion* sReg)
|
||||
: DeclRegion(vd, sReg, VarRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD,
|
||||
const MemRegion* superRegion) {
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
|
||||
}
|
||||
|
||||
@ -436,8 +451,8 @@ class FieldRegion : public DeclRegion {
|
||||
return C.getCanonicalType(getDecl()->getType());
|
||||
}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD,
|
||||
const MemRegion* superRegion) {
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
|
||||
}
|
||||
|
||||
@ -453,7 +468,8 @@ class ObjCObjectRegion : public DeclRegion {
|
||||
ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCObjectRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCInterfaceDecl* ivd,
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const ObjCInterfaceDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind);
|
||||
}
|
||||
@ -479,8 +495,8 @@ class ObjCIvarRegion : public DeclRegion {
|
||||
ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
|
||||
}
|
||||
|
||||
@ -556,6 +572,7 @@ const RegionTy* MemRegion::getAs() const {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class MemRegionManager {
|
||||
ASTContext &C;
|
||||
llvm::BumpPtrAllocator& A;
|
||||
llvm::FoldingSet<MemRegion> Regions;
|
||||
|
||||
@ -566,11 +583,13 @@ class MemRegionManager {
|
||||
MemSpaceRegion* code;
|
||||
|
||||
public:
|
||||
MemRegionManager(llvm::BumpPtrAllocator& a)
|
||||
: A(a), globals(0), stack(0), heap(0), unknown(0), code(0) {}
|
||||
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
|
||||
: C(c), A(a), globals(0), stack(0), heap(0), unknown(0), code(0) {}
|
||||
|
||||
~MemRegionManager() {}
|
||||
|
||||
ASTContext &getContext() { return C; }
|
||||
|
||||
/// getStackRegion - Retrieve the memory region associated with the
|
||||
/// current stack frame.
|
||||
MemSpaceRegion* getStackRegion();
|
||||
@ -589,17 +608,6 @@ class MemRegionManager {
|
||||
|
||||
MemSpaceRegion* getCodeRegion();
|
||||
|
||||
bool isGlobalsRegion(const MemRegion* R) {
|
||||
assert(R);
|
||||
return R == globals;
|
||||
}
|
||||
|
||||
/// onStack - check if the region is allocated on the stack.
|
||||
bool onStack(const MemRegion* R);
|
||||
|
||||
/// onHeap - check if the region is allocated on the heap, usually by malloc.
|
||||
bool onHeap(const MemRegion* R);
|
||||
|
||||
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
|
||||
AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt);
|
||||
|
||||
@ -646,14 +654,164 @@ class MemRegionManager {
|
||||
|
||||
CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t);
|
||||
CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t);
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* getRegion(const A1 a1);
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* getRegion(const A1 a1, const MemRegion* superRegion);
|
||||
|
||||
template <typename RegionTy, typename A1, typename A2>
|
||||
RegionTy* getRegion(const A1 a1, const A2 a2);
|
||||
|
||||
bool isGlobalsRegion(const MemRegion* R) {
|
||||
assert(R);
|
||||
return R == globals;
|
||||
}
|
||||
|
||||
bool hasStackStorage(const MemRegion* R);
|
||||
|
||||
bool hasHeapStorage(const MemRegion* R);
|
||||
|
||||
private:
|
||||
MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Out-of-line member definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
inline ASTContext& MemRegion::getContext() const {
|
||||
return getMemRegionManager()->getContext();
|
||||
}
|
||||
|
||||
template<typename RegionTy> struct MemRegionManagerTrait;
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1) {
|
||||
|
||||
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
|
||||
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1, const MemRegion *superRegion)
|
||||
{
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
template <typename RegionTy, typename A1, typename A2>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
|
||||
|
||||
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
|
||||
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, a2, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, a2, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Traits for constructing regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <> struct MemRegionManagerTrait<AllocaRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const Expr *, unsigned) {
|
||||
return MRMgr.getStackRegion();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MemRegionManagerTrait<CompoundLiteralRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const CompoundLiteralExpr *CL) {
|
||||
|
||||
return CL->isFileScope() ? MRMgr.getGlobalsRegion()
|
||||
: MRMgr.getStackRegion();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MemRegionManagerTrait<StringRegion> {
|
||||
typedef MemSpaceRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const StringLiteral*) {
|
||||
return MRMgr.getGlobalsRegion();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MemRegionManagerTrait<VarRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const VarDecl *d) {
|
||||
return d->hasLocalStorage() ? MRMgr.getStackRegion()
|
||||
: MRMgr.getGlobalsRegion();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MemRegionManagerTrait<SymbolicRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
SymbolRef) {
|
||||
return MRMgr.getUnknownRegion();
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct MemRegionManagerTrait<CodeTextRegion> {
|
||||
typedef MemSpaceRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const FunctionDecl*, QualType) {
|
||||
return MRMgr.getCodeRegion();
|
||||
}
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
SymbolRef, QualType) {
|
||||
return MRMgr.getCodeRegion();
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pretty-printing regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
static inline raw_ostream& operator<<(raw_ostream& O,
|
||||
const clang::MemRegion* R) {
|
||||
|
@ -30,6 +30,7 @@ class BasicValueFactory;
|
||||
class MemRegion;
|
||||
class MemRegionManager;
|
||||
class GRStateManager;
|
||||
class ValueManager;
|
||||
|
||||
class SVal {
|
||||
public:
|
||||
@ -171,28 +172,6 @@ class NonLoc : public SVal {
|
||||
public:
|
||||
void print(llvm::raw_ostream& Out) const;
|
||||
|
||||
// Utility methods to create NonLocs.
|
||||
|
||||
static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
|
||||
bool isUnsigned);
|
||||
|
||||
static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X,
|
||||
unsigned BitWidth, bool isUnsigned);
|
||||
|
||||
static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T);
|
||||
|
||||
static NonLoc MakeVal(BasicValueFactory& BasicVals, const IntegerLiteral *I);
|
||||
|
||||
static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
|
||||
bool isUnsigned);
|
||||
|
||||
static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I);
|
||||
|
||||
static NonLoc MakeIntTruthVal(BasicValueFactory& BasicVals, bool b);
|
||||
|
||||
static NonLoc MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
|
||||
BasicValueFactory& BasicVals);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == NonLocKind;
|
||||
@ -210,12 +189,6 @@ class Loc : public SVal {
|
||||
Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {}
|
||||
Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; }
|
||||
|
||||
static Loc MakeVal(const MemRegion* R);
|
||||
|
||||
static Loc MakeVal(const AddrLabelExpr* E);
|
||||
|
||||
static Loc MakeNull(BasicValueFactory &BasicVals);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == LocKind;
|
||||
@ -301,6 +274,8 @@ class ConcreteInt : public NonLoc {
|
||||
};
|
||||
|
||||
class LocAsInteger : public NonLoc {
|
||||
friend class clang::ValueManager;
|
||||
|
||||
LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
|
||||
NonLoc(LocAsIntegerKind, &data) {
|
||||
assert (isa<Loc>(data.first));
|
||||
@ -330,12 +305,10 @@ class LocAsInteger : public NonLoc {
|
||||
static inline bool classof(const NonLoc* V) {
|
||||
return V->getSubKind() == LocAsIntegerKind;
|
||||
}
|
||||
|
||||
static LocAsInteger Make(BasicValueFactory& Vals, Loc V, unsigned Bits);
|
||||
};
|
||||
|
||||
class CompoundVal : public NonLoc {
|
||||
friend class NonLoc;
|
||||
friend class clang::ValueManager;
|
||||
|
||||
CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// This file defines ValueManager, a class that manages symbolic values
|
||||
// and SVals created for use by GRExprEngine and related classes. It
|
||||
// wraps SymbolManager, MemRegionManager, and BasicValueFactory.
|
||||
// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -39,7 +39,7 @@ class ValueManager {
|
||||
ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context)
|
||||
: Context(context), BasicVals(Context, alloc),
|
||||
SymMgr(Context, BasicVals, alloc),
|
||||
MemMgr(alloc) {}
|
||||
MemMgr(Context, alloc) {}
|
||||
|
||||
// Accessors to submanagers.
|
||||
|
||||
@ -68,17 +68,8 @@ class ValueManager {
|
||||
return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
|
||||
}
|
||||
|
||||
// Aggregation methods that use multiple submanagers.
|
||||
|
||||
Loc makeRegionVal(SymbolRef Sym) {
|
||||
return Loc::MakeVal(MemMgr.getSymbolicRegion(Sym));
|
||||
}
|
||||
|
||||
/// makeZeroVal - Construct an SVal representing '0' for the specified type.
|
||||
SVal makeZeroVal(QualType T);
|
||||
/// makeZeroArrayIndex - Construct an SVal representing '0' index for array
|
||||
/// elements.
|
||||
SVal makeZeroArrayIndex();
|
||||
|
||||
/// GetRegionValueSymbolVal - make a unique symbol for value of R.
|
||||
SVal getRegionValueSymbolVal(const MemRegion* R, QualType T = QualType());
|
||||
@ -87,16 +78,77 @@ class ValueManager {
|
||||
SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count);
|
||||
|
||||
SVal getFunctionPointer(const FunctionDecl* FD);
|
||||
|
||||
NonLoc makeNonLoc(SymbolRef sym);
|
||||
|
||||
|
||||
NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
|
||||
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
|
||||
}
|
||||
|
||||
NonLoc makeZeroArrayIndex() {
|
||||
return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const IntegerLiteral* I) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
|
||||
I->getType()->isUnsignedIntegerType()));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const llvm::APSInt& V) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(uint64_t X, QualType T) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(X, T));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(uint64_t X, bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc makeLocAsInteger(Loc V, unsigned Bits) {
|
||||
return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits));
|
||||
}
|
||||
|
||||
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const llvm::APSInt& rhs, QualType T);
|
||||
|
||||
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const SymExpr *rhs, QualType T);
|
||||
|
||||
NonLoc makeTruthVal(bool b, QualType T);
|
||||
NonLoc makeTruthVal(bool b, QualType T) {
|
||||
return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
|
||||
}
|
||||
|
||||
NonLoc makeTruthVal(bool b) {
|
||||
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
|
||||
}
|
||||
|
||||
Loc makeNull() {
|
||||
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
|
||||
}
|
||||
|
||||
Loc makeLoc(SymbolRef Sym) {
|
||||
return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym));
|
||||
}
|
||||
|
||||
Loc makeLoc(const MemRegion* R) {
|
||||
return loc::MemRegionVal(R);
|
||||
}
|
||||
|
||||
Loc makeLoc(const AddrLabelExpr* E) {
|
||||
return loc::GotoLabel(E->getLabel());
|
||||
}
|
||||
|
||||
Loc makeLoc(const llvm::APSInt& V) {
|
||||
return loc::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
};
|
||||
} // end clang namespace
|
||||
#endif
|
||||
|
@ -136,4 +136,7 @@ def warn_pch_char_signed : Error<
|
||||
|
||||
def err_not_a_pch_file : Error<
|
||||
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
|
||||
def warn_unknown_warning_option : Warning<
|
||||
"unknown warning option '%0'">,
|
||||
InGroup<DiagGroup<"unknown-warning-option"> >;
|
||||
}
|
||||
|
@ -580,8 +580,8 @@ def err_param_default_argument_nonfunc : Error<
|
||||
"default arguments can only be specified for parameters in a function "
|
||||
"declaration">;
|
||||
def err_defining_default_ctor : Error<
|
||||
"cannot define the default constructor for %0, because %select{base class|member}1 "
|
||||
"%2 does not have any implicit default constructor">;
|
||||
"cannot define the implicit default constructor for %0, because %select{base class|member}1 "
|
||||
"%2 does not have any default constructor">;
|
||||
def note_previous_class_decl : Note<
|
||||
"%0 declared here">;
|
||||
def err_unintialized_member : Error<
|
||||
@ -870,7 +870,8 @@ def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
|
||||
def err_undeclared_use : Error<"use of undeclared '%0'">;
|
||||
def warn_deprecated : Warning<"%0 is deprecated">,
|
||||
InGroup<DiagGroup<"deprecated-declarations">>;
|
||||
def warn_unavailable : Warning<"%0 is unavailable">;
|
||||
def warn_unavailable : Warning<"%0 is unavailable">,
|
||||
InGroup<DiagGroup<"unavailable-declarations">>;
|
||||
def note_unavailable_here : Note<
|
||||
"function has been explicitly marked %select{unavailable|deleted}0 here">;
|
||||
def warn_not_enough_argument : Warning<
|
||||
|
@ -145,10 +145,6 @@ inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) {
|
||||
return LHS.getRawEncoding() < RHS.getRawEncoding();
|
||||
}
|
||||
|
||||
inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) {
|
||||
return LHS.getRawEncoding() <= RHS.getRawEncoding();
|
||||
}
|
||||
|
||||
/// SourceRange - a trival tuple used to represent a source range.
|
||||
class SourceRange {
|
||||
SourceLocation B;
|
||||
|
@ -637,18 +637,50 @@ class Action : public ActionBase {
|
||||
// Expression Parsing Callbacks.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Notifies the action when the parser is processing an unevaluated
|
||||
/// operand.
|
||||
/// \brief Describes how the expressions currently being parsed are
|
||||
/// evaluated at run-time, if at all.
|
||||
enum ExpressionEvaluationContext {
|
||||
/// \brief The current expression and its subexpressions occur within an
|
||||
/// unevaluated operand (C++0x [expr]p8), such as a constant expression
|
||||
/// or the subexpression of \c sizeof, where the type or the value of the
|
||||
/// expression may be significant but no code will be generated to evaluate
|
||||
/// the value of the expression at run time.
|
||||
Unevaluated,
|
||||
|
||||
/// \brief The current expression is potentially evaluated at run time,
|
||||
/// which means that code may be generated to evaluate the value of the
|
||||
/// expression at run time.
|
||||
PotentiallyEvaluated,
|
||||
|
||||
/// \brief The current expression may be potentially evaluated or it may
|
||||
/// be unevaluated, but it is impossible to tell from the lexical context.
|
||||
/// This evaluation context is used primary for the operand of the C++
|
||||
/// \c typeid expression, whose argument is potentially evaluated only when
|
||||
/// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2).
|
||||
PotentiallyPotentiallyEvaluated
|
||||
};
|
||||
|
||||
/// \brief The parser is entering a new expression evaluation context.
|
||||
///
|
||||
/// \param UnevaluatedOperand true to indicate that the parser is processing
|
||||
/// an unevaluated operand, or false otherwise.
|
||||
/// \param NewContext is the new expression evaluation context.
|
||||
///
|
||||
/// \returns whether the the action module was previously in an unevaluated
|
||||
/// operand.
|
||||
virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) {
|
||||
return false;
|
||||
/// \returns the previous expression evaluation context.
|
||||
virtual ExpressionEvaluationContext
|
||||
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
|
||||
return PotentiallyEvaluated;
|
||||
}
|
||||
|
||||
/// \brief The parser is existing an expression evaluation context.
|
||||
///
|
||||
/// \param OldContext the expression evaluation context that the parser is
|
||||
/// leaving.
|
||||
///
|
||||
/// \param NewContext the expression evaluation context that the parser is
|
||||
/// returning to.
|
||||
virtual void
|
||||
PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
|
||||
ExpressionEvaluationContext NewContext) { }
|
||||
|
||||
// Primary Expressions.
|
||||
|
||||
/// \brief Retrieve the source range that corresponds to the given
|
||||
@ -1891,6 +1923,29 @@ class PrettyStackTraceActionsDecl : public llvm::PrettyStackTraceEntry {
|
||||
virtual void print(llvm::raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
/// \brief RAII object that enters a new expression evaluation context.
|
||||
class EnterExpressionEvaluationContext {
|
||||
/// \brief The action object.
|
||||
Action &Actions;
|
||||
|
||||
/// \brief The previous expression evaluation context.
|
||||
Action::ExpressionEvaluationContext PrevContext;
|
||||
|
||||
/// \brief The current expression evaluation context.
|
||||
Action::ExpressionEvaluationContext CurContext;
|
||||
|
||||
public:
|
||||
EnterExpressionEvaluationContext(Action &Actions,
|
||||
Action::ExpressionEvaluationContext NewContext)
|
||||
: Actions(Actions), CurContext(NewContext) {
|
||||
PrevContext = Actions.PushExpressionEvaluationContext(NewContext);
|
||||
}
|
||||
|
||||
~EnterExpressionEvaluationContext() {
|
||||
Actions.PopExpressionEvaluationContext(CurContext, PrevContext);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -104,24 +104,6 @@ class Parser {
|
||||
GreaterThanIsOperator = OldGreaterThanIsOperator;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief RAII object that enters an unevaluated operand.
|
||||
class EnterUnevaluatedOperand {
|
||||
/// \brief The action object.
|
||||
Action &Actions;
|
||||
|
||||
/// \brief Whether we were previously within an unevaluated operand.
|
||||
bool PreviouslyInUnevaluatedOperand;
|
||||
|
||||
public:
|
||||
explicit EnterUnevaluatedOperand(Action &Actions) : Actions(Actions) {
|
||||
PreviouslyInUnevaluatedOperand = Actions.setUnevaluatedOperand(true);
|
||||
}
|
||||
|
||||
~EnterUnevaluatedOperand() {
|
||||
Actions.setUnevaluatedOperand(PreviouslyInUnevaluatedOperand);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
Parser(Preprocessor &PP, Action &Actions);
|
||||
|
@ -379,7 +379,7 @@ Stmt *FunctionDecl::getBodyIfAvailable() const {
|
||||
|
||||
void FunctionDecl::setBody(Stmt *B) {
|
||||
Body = B;
|
||||
if (B && EndRangeLoc < B->getLocEnd())
|
||||
if (B)
|
||||
EndRangeLoc = B->getLocEnd();
|
||||
}
|
||||
|
||||
@ -494,8 +494,9 @@ void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
|
||||
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
|
||||
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
||||
|
||||
// Update source range.
|
||||
if (EndRangeLoc < NewParamInfo[NumParams-1]->getLocEnd())
|
||||
// Update source range. The check below allows us to set EndRangeLoc before
|
||||
// setting the parameters.
|
||||
if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation())
|
||||
EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd();
|
||||
}
|
||||
}
|
||||
|
@ -66,21 +66,29 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
|
||||
return getCopyConstructor(Context, QualType::Const) != 0;
|
||||
}
|
||||
|
||||
CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
|
||||
unsigned TypeQuals) const{
|
||||
QualType ClassType
|
||||
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
|
||||
DeclarationName ConstructorName
|
||||
= Context.DeclarationNames.getCXXConstructorName(
|
||||
Context.getCanonicalType(ClassType));
|
||||
unsigned TypeQuals;
|
||||
Context.getCanonicalType(ClassType));
|
||||
unsigned FoundTQs;
|
||||
DeclContext::lookup_const_iterator Con, ConEnd;
|
||||
for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName);
|
||||
Con != ConEnd; ++Con) {
|
||||
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) &&
|
||||
(TypeQuals & QualType::Const) != 0)
|
||||
return true;
|
||||
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
|
||||
FoundTQs)) {
|
||||
if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) ||
|
||||
(!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const)))
|
||||
return cast<CXXConstructorDecl>(*Con);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
|
||||
|
@ -239,79 +239,103 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument pack.
|
||||
TemplateArgument::TemplateArgument(SourceLocation Loc, TemplateArgument *args,
|
||||
unsigned NumArgs, bool CopyArgs)
|
||||
: Kind(Pack) {
|
||||
Args.NumArgs = NumArgs;
|
||||
Args.CopyArgs = CopyArgs;
|
||||
if (!Args.CopyArgs) {
|
||||
Args.Args = args;
|
||||
return;
|
||||
}
|
||||
|
||||
Args.Args = new TemplateArgument[NumArgs];
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
Args.Args[I] = args[I];
|
||||
void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
|
||||
bool CopyArgs) {
|
||||
assert(isNull() && "Must call setArgumentPack on a null argument");
|
||||
|
||||
Kind = Pack;
|
||||
Args.NumArgs = NumArgs;
|
||||
Args.CopyArgs = CopyArgs;
|
||||
if (!Args.CopyArgs) {
|
||||
Args.Args = args;
|
||||
return;
|
||||
}
|
||||
|
||||
Args.Args = new TemplateArgument[NumArgs];
|
||||
for (unsigned I = 0; I != Args.NumArgs; ++I)
|
||||
Args.Args[I] = args[I];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TemplateArgumentListBuilder Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
void TemplateArgumentListBuilder::push_back(const TemplateArgument& Arg) {
|
||||
|
||||
void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) {
|
||||
switch (Arg.getKind()) {
|
||||
default: break;
|
||||
case TemplateArgument::Type:
|
||||
assert(Arg.getAsType()->isCanonical() && "Type must be canonical!");
|
||||
break;
|
||||
default: break;
|
||||
case TemplateArgument::Type:
|
||||
assert(Arg.getAsType()->isCanonical() && "Type must be canonical!");
|
||||
break;
|
||||
}
|
||||
|
||||
FlatArgs.push_back(Arg);
|
||||
assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!");
|
||||
assert(!StructuredArgs &&
|
||||
"Can't append arguments when an argument pack has been added!");
|
||||
|
||||
if (!isAddingFromParameterPack())
|
||||
StructuredArgs.push_back(Arg);
|
||||
if (!FlatArgs)
|
||||
FlatArgs = new TemplateArgument[MaxFlatArgs];
|
||||
|
||||
FlatArgs[NumFlatArgs++] = Arg;
|
||||
}
|
||||
|
||||
void TemplateArgumentListBuilder::BeginParameterPack() {
|
||||
assert(!isAddingFromParameterPack() && "Already adding to parameter pack!");
|
||||
|
||||
PackBeginIndex = FlatArgs.size();
|
||||
void TemplateArgumentListBuilder::BeginPack() {
|
||||
assert(!AddingToPack && "Already adding to pack!");
|
||||
assert(!StructuredArgs && "Argument list already contains a pack!");
|
||||
|
||||
AddingToPack = true;
|
||||
PackBeginIndex = NumFlatArgs;
|
||||
}
|
||||
|
||||
void TemplateArgumentListBuilder::EndParameterPack() {
|
||||
assert(isAddingFromParameterPack() && "Not adding to parameter pack!");
|
||||
void TemplateArgumentListBuilder::EndPack() {
|
||||
assert(AddingToPack && "Not adding to pack!");
|
||||
assert(!StructuredArgs && "Argument list already contains a pack!");
|
||||
|
||||
AddingToPack = false;
|
||||
|
||||
unsigned NumArgs = FlatArgs.size() - PackBeginIndex;
|
||||
TemplateArgument *Args = NumArgs ? &FlatArgs[PackBeginIndex] : 0;
|
||||
StructuredArgs = new TemplateArgument[MaxStructuredArgs];
|
||||
|
||||
StructuredArgs.push_back(TemplateArgument(SourceLocation(), Args, NumArgs,
|
||||
/*CopyArgs=*/false));
|
||||
// First copy the flat entries over to the list (if any)
|
||||
for (unsigned I = 0; I != PackBeginIndex; ++I) {
|
||||
NumStructuredArgs++;
|
||||
StructuredArgs[I] = FlatArgs[I];
|
||||
}
|
||||
|
||||
PackBeginIndex = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
// Next, set the pack.
|
||||
TemplateArgument *PackArgs = 0;
|
||||
unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
|
||||
if (NumPackArgs)
|
||||
PackArgs = &FlatArgs[PackBeginIndex];
|
||||
|
||||
StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
|
||||
/*CopyArgs=*/false);
|
||||
}
|
||||
|
||||
void TemplateArgumentListBuilder::ReleaseArgs() {
|
||||
FlatArgs = 0;
|
||||
NumFlatArgs = 0;
|
||||
MaxFlatArgs = 0;
|
||||
StructuredArgs = 0;
|
||||
NumStructuredArgs = 0;
|
||||
MaxStructuredArgs = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TemplateArgumentList Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
|
||||
TemplateArgumentListBuilder &Builder,
|
||||
bool CopyArgs, bool FlattenArgs)
|
||||
: NumArguments(Builder.flatSize()) {
|
||||
if (!CopyArgs) {
|
||||
Arguments.setPointer(Builder.getFlatArgumentList());
|
||||
Arguments.setInt(1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool TakeArgs)
|
||||
: FlatArguments(Builder.getFlatArguments(), TakeArgs),
|
||||
NumFlatArguments(Builder.flatSize()),
|
||||
StructuredArguments(Builder.getStructuredArguments(), TakeArgs),
|
||||
NumStructuredArguments(Builder.structuredSize()) {
|
||||
|
||||
unsigned Size = sizeof(TemplateArgument) * Builder.flatSize();
|
||||
unsigned Align = llvm::AlignOf<TemplateArgument>::Alignment;
|
||||
void *Mem = Context.Allocate(Size, Align);
|
||||
Arguments.setPointer((TemplateArgument *)Mem);
|
||||
Arguments.setInt(0);
|
||||
|
||||
TemplateArgument *Args = (TemplateArgument *)Mem;
|
||||
for (unsigned I = 0; I != NumArguments; ++I)
|
||||
new (Args + I) TemplateArgument(Builder.getFlatArgumentList()[I]);
|
||||
if (!TakeArgs)
|
||||
return;
|
||||
|
||||
if (Builder.getStructuredArguments() == Builder.getFlatArguments())
|
||||
StructuredArguments.setInt(0);
|
||||
Builder.ReleaseArgs();
|
||||
}
|
||||
|
||||
TemplateArgumentList::~TemplateArgumentList() {
|
||||
@ -333,7 +357,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
|
||||
// class template specializations?
|
||||
SpecializedTemplate->getIdentifier()),
|
||||
SpecializedTemplate(SpecializedTemplate),
|
||||
TemplateArgs(Context, Builder, /*CopyArgs=*/true, /*FlattenArgs=*/true),
|
||||
TemplateArgs(Context, Builder, /*TakeArgs=*/true),
|
||||
SpecializationKind(TSK_Undeclared) {
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
|
||||
|
||||
// FIXME: Investigate what is using this. This method should be removed.
|
||||
virtual Loc getLoc(const VarDecl* VD) {
|
||||
return Loc::MakeVal(MRMgr.getVarRegion(VD));
|
||||
return ValMgr.makeLoc(MRMgr.getVarRegion(VD));
|
||||
}
|
||||
|
||||
const GRState *BindCompoundLiteral(const GRState *state,
|
||||
@ -126,17 +126,17 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
|
||||
}
|
||||
|
||||
SVal BasicStoreManager::getLValueVar(const GRState *state, const VarDecl* VD) {
|
||||
return Loc::MakeVal(MRMgr.getVarRegion(VD));
|
||||
return ValMgr.makeLoc(MRMgr.getVarRegion(VD));
|
||||
}
|
||||
|
||||
SVal BasicStoreManager::getLValueString(const GRState *state,
|
||||
const StringLiteral* S) {
|
||||
return Loc::MakeVal(MRMgr.getStringRegion(S));
|
||||
return ValMgr.makeLoc(MRMgr.getStringRegion(S));
|
||||
}
|
||||
|
||||
SVal BasicStoreManager::getLValueCompoundLiteral(const GRState *state,
|
||||
const CompoundLiteralExpr* CL){
|
||||
return Loc::MakeVal(MRMgr.getCompoundLiteralRegion(CL));
|
||||
return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL));
|
||||
}
|
||||
|
||||
SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl* D,
|
||||
@ -151,7 +151,7 @@ SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl*
|
||||
const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
|
||||
|
||||
if (BaseR == SelfRegion)
|
||||
return loc::MemRegionVal(MRMgr.getObjCIvarRegion(D, BaseR));
|
||||
return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR));
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
@ -186,7 +186,7 @@ SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base,
|
||||
return Base;
|
||||
}
|
||||
|
||||
return Loc::MakeVal(MRMgr.getFieldRegion(D, BaseR));
|
||||
return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR));
|
||||
}
|
||||
|
||||
SVal BasicStoreManager::getLValueElement(const GRState *state,
|
||||
@ -242,8 +242,8 @@ SVal BasicStoreManager::getLValueElement(const GRState *state,
|
||||
}
|
||||
|
||||
if (BaseR)
|
||||
return Loc::MakeVal(MRMgr.getElementRegion(elementType, UnknownVal(),
|
||||
BaseR, getContext()));
|
||||
return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(),
|
||||
BaseR, getContext()));
|
||||
else
|
||||
return UnknownVal();
|
||||
}
|
||||
@ -351,7 +351,7 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
|
||||
// are incompatible. This may also cause lots of breakage
|
||||
// elsewhere. Food for thought.
|
||||
if (const TypedRegion *TyR = dyn_cast<TypedRegion>(R)) {
|
||||
if (TyR->isBoundable(C) &&
|
||||
if (TyR->isBoundable() &&
|
||||
Loc::IsLocType(TyR->getValueType(C)))
|
||||
V = X->getLoc();
|
||||
}
|
||||
@ -456,7 +456,7 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
|
||||
const MemRegion* R = I.getKey();
|
||||
|
||||
if (!Marked.count(R)) {
|
||||
store = Remove(store, Loc::MakeVal(R));
|
||||
store = Remove(store, ValMgr.makeLoc(R));
|
||||
SVal X = I.getData();
|
||||
|
||||
for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
|
||||
@ -483,7 +483,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) {
|
||||
const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
|
||||
SelfRegion);
|
||||
SVal X = ValMgr.getRegionValueSymbolVal(IVR);
|
||||
St = BindInternal(St, Loc::MakeVal(IVR), X);
|
||||
St = BindInternal(St, ValMgr.makeLoc(IVR), X);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -515,8 +515,8 @@ Store BasicStoreManager::getInitialStore() {
|
||||
SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
|
||||
MRMgr.getHeapRegion());
|
||||
|
||||
St = BindInternal(St, Loc::MakeVal(MRMgr.getVarRegion(PD)),
|
||||
Loc::MakeVal(SelfRegion));
|
||||
St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD)),
|
||||
ValMgr.makeLoc(SelfRegion));
|
||||
|
||||
// Scan the method for ivar references. While this requires an
|
||||
// entire AST scan, the cost should not be high in practice.
|
||||
@ -541,7 +541,7 @@ Store BasicStoreManager::getInitialStore() {
|
||||
? ValMgr.getRegionValueSymbolVal(R)
|
||||
: UndefinedVal();
|
||||
|
||||
St = BindInternal(St, Loc::MakeVal(R), X);
|
||||
St = BindInternal(St, ValMgr.makeLoc(R), X);
|
||||
}
|
||||
}
|
||||
return St;
|
||||
|
@ -2835,7 +2835,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
// Remove any existing reference-count binding.
|
||||
if (Sym) state = state->remove<RefBindings>(Sym);
|
||||
|
||||
if (R->isBoundable(Ctx)) {
|
||||
if (R->isBoundable()) {
|
||||
// Set the value of the variable to be a conjured symbol.
|
||||
unsigned Count = Builder.getCurrentBlockCount();
|
||||
QualType T = R->getValueType(Ctx);
|
||||
@ -2843,7 +2843,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())){
|
||||
ValueManager &ValMgr = Eng.getValueManager();
|
||||
SVal V = ValMgr.getConjuredSymbolVal(*I, T, Count);
|
||||
state = state->bindLoc(Loc::MakeVal(R), V);
|
||||
state = state->bindLoc(ValMgr.makeLoc(R), V);
|
||||
}
|
||||
else if (const RecordType *RT = T->getAsStructureType()) {
|
||||
// Handle structs in a not so awesome way. Here we just
|
||||
@ -2873,7 +2873,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
const FieldRegion* FR = MRMgr.getFieldRegion(FD, R);
|
||||
|
||||
SVal V = ValMgr.getConjuredSymbolVal(*I, FT, Count);
|
||||
state = state->bindLoc(Loc::MakeVal(FR), V);
|
||||
state = state->bindLoc(ValMgr.makeLoc(FR), V);
|
||||
}
|
||||
}
|
||||
} else if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
|
||||
@ -2987,7 +2987,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
QualType RetT = GetReturnType(Ex, ValMgr.getContext());
|
||||
state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
|
||||
RetT));
|
||||
state = state->bindExpr(Ex, ValMgr.makeRegionVal(Sym), false);
|
||||
state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false);
|
||||
|
||||
// FIXME: Add a flag to the checker where allocations are assumed to
|
||||
// *not fail.
|
||||
@ -3010,7 +3010,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
QualType RetT = GetReturnType(Ex, ValMgr.getContext());
|
||||
state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
|
||||
RetT));
|
||||
state = state->bindExpr(Ex, ValMgr.makeRegionVal(Sym), false);
|
||||
state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,14 @@
|
||||
|
||||
using namespace clang;
|
||||
|
||||
SVal Environment::GetSVal(const Stmt *E, BasicValueFactory& BasicVals) const {
|
||||
SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (E->getStmtClass()) {
|
||||
|
||||
case Stmt::AddrLabelExprClass:
|
||||
return Loc::MakeVal(cast<AddrLabelExpr>(E));
|
||||
return ValMgr.makeLoc(cast<AddrLabelExpr>(E));
|
||||
|
||||
// ParenExprs are no-ops.
|
||||
|
||||
@ -35,11 +35,11 @@ SVal Environment::GetSVal(const Stmt *E, BasicValueFactory& BasicVals) const {
|
||||
|
||||
case Stmt::CharacterLiteralClass: {
|
||||
const CharacterLiteral* C = cast<CharacterLiteral>(E);
|
||||
return NonLoc::MakeVal(BasicVals, C->getValue(), C->getType());
|
||||
return ValMgr.makeIntVal(C->getValue(), C->getType());
|
||||
}
|
||||
|
||||
case Stmt::IntegerLiteralClass: {
|
||||
return NonLoc::MakeVal(BasicVals, cast<IntegerLiteral>(E));
|
||||
return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
|
||||
}
|
||||
|
||||
// Casts where the source and target type are the same
|
||||
@ -69,8 +69,7 @@ SVal Environment::GetSVal(const Stmt *E, BasicValueFactory& BasicVals) const {
|
||||
return LookupExpr(E);
|
||||
}
|
||||
|
||||
SVal Environment::GetBlkExprSVal(const Stmt *E,
|
||||
BasicValueFactory& BasicVals) const {
|
||||
SVal Environment::GetBlkExprSVal(const Stmt *E, ValueManager& ValMgr) const {
|
||||
|
||||
while (1) {
|
||||
switch (E->getStmtClass()) {
|
||||
@ -80,11 +79,11 @@ SVal Environment::GetBlkExprSVal(const Stmt *E,
|
||||
|
||||
case Stmt::CharacterLiteralClass: {
|
||||
const CharacterLiteral* C = cast<CharacterLiteral>(E);
|
||||
return NonLoc::MakeVal(BasicVals, C->getValue(), C->getType());
|
||||
return ValMgr.makeIntVal(C->getValue(), C->getType());
|
||||
}
|
||||
|
||||
case Stmt::IntegerLiteralClass: {
|
||||
return NonLoc::MakeVal(BasicVals, cast<IntegerLiteral>(E));
|
||||
return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -905,16 +905,19 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
|
||||
// this right now, and since most logical expressions are used for branches,
|
||||
// the payoff is not likely to be large. Instead, we do eager evaluation.
|
||||
if (const GRState *newState = state->assume(X, true))
|
||||
MakeNode(Dst, B, Pred, newState->bindBlkExpr(B, MakeConstantVal(1U, B)));
|
||||
MakeNode(Dst, B, Pred,
|
||||
newState->bindBlkExpr(B, ValMgr.makeIntVal(1U, B->getType())));
|
||||
|
||||
if (const GRState *newState = state->assume(X, false))
|
||||
MakeNode(Dst, B, Pred, newState->bindBlkExpr(B, MakeConstantVal(0U, B)));
|
||||
MakeNode(Dst, B, Pred,
|
||||
newState->bindBlkExpr(B, ValMgr.makeIntVal(0U, B->getType())));
|
||||
}
|
||||
else {
|
||||
// We took the LHS expression. Depending on whether we are '&&' or
|
||||
// '||' we know what the value of the expression is via properties of
|
||||
// the short-circuiting.
|
||||
X = MakeConstantVal( B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B);
|
||||
X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U,
|
||||
B->getType());
|
||||
MakeNode(Dst, B, Pred, state->bindBlkExpr(B, X));
|
||||
}
|
||||
}
|
||||
@ -944,8 +947,7 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst,
|
||||
} else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
|
||||
assert(!asLValue && "EnumConstantDecl does not have lvalue.");
|
||||
|
||||
BasicValueFactory& BasicVals = StateMgr.getBasicVals();
|
||||
SVal V = nonloc::ConcreteInt(BasicVals.getValue(ED->getInitVal()));
|
||||
SVal V = ValMgr.makeIntVal(ED->getInitVal());
|
||||
MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V));
|
||||
return;
|
||||
|
||||
@ -1615,14 +1617,16 @@ void GRExprEngine::EvalEagerlyAssume(NodeSet &Dst, NodeSet &Src, Expr *Ex) {
|
||||
if (isa<nonloc::SymExprVal>(V)) {
|
||||
// First assume that the condition is true.
|
||||
if (const GRState *stateTrue = state->assume(V, true)) {
|
||||
stateTrue = stateTrue->bindExpr(Ex, MakeConstantVal(1U, Ex));
|
||||
stateTrue = stateTrue->bindExpr(Ex,
|
||||
ValMgr.makeIntVal(1U, Ex->getType()));
|
||||
Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
|
||||
stateTrue, Pred));
|
||||
}
|
||||
|
||||
// Next, assume that the condition is false.
|
||||
if (const GRState *stateFalse = state->assume(V, false)) {
|
||||
stateFalse = stateFalse->bindExpr(Ex, MakeConstantVal(0U, Ex));
|
||||
stateFalse = stateFalse->bindExpr(Ex,
|
||||
ValMgr.makeIntVal(0U, Ex->getType()));
|
||||
Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
|
||||
stateFalse, Pred));
|
||||
}
|
||||
@ -1725,12 +1729,11 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
|
||||
const GRState *state = GetState(Pred);
|
||||
|
||||
// Handle the case where the container still has elements.
|
||||
QualType IntTy = getContext().IntTy;
|
||||
SVal TrueV = NonLoc::MakeVal(getBasicVals(), 1, IntTy);
|
||||
SVal TrueV = ValMgr.makeTruthVal(1);
|
||||
const GRState *hasElems = state->bindExpr(S, TrueV);
|
||||
|
||||
// Handle the case where the container has no elements.
|
||||
SVal FalseV = NonLoc::MakeVal(getBasicVals(), 0, IntTy);
|
||||
SVal FalseV = ValMgr.makeTruthVal(0);
|
||||
const GRState *noElems = state->bindExpr(S, FalseV);
|
||||
|
||||
if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
|
||||
@ -1742,11 +1745,11 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
|
||||
assert (Loc::IsLocType(T));
|
||||
unsigned Count = Builder->getCurrentBlockCount();
|
||||
SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
|
||||
SVal V = Loc::MakeVal(getStoreManager().getRegionManager().getSymbolicRegion(Sym));
|
||||
SVal V = ValMgr.makeLoc(Sym);
|
||||
hasElems = hasElems->bindLoc(ElementV, V);
|
||||
|
||||
// Bind the location to 'nil' on the false branch.
|
||||
SVal nilV = loc::ConcreteInt(getBasicVals().getValue(0, T));
|
||||
SVal nilV = ValMgr.makeIntVal(0, T);
|
||||
noElems = noElems->bindLoc(ElementV, nilV);
|
||||
}
|
||||
|
||||
@ -2290,7 +2293,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
|
||||
// Handle base case where the initializer has no elements.
|
||||
// e.g: static int* myArray[] = {};
|
||||
if (NumInitElements == 0) {
|
||||
SVal V = NonLoc::MakeCompoundVal(T, StartVals, getBasicVals());
|
||||
SVal V = ValMgr.makeCompoundVal(T, StartVals);
|
||||
MakeNode(Dst, E, Pred, state->bindExpr(E, V));
|
||||
return;
|
||||
}
|
||||
@ -2323,7 +2326,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
|
||||
|
||||
if (NewItr == ItrEnd) {
|
||||
// Now we have a list holding all init values. Make CompoundValData.
|
||||
SVal V = NonLoc::MakeCompoundVal(T, NewVals, getBasicVals());
|
||||
SVal V = ValMgr.makeCompoundVal(T, NewVals);
|
||||
|
||||
// Make final state and node.
|
||||
MakeNode(Dst, E, *NI, state->bindExpr(E, V));
|
||||
@ -2393,8 +2396,7 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
|
||||
amt = getContext().getTypeAlign(T) / 8;
|
||||
|
||||
MakeNode(Dst, Ex, Pred,
|
||||
GetState(Pred)->bindExpr(Ex, NonLoc::MakeVal(getBasicVals(), amt,
|
||||
Ex->getType())));
|
||||
GetState(Pred)->bindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
|
||||
}
|
||||
|
||||
|
||||
@ -2468,7 +2470,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
// For all other types, UnaryOperator::Float returns 0.
|
||||
assert (Ex->getType()->isIntegerType());
|
||||
const GRState* state = GetState(*I);
|
||||
SVal X = NonLoc::MakeVal(getBasicVals(), 0, Ex->getType());
|
||||
SVal X = ValMgr.makeZeroVal(Ex->getType());
|
||||
MakeNode(Dst, U, *I, state->bindExpr(U, X));
|
||||
}
|
||||
|
||||
@ -2571,7 +2573,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
// transfer functions as "0 == E".
|
||||
|
||||
if (isa<Loc>(V)) {
|
||||
Loc X = Loc::MakeNull(getBasicVals());
|
||||
Loc X = ValMgr.makeNull();
|
||||
SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X,
|
||||
U->getType());
|
||||
state = state->bindExpr(U, Result);
|
||||
@ -2629,7 +2631,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
|
||||
: BinaryOperator::Sub;
|
||||
|
||||
SVal Result = EvalBinOp(state, Op, V2, MakeConstantVal(1U, U),
|
||||
SVal Result = EvalBinOp(state, Op, V2, ValMgr.makeIntVal(1U,U->getType()),
|
||||
U->getType());
|
||||
|
||||
// Conjure a new symbol if necessary to recover precision.
|
||||
|
@ -717,7 +717,7 @@ class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
|
||||
if (isa<loc::ConcreteInt>(V)) {
|
||||
bool b = false;
|
||||
ASTContext &C = BRC.getASTContext();
|
||||
if (R->isBoundable(C)) {
|
||||
if (R->isBoundable()) {
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
if (C.isObjCObjectPointerType(TR->getValueType(C))) {
|
||||
os << "initialized to nil";
|
||||
@ -748,7 +748,7 @@ class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
|
||||
if (isa<loc::ConcreteInt>(V)) {
|
||||
bool b = false;
|
||||
ASTContext &C = BRC.getASTContext();
|
||||
if (R->isBoundable(C)) {
|
||||
if (R->isBoundable()) {
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
if (C.isObjCObjectPointerType(TR->getValueType(C))) {
|
||||
os << "nil object reference stored to ";
|
||||
|
@ -84,7 +84,7 @@ SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
|
||||
unsigned BitWidth = Eng.getContext().getTypeSize(T);
|
||||
|
||||
if (!isa<loc::ConcreteInt>(X))
|
||||
return nonloc::LocAsInteger::Make(BasicVals, X, BitWidth);
|
||||
return Eng.getValueManager().makeLocAsInteger(X, BitWidth);
|
||||
|
||||
llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
|
||||
V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
|
||||
@ -133,8 +133,8 @@ SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R,
|
||||
QualType T) {
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
ValueManager& ValMgr = Eng.getValueManager();
|
||||
unsigned subkind = L.getSubKind();
|
||||
|
||||
while (1) {
|
||||
@ -157,16 +157,15 @@ SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
|
||||
V.setIsUnsigned(true);
|
||||
V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
|
||||
return EvalBinOp(Eng, Op, LL,
|
||||
loc::ConcreteInt(BasicVals.getValue(V)));
|
||||
return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V));
|
||||
}
|
||||
|
||||
default:
|
||||
switch (Op) {
|
||||
case BinaryOperator::EQ:
|
||||
return NonLoc::MakeIntTruthVal(BasicVals, false);
|
||||
return ValMgr.makeTruthVal(false);
|
||||
case BinaryOperator::NE:
|
||||
return NonLoc::MakeIntTruthVal(BasicVals, true);
|
||||
return ValMgr.makeTruthVal(true);
|
||||
default:
|
||||
// This case also handles pointer arithmetic.
|
||||
return UnknownVal();
|
||||
@ -289,7 +288,7 @@ SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state,
|
||||
|
||||
SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
ValueManager& ValMgr = Eng.getValueManager();
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
@ -307,7 +306,7 @@ SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
|
||||
if (!isEqual)
|
||||
b = !b;
|
||||
|
||||
return NonLoc::MakeIntTruthVal(BasicVals, b);
|
||||
return ValMgr.makeTruthVal(b);
|
||||
}
|
||||
else if (SymbolRef Sym = R.getAsSymbol()) {
|
||||
const SymIntExpr * SE =
|
||||
@ -339,10 +338,10 @@ SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
|
||||
// Fall-through.
|
||||
|
||||
case loc::GotoLabelKind:
|
||||
return NonLoc::MakeIntTruthVal(BasicVals, isEqual ? L == R : L != R);
|
||||
return ValMgr.makeTruthVal(isEqual ? L == R : L != R);
|
||||
}
|
||||
|
||||
return NonLoc::MakeIntTruthVal(BasicVals, isEqual ? false : true);
|
||||
return ValMgr.makeTruthVal(isEqual ? false : true);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -367,8 +366,8 @@ void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
|
||||
if (isa<loc::MemRegionVal>(V)) {
|
||||
const MemRegion *R = cast<loc::MemRegionVal>(V).getRegion();
|
||||
if (R->isBoundable(Eng.getContext()))
|
||||
St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
|
||||
if (R->isBoundable())
|
||||
St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
|
||||
} else if (isa<nonloc::LocAsInteger>(V))
|
||||
St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(),
|
||||
UnknownVal());
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MemRegion::~MemRegion() {}
|
||||
|
||||
@ -34,6 +37,19 @@ bool SubRegion::isSubRegionOf(const MemRegion* R) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MemRegionManager* SubRegion::getMemRegionManager() const {
|
||||
const SubRegion* r = this;
|
||||
do {
|
||||
const MemRegion *superRegion = r->getSuperRegion();
|
||||
if (const SubRegion *sr = dyn_cast<SubRegion>(superRegion)) {
|
||||
r = sr;
|
||||
continue;
|
||||
}
|
||||
return superRegion->getMemRegionManager();
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddInteger((unsigned)getKind());
|
||||
}
|
||||
@ -47,14 +63,15 @@ void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
}
|
||||
|
||||
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const Expr* Ex, unsigned cnt) {
|
||||
const Expr* Ex, unsigned cnt,
|
||||
const MemRegion *) {
|
||||
ID.AddInteger((unsigned) AllocaRegionKind);
|
||||
ID.AddPointer(Ex);
|
||||
ID.AddInteger(cnt);
|
||||
}
|
||||
|
||||
void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ProfileRegion(ID, Ex, Cnt);
|
||||
ProfileRegion(ID, Ex, Cnt, superRegion);
|
||||
}
|
||||
|
||||
void TypedViewRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
@ -87,13 +104,15 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
|
||||
}
|
||||
|
||||
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym) {
|
||||
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
|
||||
const MemRegion *sreg) {
|
||||
ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
|
||||
ID.Add(sym);
|
||||
ID.AddPointer(sreg);
|
||||
}
|
||||
|
||||
void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
SymbolicRegion::ProfileRegion(ID, sym);
|
||||
SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
|
||||
}
|
||||
|
||||
void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
@ -110,14 +129,14 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
}
|
||||
|
||||
void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const void* data,
|
||||
QualType t) {
|
||||
QualType t, const MemRegion*) {
|
||||
ID.AddInteger(MemRegion::CodeTextRegionKind);
|
||||
ID.AddPointer(data);
|
||||
ID.Add(t);
|
||||
}
|
||||
|
||||
void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
CodeTextRegion::ProfileRegion(ID, Data, LocationType);
|
||||
CodeTextRegion::ProfileRegion(ID, Data, LocationType, superRegion);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -186,13 +205,12 @@ void VarRegion::print(llvm::raw_ostream& os) const {
|
||||
// MemRegionManager methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
|
||||
|
||||
MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
|
||||
if (!region) {
|
||||
region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
|
||||
new (region) MemSpaceRegion();
|
||||
new (region) MemSpaceRegion(this);
|
||||
}
|
||||
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
@ -216,82 +234,21 @@ MemSpaceRegion* MemRegionManager::getCodeRegion() {
|
||||
return LazyAllocate(code);
|
||||
}
|
||||
|
||||
bool MemRegionManager::onStack(const MemRegion* R) {
|
||||
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
|
||||
R = SR->getSuperRegion();
|
||||
|
||||
return (R != 0) && (R == stack);
|
||||
}
|
||||
|
||||
bool MemRegionManager::onHeap(const MemRegion* R) {
|
||||
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
|
||||
R = SR->getSuperRegion();
|
||||
|
||||
return (R != 0) && (R == heap);
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Constructing regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
MemSpaceRegion* GlobalsR = getGlobalsRegion();
|
||||
|
||||
StringRegion::ProfileRegion(ID, Str, GlobalsR);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
StringRegion* R = cast_or_null<StringRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (StringRegion*) A.Allocate<StringRegion>();
|
||||
new (R) StringRegion(Str, GlobalsR);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<StringRegion>(Str);
|
||||
}
|
||||
|
||||
VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) {
|
||||
|
||||
const MemRegion* superRegion = d->hasLocalStorage() ? getStackRegion()
|
||||
: getGlobalsRegion();
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::VarRegionKind);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
VarRegion* R = cast_or_null<VarRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (VarRegion*) A.Allocate<VarRegion>();
|
||||
new (R) VarRegion(d, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<VarRegion>(d);
|
||||
}
|
||||
|
||||
CompoundLiteralRegion*
|
||||
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
|
||||
// Is this compound literal allocated on the stack or is part of the
|
||||
// global constant pool?
|
||||
const MemRegion* superRegion = CL->isFileScope() ?
|
||||
getGlobalsRegion() : getStackRegion();
|
||||
|
||||
// Profile the compound literal.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
CompoundLiteralRegion* R = cast_or_null<CompoundLiteralRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (CompoundLiteralRegion*) A.Allocate<CompoundLiteralRegion>();
|
||||
new (R) CompoundLiteralRegion(CL, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<CompoundLiteralRegion>(CL);
|
||||
}
|
||||
|
||||
ElementRegion*
|
||||
@ -318,149 +275,45 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
|
||||
|
||||
CodeTextRegion* MemRegionManager::getCodeTextRegion(const FunctionDecl* fd,
|
||||
QualType t) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
CodeTextRegion::ProfileRegion(ID, fd, t);
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
CodeTextRegion* R = cast_or_null<CodeTextRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (CodeTextRegion*) A.Allocate<CodeTextRegion>();
|
||||
new (R) CodeTextRegion(fd, t, getCodeRegion());
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<CodeTextRegion>(fd, t);
|
||||
}
|
||||
|
||||
CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
CodeTextRegion::ProfileRegion(ID, sym, t);
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
CodeTextRegion* R = cast_or_null<CodeTextRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (CodeTextRegion*) A.Allocate<CodeTextRegion>();
|
||||
new (R) CodeTextRegion(sym, t, getCodeRegion());
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<CodeTextRegion>(sym, t);
|
||||
}
|
||||
|
||||
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
|
||||
SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
SymbolicRegion::ProfileRegion(ID, sym);
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
SymbolicRegion* R = cast_or_null<SymbolicRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (SymbolicRegion*) A.Allocate<SymbolicRegion>();
|
||||
// SymbolicRegion's storage class is usually unknown.
|
||||
new (R) SymbolicRegion(sym, getUnknownRegion());
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<SymbolicRegion>(sym);
|
||||
}
|
||||
|
||||
FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
|
||||
const MemRegion* superRegion) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::FieldRegionKind);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
FieldRegion* R = cast_or_null<FieldRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (FieldRegion*) A.Allocate<FieldRegion>();
|
||||
new (R) FieldRegion(d, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<FieldRegion>(d, superRegion);
|
||||
}
|
||||
|
||||
ObjCIvarRegion*
|
||||
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
|
||||
const MemRegion* superRegion) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::ObjCIvarRegionKind);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
ObjCIvarRegion* R = cast_or_null<ObjCIvarRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (ObjCIvarRegion*) A.Allocate<ObjCIvarRegion>();
|
||||
new (R) ObjCIvarRegion(d, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<ObjCIvarRegion>(d, superRegion);
|
||||
}
|
||||
|
||||
ObjCObjectRegion*
|
||||
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
|
||||
const MemRegion* superRegion) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DeclRegion::ProfileRegion(ID, d, superRegion,
|
||||
MemRegion::ObjCObjectRegionKind);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
ObjCObjectRegion* R = cast_or_null<ObjCObjectRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (ObjCObjectRegion*) A.Allocate<ObjCObjectRegion>();
|
||||
new (R) ObjCObjectRegion(d, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
const MemRegion* superRegion) {
|
||||
return getRegion<ObjCObjectRegion>(d, superRegion);
|
||||
}
|
||||
|
||||
TypedViewRegion*
|
||||
MemRegionManager::getTypedViewRegion(QualType t, const MemRegion* superRegion) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
TypedViewRegion::ProfileRegion(ID, t, superRegion);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
TypedViewRegion* R = cast_or_null<TypedViewRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (TypedViewRegion*) A.Allocate<TypedViewRegion>();
|
||||
new (R) TypedViewRegion(t, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<TypedViewRegion>(t, superRegion);
|
||||
}
|
||||
|
||||
AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
AllocaRegion::ProfileRegion(ID, E, cnt);
|
||||
|
||||
void* InsertPos;
|
||||
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
|
||||
AllocaRegion* R = cast_or_null<AllocaRegion>(data);
|
||||
|
||||
if (!R) {
|
||||
R = (AllocaRegion*) A.Allocate<AllocaRegion>();
|
||||
new (R) AllocaRegion(E, cnt, getStackRegion());
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
return R;
|
||||
return getRegion<AllocaRegion>(E, cnt);
|
||||
}
|
||||
|
||||
bool MemRegionManager::hasStackStorage(const MemRegion* R) {
|
||||
|
||||
// Only subregions can have stack storage.
|
||||
const SubRegion* SR = dyn_cast<SubRegion>(R);
|
||||
|
||||
@ -476,10 +329,29 @@ bool MemRegionManager::hasStackStorage(const MemRegion* R) {
|
||||
|
||||
SR = dyn_cast<SubRegion>(R);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemRegionManager::hasHeapStorage(const MemRegion* R) {
|
||||
// Only subregions can have stack storage.
|
||||
const SubRegion* SR = dyn_cast<SubRegion>(R);
|
||||
|
||||
if (!SR)
|
||||
return false;
|
||||
|
||||
MemSpaceRegion* H = getHeapRegion();
|
||||
|
||||
while (SR) {
|
||||
R = SR->getSuperRegion();
|
||||
if (R == H)
|
||||
return true;
|
||||
|
||||
SR = dyn_cast<SubRegion>(R);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// View handling.
|
||||
|
@ -513,7 +513,7 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
|
||||
if (OffI.isUnsigned()) {
|
||||
llvm::APSInt Tmp = OffI;
|
||||
Tmp.setIsSigned(true);
|
||||
Offset = NonLoc::MakeVal(getBasicVals(), Tmp);
|
||||
Offset = ValMgr.makeIntVal(Tmp);
|
||||
}
|
||||
}
|
||||
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
|
||||
@ -547,7 +547,7 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
|
||||
|
||||
Tmp.setIsSigned(true);
|
||||
Tmp += BaseIdxI; // Compute the new offset.
|
||||
NewIdx = NonLoc::MakeVal(getBasicVals(), Tmp);
|
||||
NewIdx = ValMgr.makeIntVal(Tmp);
|
||||
}
|
||||
else
|
||||
NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
|
||||
@ -572,7 +572,7 @@ SVal RegionStoreManager::getSizeInElements(const GRState *state,
|
||||
|
||||
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
|
||||
// return the size as signed integer.
|
||||
return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false);
|
||||
return ValMgr.makeIntVal(CAT->getSize(), false);
|
||||
}
|
||||
|
||||
const QualType* CastTy = state->get<RegionCasts>(VR);
|
||||
@ -585,19 +585,19 @@ SVal RegionStoreManager::getSizeInElements(const GRState *state,
|
||||
uint64_t EleSize = getContext().getTypeSize(EleTy);
|
||||
uint64_t VarSize = getContext().getTypeSize(VarTy);
|
||||
assert(VarSize != 0);
|
||||
return NonLoc::MakeIntVal(getBasicVals(), VarSize / EleSize, false);
|
||||
return ValMgr.makeIntVal(VarSize/EleSize, false);
|
||||
}
|
||||
|
||||
// Clients can use ordinary variables as if they were arrays. These
|
||||
// essentially are arrays of size 1.
|
||||
return NonLoc::MakeIntVal(getBasicVals(), 1, false);
|
||||
return ValMgr.makeIntVal(1, false);
|
||||
}
|
||||
|
||||
if (const StringRegion* SR = dyn_cast<StringRegion>(R)) {
|
||||
const StringLiteral* Str = SR->getStringLiteral();
|
||||
// We intentionally made the size value signed because it participates in
|
||||
// operations with signed indices.
|
||||
return NonLoc::MakeIntVal(getBasicVals(), Str->getByteLength()+1, false);
|
||||
return ValMgr.makeIntVal(Str->getByteLength()+1, false);
|
||||
}
|
||||
|
||||
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) {
|
||||
@ -676,7 +676,9 @@ RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R,
|
||||
|
||||
// CodeTextRegion should be cast to only function pointer type.
|
||||
if (isa<CodeTextRegion>(R)) {
|
||||
assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType());
|
||||
assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType()
|
||||
|| (CastToTy->isPointerType()
|
||||
&& CastToTy->getAsPointerType()->getPointeeType()->isVoidType()));
|
||||
return CastResult(state, R);
|
||||
}
|
||||
|
||||
@ -800,7 +802,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||
const MemRegion* NewER =
|
||||
MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
|
||||
getContext());
|
||||
return Loc::MakeVal(NewER);
|
||||
return ValMgr.makeLoc(NewER);
|
||||
|
||||
}
|
||||
|
||||
@ -937,7 +939,7 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
}
|
||||
}
|
||||
|
||||
if (MRMgr.onStack(R) || MRMgr.onHeap(R)) {
|
||||
if (MRMgr.hasStackStorage(R) || MRMgr.hasHeapStorage(R)) {
|
||||
// All stack variables are considered to have undefined values
|
||||
// upon creation. All heap allocated blocks are considered to
|
||||
// have undefined values as well unless they are explicitly bound
|
||||
@ -984,7 +986,7 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state,
|
||||
StructVal = getBasicVals().consVals(FieldValue, StructVal);
|
||||
}
|
||||
|
||||
return NonLoc::MakeCompoundVal(T, StructVal, getBasicVals());
|
||||
return ValMgr.makeCompoundVal(T, StructVal);
|
||||
}
|
||||
|
||||
SVal RegionStoreManager::RetrieveArray(const GRState *state,
|
||||
@ -998,7 +1000,7 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
|
||||
llvm::APSInt i = getBasicVals().getZeroWithPtrWidth(false);
|
||||
|
||||
for (; i < Size; ++i) {
|
||||
SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
|
||||
SVal Idx = ValMgr.makeIntVal(i);
|
||||
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
|
||||
getContext());
|
||||
QualType ETy = ER->getElementType();
|
||||
@ -1006,7 +1008,7 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
|
||||
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
|
||||
}
|
||||
|
||||
return NonLoc::MakeCompoundVal(T, ArrayVal, getBasicVals());
|
||||
return ValMgr.makeCompoundVal(T, ArrayVal);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1059,7 +1061,7 @@ const GRState *RegionStoreManager::BindDecl(const GRState *state,
|
||||
if (T->isStructureType())
|
||||
return BindStruct(state, VR, InitVal);
|
||||
|
||||
return Bind(state, Loc::MakeVal(VR), InitVal);
|
||||
return Bind(state, ValMgr.makeLoc(VR), InitVal);
|
||||
}
|
||||
|
||||
// FIXME: this method should be merged into Bind().
|
||||
@ -1077,17 +1079,11 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
|
||||
SVal Init) {
|
||||
|
||||
QualType T = R->getValueType(getContext());
|
||||
assert(T->isArrayType());
|
||||
|
||||
// When we are binding the whole array, it always has default value 0.
|
||||
state = state->set<RegionDefaultValue>(R, NonLoc::MakeIntVal(getBasicVals(),
|
||||
0, false));
|
||||
|
||||
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
|
||||
QualType ElementTy = CAT->getElementType();
|
||||
|
||||
llvm::APSInt Size(CAT->getSize(), false);
|
||||
llvm::APSInt i = getBasicVals().getValue(0, Size.getBitWidth(),
|
||||
Size.isUnsigned());
|
||||
llvm::APSInt i(llvm::APInt::getNullValue(Size.getBitWidth()), false);
|
||||
|
||||
// Check if the init expr is a StringLiteral.
|
||||
if (isa<loc::MemRegionVal>(Init)) {
|
||||
@ -1104,12 +1100,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
|
||||
if (j >= len)
|
||||
break;
|
||||
|
||||
SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
|
||||
ElementRegion* ER =
|
||||
MRMgr.getElementRegion(cast<ArrayType>(T)->getElementType(),
|
||||
Idx, R, getContext());
|
||||
SVal Idx = ValMgr.makeIntVal(i);
|
||||
ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
|
||||
|
||||
SVal V = NonLoc::MakeVal(getBasicVals(), str[j], sizeof(char)*8, true);
|
||||
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
|
||||
state = Bind(state, loc::MemRegionVal(ER), V);
|
||||
}
|
||||
|
||||
@ -1120,19 +1114,29 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
|
||||
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
|
||||
|
||||
for (; i < Size; ++i, ++VI) {
|
||||
// The init list might be shorter than the array decl.
|
||||
// The init list might be shorter than the array length.
|
||||
if (VI == VE)
|
||||
break;
|
||||
|
||||
SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
|
||||
ElementRegion* ER =
|
||||
MRMgr.getElementRegion(cast<ArrayType>(T)->getElementType(),
|
||||
Idx, R, getContext());
|
||||
SVal Idx = ValMgr.makeIntVal(i);
|
||||
ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
|
||||
|
||||
if (CAT->getElementType()->isStructureType())
|
||||
state = BindStruct(state, ER, *VI);
|
||||
else
|
||||
state = Bind(state, Loc::MakeVal(ER), *VI);
|
||||
state = Bind(state, ValMgr.makeLoc(ER), *VI);
|
||||
}
|
||||
|
||||
// If the init list is shorter than the array length, bind the rest elements
|
||||
// to 0.
|
||||
if (ElementTy->isIntegerType()) {
|
||||
while (i < Size) {
|
||||
SVal Idx = ValMgr.makeIntVal(i);
|
||||
ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
|
||||
SVal V = ValMgr.makeZeroVal(ElementTy);
|
||||
state = Bind(state, ValMgr.makeLoc(ER), V);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
@ -1161,30 +1165,37 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
|
||||
|
||||
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
|
||||
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
|
||||
|
||||
for (RecordDecl::field_iterator FI = RD->field_begin(getContext()),
|
||||
FE = RD->field_end(getContext());
|
||||
|
||||
RecordDecl::field_iterator FI, FE;
|
||||
|
||||
for (FI = RD->field_begin(getContext()), FE = RD->field_end(getContext());
|
||||
FI != FE; ++FI, ++VI) {
|
||||
|
||||
// There may be fewer values than fields only when we are initializing a
|
||||
// struct decl. In this case, mark the region as having default value.
|
||||
if (VI == VE) {
|
||||
const NonLoc& Idx = NonLoc::MakeIntVal(getBasicVals(), 0, false);
|
||||
state = state->set<RegionDefaultValue>(R, Idx);
|
||||
if (VI == VE)
|
||||
break;
|
||||
}
|
||||
|
||||
QualType FTy = (*FI)->getType();
|
||||
FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
|
||||
|
||||
if (Loc::IsLocType(FTy) || FTy->isIntegerType())
|
||||
state = Bind(state, Loc::MakeVal(FR), *VI);
|
||||
state = Bind(state, ValMgr.makeLoc(FR), *VI);
|
||||
else if (FTy->isArrayType())
|
||||
state = BindArray(state, FR, *VI);
|
||||
else if (FTy->isStructureType())
|
||||
state = BindStruct(state, FR, *VI);
|
||||
}
|
||||
|
||||
// There may be fewer values in the initialize list than the fields of struct.
|
||||
while (FI != FE) {
|
||||
QualType FTy = (*FI)->getType();
|
||||
if (FTy->isIntegerType()) {
|
||||
FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
|
||||
state = Bind(state, ValMgr.makeLoc(FR), ValMgr.makeZeroVal(FTy));
|
||||
}
|
||||
|
||||
++FI;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -1202,7 +1213,7 @@ const GRState *RegionStoreManager::KillStruct(const GRState *state,
|
||||
const MemRegion* R = I.getKey();
|
||||
if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
|
||||
if (subRegion->isSubRegionOf(R))
|
||||
store = Remove(store, Loc::MakeVal(subRegion));
|
||||
store = Remove(store, ValMgr.makeLoc(subRegion));
|
||||
// FIXME: Maybe we should also remove the bindings for the "views" of the
|
||||
// subregions.
|
||||
}
|
||||
@ -1398,7 +1409,7 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
|
||||
continue;
|
||||
|
||||
// Remove this dead region from the store.
|
||||
store = Remove(store, Loc::MakeVal(R));
|
||||
store = Remove(store, ValMgr.makeLoc(R));
|
||||
|
||||
// Mark all non-live symbols that this region references as dead.
|
||||
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
|
||||
|
@ -236,180 +236,6 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
|
||||
return UndefinedVal();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing SVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal ValueManager::makeZeroVal(QualType T) {
|
||||
if (Loc::IsLocType(T))
|
||||
return Loc::MakeNull(BasicVals);
|
||||
|
||||
if (T->isIntegerType())
|
||||
return NonLoc::MakeVal(BasicVals, 0, T);
|
||||
|
||||
// FIXME: Handle floats.
|
||||
// FIXME: Handle structs.
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::makeZeroArrayIndex() {
|
||||
return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing Non-Locs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
NonLoc ValueManager::makeNonLoc(SymbolRef sym) {
|
||||
return nonloc::SymbolVal(sym);
|
||||
}
|
||||
|
||||
NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const APSInt& v, QualType T) {
|
||||
// The Environment ensures we always get a persistent APSInt in
|
||||
// BasicValueFactory, so we don't need to get the APSInt from
|
||||
// BasicValueFactory again.
|
||||
assert(!Loc::IsLocType(T));
|
||||
return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T));
|
||||
}
|
||||
|
||||
NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const SymExpr *rhs, QualType T) {
|
||||
assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
|
||||
assert(!Loc::IsLocType(T));
|
||||
return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
|
||||
bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X,
|
||||
unsigned BitWidth, bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(X, T));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const IntegerLiteral* I) {
|
||||
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(APSInt(I->getValue(),
|
||||
I->getType()->isUnsignedIntegerType())));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
|
||||
bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(I, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(I));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) {
|
||||
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
|
||||
}
|
||||
|
||||
NonLoc ValueManager::makeTruthVal(bool b, QualType T) {
|
||||
return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
|
||||
}
|
||||
|
||||
NonLoc NonLoc::MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
|
||||
BasicValueFactory& BasicVals) {
|
||||
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
|
||||
}
|
||||
|
||||
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) {
|
||||
SymbolRef sym = SymMgr.getRegionValueSymbol(R, T);
|
||||
|
||||
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
|
||||
if (T.isNull())
|
||||
T = TR->getValueType(SymMgr.getContext());
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
// Only handle integers for now.
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return makeNonLoc(sym);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) {
|
||||
QualType T = E->getType();
|
||||
SymbolRef sym = SymMgr.getConjuredSymbol(E, Count);
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return makeNonLoc(sym);
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getConjuredSymbolVal(const Expr* E, QualType T,
|
||||
unsigned Count) {
|
||||
|
||||
SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count);
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return makeNonLoc(sym);
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
|
||||
CodeTextRegion* R
|
||||
= MemMgr.getCodeTextRegion(FD, Context.getPointerType(FD->getType()));
|
||||
return loc::MemRegionVal(R);
|
||||
}
|
||||
|
||||
nonloc::LocAsInteger nonloc::LocAsInteger::Make(BasicValueFactory& Vals, Loc V,
|
||||
unsigned Bits) {
|
||||
return LocAsInteger(Vals.getPersistentSValWithData(V, Bits));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing Locs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Loc Loc::MakeVal(const MemRegion* R) { return loc::MemRegionVal(R); }
|
||||
|
||||
Loc Loc::MakeVal(const AddrLabelExpr *E) {
|
||||
return loc::GotoLabel(E->getLabel());
|
||||
}
|
||||
|
||||
Loc Loc::MakeNull(BasicValueFactory &BasicVals) {
|
||||
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pretty-Printing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
125
lib/Analysis/ValueManager.cpp
Normal file
125
lib/Analysis/ValueManager.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
//== ValueManager.cpp - Aggregate manager of symbols and SVals --*- C++ -*--==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines ValueManager, a class that manages symbolic values
|
||||
// and SVals created for use by GRExprEngine and related classes. It
|
||||
// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/ValueManager.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing SVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal ValueManager::makeZeroVal(QualType T) {
|
||||
if (Loc::IsLocType(T))
|
||||
return makeNull();
|
||||
|
||||
if (T->isIntegerType())
|
||||
return makeIntVal(0, T);
|
||||
|
||||
// FIXME: Handle floats.
|
||||
// FIXME: Handle structs.
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing Non-Locs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const APSInt& v, QualType T) {
|
||||
// The Environment ensures we always get a persistent APSInt in
|
||||
// BasicValueFactory, so we don't need to get the APSInt from
|
||||
// BasicValueFactory again.
|
||||
assert(!Loc::IsLocType(T));
|
||||
return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T));
|
||||
}
|
||||
|
||||
NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
|
||||
const SymExpr *rhs, QualType T) {
|
||||
assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
|
||||
assert(!Loc::IsLocType(T));
|
||||
return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T));
|
||||
}
|
||||
|
||||
|
||||
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) {
|
||||
SymbolRef sym = SymMgr.getRegionValueSymbol(R, T);
|
||||
|
||||
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
|
||||
if (T.isNull())
|
||||
T = TR->getValueType(SymMgr.getContext());
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
// Only handle integers for now.
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return nonloc::SymbolVal(sym);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) {
|
||||
QualType T = E->getType();
|
||||
SymbolRef sym = SymMgr.getConjuredSymbol(E, Count);
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return nonloc::SymbolVal(sym);
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getConjuredSymbolVal(const Expr* E, QualType T,
|
||||
unsigned Count) {
|
||||
|
||||
SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count);
|
||||
|
||||
// If T is of function pointer type, create a CodeTextRegion wrapping a
|
||||
// symbol.
|
||||
if (T->isFunctionPointerType()) {
|
||||
return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T));
|
||||
}
|
||||
|
||||
if (Loc::IsLocType(T))
|
||||
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
if (T->isIntegerType() && T->isScalarType())
|
||||
return nonloc::SymbolVal(sym);
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
|
||||
CodeTextRegion* R
|
||||
= MemMgr.getCodeTextRegion(FD, Context.getPointerType(FD->getType()));
|
||||
return loc::MemRegionVal(R);
|
||||
}
|
@ -373,7 +373,10 @@ FileID SourceManager::createFileID(const ContentCache *File,
|
||||
|
||||
// Set LastFileIDLookup to the newly created file. The next getFileID call is
|
||||
// almost guaranteed to be from that file.
|
||||
return LastFileIDLookup = FileID::get(SLocEntryTable.size()-1);
|
||||
FileID FID = FileID::get(SLocEntryTable.size()-1);
|
||||
if (File->FirstFID.isInvalid())
|
||||
File->FirstFID = FID;
|
||||
return LastFileIDLookup = FID;
|
||||
}
|
||||
|
||||
/// createInstantiationLoc - Return a new SourceLocation that encodes the fact
|
||||
|
@ -169,6 +169,7 @@ static bool getDarwinNumber(const char *Triple, unsigned &Maj, unsigned &Min, un
|
||||
}
|
||||
|
||||
static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
|
||||
Define(Defs, "__APPLE_CC__", "5621");
|
||||
Define(Defs, "__APPLE__");
|
||||
Define(Defs, "__MACH__");
|
||||
Define(Defs, "OBJC_NEW_PROPERTIES");
|
||||
|
@ -763,7 +763,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
if (CE->getOpcode() == llvm::Instruction::BitCast &&
|
||||
ActualFT->getReturnType() == CurFT->getReturnType() &&
|
||||
ActualFT->getNumParams() == CurFT->getNumParams()) {
|
||||
ActualFT->getNumParams() == CurFT->getNumParams() &&
|
||||
ActualFT->getNumParams() == Args.size()) {
|
||||
bool ArgsMatch = true;
|
||||
for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i)
|
||||
if (ActualFT->getParamType(i) != CurFT->getParamType(i)) {
|
||||
|
@ -232,7 +232,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
|
||||
DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend
|
||||
|
||||
// Currently claim to be compatible with GCC 4.2.1-5621.
|
||||
DefineBuiltinMacro(Buf, "__APPLE_CC__=5621");
|
||||
DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
|
||||
DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
|
||||
DefineBuiltinMacro(Buf, "__GNUC__=4");
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Sema/SemaDiagnostic.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
@ -99,7 +100,8 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
|
||||
}
|
||||
|
||||
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
|
||||
fprintf(stderr, "warning: unknown warning option: -W%s\n", Opt.c_str());
|
||||
Diags.Report(FullSourceLoc(), diag::warn_unknown_warning_option)
|
||||
<< ("-W" + Opt);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -473,13 +473,14 @@ char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
|
||||
// Common case, backslash-char where the char is not whitespace.
|
||||
if (!isWhitespace(Ptr[0])) return '\\';
|
||||
|
||||
// See if we have optional whitespace characters followed by a newline.
|
||||
// See if we have optional whitespace characters between the slash and
|
||||
// newline.
|
||||
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
|
||||
// Remember that this token needs to be cleaned.
|
||||
if (Tok) Tok->setFlag(Token::NeedsCleaning);
|
||||
|
||||
// Warn if there was whitespace between the backslash and newline.
|
||||
if (EscapedNewLineSize != 1 && Tok && !isLexingRawMode())
|
||||
if (Ptr[0] != '\n' && Ptr[0] != '\r' && Tok && !isLexingRawMode())
|
||||
Diag(Ptr, diag::backslash_newline_space);
|
||||
|
||||
// Found backslash<whitespace><newline>. Parse the char after it.
|
||||
|
@ -273,7 +273,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
|
||||
/// [C++] template-declaration
|
||||
/// [C++] namespace-definition
|
||||
/// [C++] using-directive
|
||||
/// [C++] using-declaration [TODO]
|
||||
/// [C++] using-declaration
|
||||
/// [C++0x] static_assert-declaration
|
||||
/// others... [FIXME]
|
||||
///
|
||||
|
@ -279,7 +279,8 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
|
||||
// C++ [basic.def.odr]p2:
|
||||
// An expression is potentially evaluated unless it appears where an
|
||||
// integral constant expression is required (see 5.19) [...].
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Action::Unevaluated);
|
||||
|
||||
OwningExprResult LHS(ParseCastExpression(false));
|
||||
if (LHS.isInvalid()) return move(LHS);
|
||||
@ -983,7 +984,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
|
||||
//
|
||||
// The GNU typeof and alignof extensions also behave as unevaluated
|
||||
// operands.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Action::Unevaluated);
|
||||
Operand = ParseCastExpression(true/*isUnaryExpression*/);
|
||||
} else {
|
||||
// If it starts with a '(', we know that it is either a parenthesized
|
||||
@ -999,7 +1001,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
|
||||
//
|
||||
// The GNU typeof and alignof extensions also behave as unevaluated
|
||||
// operands.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Action::Unevaluated);
|
||||
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
|
||||
CastTy, RParenLoc);
|
||||
CastRange = SourceRange(LParenLoc, RParenLoc);
|
||||
|
@ -384,10 +384,9 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() {
|
||||
//
|
||||
// Note that we can't tell whether the expression is an lvalue of a
|
||||
// polymorphic class type until after we've parsed the expression, so
|
||||
// we treat the expression as an unevaluated operand and let semantic
|
||||
// analysis cope with case where the expression is not an unevaluated
|
||||
// operand.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
// we the expression is potentially potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Action::PotentiallyPotentiallyEvaluated);
|
||||
Result = ParseExpression();
|
||||
|
||||
// Match the ')'.
|
||||
|
@ -750,7 +750,7 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
|
||||
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
|
||||
///
|
||||
/// template-argument: [C++ 14.2]
|
||||
/// assignment-expression
|
||||
/// constant-expression
|
||||
/// type-id
|
||||
/// id-expression
|
||||
void *Parser::ParseTemplateArgument(bool &ArgIsType) {
|
||||
@ -768,7 +768,7 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
|
||||
return TypeArg.get();
|
||||
}
|
||||
|
||||
OwningExprResult ExprArg = ParseAssignmentExpression();
|
||||
OwningExprResult ExprArg = ParseConstantExpression();
|
||||
if (ExprArg.isInvalid() || !ExprArg.get())
|
||||
return 0;
|
||||
|
||||
|
@ -182,7 +182,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
||||
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
|
||||
ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
|
||||
CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
|
||||
GlobalNewDeleteDeclared(false), InUnevaluatedOperand(false),
|
||||
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
|
||||
CompleteTranslationUnit(CompleteTranslationUnit),
|
||||
NumSFINAEErrors(0), CurrentInstantiationScope(0) {
|
||||
|
||||
@ -235,6 +235,18 @@ void Sema::DeleteStmt(StmtTy *S) {
|
||||
/// translation unit when EOF is reached and all but the top-level scope is
|
||||
/// popped.
|
||||
void Sema::ActOnEndOfTranslationUnit() {
|
||||
// C++: Perform implicit template instantiations.
|
||||
//
|
||||
// FIXME: When we perform these implicit instantiations, we do not carefully
|
||||
// keep track of the point of instantiation (C++ [temp.point]). This means
|
||||
// that name lookup that occurs within the template instantiation will
|
||||
// always happen at the end of the translation unit, so it will find
|
||||
// some names that should not be found. Although this is common behavior
|
||||
// for C++ compilers, it is technically wrong. In the future, we either need
|
||||
// to be able to filter the results of name lookup or we need to perform
|
||||
// template instantiations earlier.
|
||||
PerformPendingImplicitInstantiations();
|
||||
|
||||
if (!CompleteTranslationUnit)
|
||||
return;
|
||||
|
||||
|
@ -29,7 +29,9 @@
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -247,11 +249,18 @@ class Sema : public Action {
|
||||
/// have been declared.
|
||||
bool GlobalNewDeleteDeclared;
|
||||
|
||||
/// A flag that indicates when we are processing an unevaluated operand
|
||||
/// (C++0x [expr]). C99 has the same notion of declarations being
|
||||
/// "used" and C++03 has the notion of "potentially evaluated", but we
|
||||
/// adopt the C++0x terminology since it is most precise.
|
||||
bool InUnevaluatedOperand;
|
||||
/// The current expression evaluation context.
|
||||
ExpressionEvaluationContext ExprEvalContext;
|
||||
|
||||
typedef std::vector<std::pair<SourceLocation, Decl *> >
|
||||
PotentiallyReferencedDecls;
|
||||
|
||||
/// A stack of declarations, each element of which is a set of declarations
|
||||
/// that will be marked as referenced if the corresponding potentially
|
||||
/// potentially evaluated expression is potentially evaluated. Each element
|
||||
/// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression
|
||||
/// evaluation context.
|
||||
std::list<PotentiallyReferencedDecls> PotentiallyReferencedDeclStack;
|
||||
|
||||
/// \brief Whether the code handled by Sema should be considered a
|
||||
/// complete translation unit or not.
|
||||
@ -1334,12 +1343,13 @@ class Sema : public Action {
|
||||
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
|
||||
Expr **Args, unsigned NumArgs);
|
||||
|
||||
virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) {
|
||||
bool Result = InUnevaluatedOperand;
|
||||
InUnevaluatedOperand = UnevaluatedOperand;
|
||||
return Result;
|
||||
}
|
||||
|
||||
virtual ExpressionEvaluationContext
|
||||
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
|
||||
|
||||
virtual void
|
||||
PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
|
||||
ExpressionEvaluationContext NewContext);
|
||||
|
||||
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
|
||||
|
||||
// Primary Expressions.
|
||||
@ -1572,10 +1582,16 @@ class Sema : public Action {
|
||||
QualType DeclInitType,
|
||||
Expr **Exprs, unsigned NumExprs);
|
||||
|
||||
/// DefineImplicitDefaultConstructor - Checks for feasibilityt of
|
||||
/// DefineImplicitDefaultConstructor - Checks for feasibility of
|
||||
/// defining this constructor as the default constructor.
|
||||
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *Constructor);
|
||||
|
||||
/// DefineImplicitCopyConstructor - Checks for feasibility of
|
||||
/// defining this constructor as the copy constructor.
|
||||
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *Constructor,
|
||||
unsigned TypeQuals);
|
||||
|
||||
/// MaybeBindToTemporary - If the passed in expression has a record type with
|
||||
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
|
||||
@ -2495,6 +2511,22 @@ class Sema : public Action {
|
||||
/// variables.
|
||||
LocalInstantiationScope *CurrentInstantiationScope;
|
||||
|
||||
/// \brief An entity for which implicit template instantiation is required.
|
||||
///
|
||||
/// The source location associated with the declaration is the first place in
|
||||
/// the source code where the declaration was "used". It is not necessarily
|
||||
/// the point of instantiation (which will be either before or after the
|
||||
/// namespace-scope declaration that triggered this implicit instantiation),
|
||||
/// However, it is the location that diagnostics should generally refer to,
|
||||
/// because users will need to know what code triggered the instantiation.
|
||||
typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation;
|
||||
|
||||
/// \brief The queue of implicit template instantiations that are required
|
||||
/// but have not yet been performed.
|
||||
std::queue<PendingImplicitInstantiation> PendingImplicitInstantiations;
|
||||
|
||||
void PerformPendingImplicitInstantiations();
|
||||
|
||||
QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc, DeclarationName Entity);
|
||||
|
||||
@ -2550,7 +2582,7 @@ class Sema : public Action {
|
||||
void InstantiateVariableDefinition(VarDecl *Var);
|
||||
|
||||
NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
|
||||
|
||||
|
||||
// Simple function for cloning expressions.
|
||||
template<typename T>
|
||||
OwningExprResult Clone(T *E) {
|
||||
|
@ -2733,12 +2733,9 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
|
||||
IK_Default);
|
||||
if (!Constructor)
|
||||
Var->setInvalidDecl();
|
||||
else {
|
||||
else
|
||||
if (!RD->hasTrivialConstructor())
|
||||
InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
|
||||
// Check for valid construction.
|
||||
DefineImplicitDefaultConstructor(Var->getLocation(), Constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,9 @@ namespace {
|
||||
void
|
||||
Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
|
||||
ExprArg defarg) {
|
||||
if (!param || !defarg.get())
|
||||
return;
|
||||
|
||||
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
|
||||
UnparsedDefaultArgLocs.erase(Param);
|
||||
|
||||
@ -161,6 +164,9 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
|
||||
void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
|
||||
SourceLocation EqualLoc,
|
||||
SourceLocation ArgLoc) {
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
|
||||
if (Param)
|
||||
Param->setUnparsedDefaultArg();
|
||||
@ -171,6 +177,9 @@ void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
|
||||
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
|
||||
/// the default argument for the parameter param failed.
|
||||
void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) {
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
|
||||
|
||||
Param->setInvalidDecl();
|
||||
@ -415,6 +424,9 @@ Sema::BaseResult
|
||||
Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
|
||||
bool Virtual, AccessSpecifier Access,
|
||||
TypeTy *basetype, SourceLocation BaseLoc) {
|
||||
if (!classdecl)
|
||||
return true;
|
||||
|
||||
AdjustDeclIfTemplate(classdecl);
|
||||
CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>());
|
||||
QualType BaseType = QualType::getFromOpaquePtr(basetype);
|
||||
@ -640,6 +652,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
if (!ConstructorD)
|
||||
return true;
|
||||
|
||||
CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>());
|
||||
if (!Constructor) {
|
||||
@ -741,8 +756,11 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
|
||||
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
|
||||
SourceLocation ColonLoc,
|
||||
MemInitTy **MemInits, unsigned NumMemInits) {
|
||||
CXXConstructorDecl *Constructor =
|
||||
dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
|
||||
if (!ConstructorDecl)
|
||||
return;
|
||||
|
||||
CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
|
||||
|
||||
if (!Constructor) {
|
||||
Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
|
||||
@ -957,6 +975,9 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
||||
DeclPtrTy TagDecl,
|
||||
SourceLocation LBrac,
|
||||
SourceLocation RBrac) {
|
||||
if (!TagDecl)
|
||||
return;
|
||||
|
||||
AdjustDeclIfTemplate(TagDecl);
|
||||
ActOnFields(S, RLoc, TagDecl,
|
||||
(DeclPtrTy*)FieldCollector->getCurFields(),
|
||||
@ -1238,6 +1259,9 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
|
||||
/// name. However, it should not bring the parameters into scope;
|
||||
/// that will be performed by ActOnDelayedCXXMethodParameter.
|
||||
void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
|
||||
if (!MethodD)
|
||||
return;
|
||||
|
||||
CXXScopeSpec SS;
|
||||
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
|
||||
QualType ClassTy
|
||||
@ -1253,6 +1277,9 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
|
||||
/// the method declaration. For example, we could see an
|
||||
/// ActOnParamDefaultArgument event for this parameter.
|
||||
void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
|
||||
if (!ParamD)
|
||||
return;
|
||||
|
||||
ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>());
|
||||
|
||||
// If this parameter has an unparsed default argument, clear it out
|
||||
@ -1272,6 +1299,9 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
|
||||
/// immediately!) for this method, if it was also defined inside the
|
||||
/// class body.
|
||||
void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
|
||||
if (!MethodD)
|
||||
return;
|
||||
|
||||
FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
|
||||
CXXScopeSpec SS;
|
||||
QualType ClassTy
|
||||
@ -1842,13 +1872,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
|
||||
|
||||
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *Constructor) {
|
||||
if (!Constructor->isDefaultConstructor() ||
|
||||
!Constructor->isImplicit() || Constructor->isImplicitMustBeDefined())
|
||||
return;
|
||||
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
|
||||
!Constructor->isUsed()) &&
|
||||
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
|
||||
|
||||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(Constructor->getDeclContext());
|
||||
assert(ClassDecl && "InitializeVarWithConstructor - invalid constructor");
|
||||
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
|
||||
// Before the implicitly-declared default constructor for a class is
|
||||
// implicitly defined, all the implicitly-declared default constructors
|
||||
// for its base class and its non-static data members shall have been
|
||||
@ -1861,8 +1891,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
if (!BaseClassDecl->hasTrivialConstructor()) {
|
||||
if (CXXConstructorDecl *BaseCtor =
|
||||
BaseClassDecl->getDefaultConstructor(Context)) {
|
||||
if (BaseCtor->isImplicit())
|
||||
BaseCtor->setImplicitMustBeDefined();
|
||||
if (BaseCtor->isImplicit() && !BaseCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
|
||||
}
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
@ -1886,8 +1916,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
if (!FieldClassDecl->hasTrivialConstructor())
|
||||
if (CXXConstructorDecl *FieldCtor =
|
||||
FieldClassDecl->getDefaultConstructor(Context)) {
|
||||
if (FieldCtor->isImplicit())
|
||||
FieldCtor->setImplicitMustBeDefined();
|
||||
if (FieldCtor->isImplicit() && !FieldCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
|
||||
}
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
@ -1912,7 +1942,49 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
Constructor->setImplicitMustBeDefined();
|
||||
Constructor->setUsed();
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *CopyConstructor,
|
||||
unsigned TypeQuals) {
|
||||
assert((CopyConstructor->isImplicit() &&
|
||||
CopyConstructor->isCopyConstructor(Context, TypeQuals) &&
|
||||
!CopyConstructor->isUsed()) &&
|
||||
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
|
||||
|
||||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
|
||||
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
|
||||
// Before the implicitly-declared copy constructor for a class is
|
||||
// implicitly defined, all the implicitly-declared copy constructors
|
||||
// for its base class and its non-static data members shall have been
|
||||
// implicitly defined.
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
|
||||
Base != ClassDecl->bases_end(); ++Base) {
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
|
||||
if (CXXConstructorDecl *BaseCopyCtor =
|
||||
BaseClassDecl->getCopyConstructor(Context, TypeQuals))
|
||||
if (BaseCopyCtor->isImplicit() && !BaseCopyCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
|
||||
}
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
|
||||
Field != ClassDecl->field_end(Context);
|
||||
++Field) {
|
||||
QualType FieldType = Context.getCanonicalType((*Field)->getType());
|
||||
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
|
||||
FieldType = Array->getElementType();
|
||||
if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
if (CXXConstructorDecl *FieldCopyCtor =
|
||||
FieldClassDecl->getCopyConstructor(Context, TypeQuals))
|
||||
if (FieldCopyCtor->isImplicit() && !FieldCopyCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
|
||||
}
|
||||
}
|
||||
CopyConstructor->setUsed();
|
||||
}
|
||||
|
||||
void Sema::InitializeVarWithConstructor(VarDecl *VD,
|
||||
@ -1921,6 +1993,7 @@ void Sema::InitializeVarWithConstructor(VarDecl *VD,
|
||||
Expr **Exprs, unsigned NumExprs) {
|
||||
Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor,
|
||||
false, Exprs, NumExprs);
|
||||
MarkDeclarationReferenced(VD->getLocation(), Constructor);
|
||||
VD->setInit(Context, Temp);
|
||||
}
|
||||
|
||||
@ -1990,9 +2063,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
|
||||
VDecl->setCXXDirectInitializer(true);
|
||||
InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
|
||||
(Expr**)Exprs.release(), NumExprs);
|
||||
// An implicitly-declared default constructor for a class is implicitly
|
||||
// defined when it is used to creat an object of its class type.
|
||||
DefineImplicitDefaultConstructor(VDecl->getLocation(), Constructor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2134,25 +2134,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||
MemberType = MemberType.getQualifiedType(combinedQualifiers);
|
||||
}
|
||||
|
||||
MarkDeclarationReferenced(MemberLoc, FD);
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
|
||||
MemberLoc, MemberType));
|
||||
}
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl))
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
||||
Var, MemberLoc,
|
||||
Var->getType().getNonReferenceType()));
|
||||
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl))
|
||||
}
|
||||
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
||||
MemberFn, MemberLoc,
|
||||
MemberFn->getType()));
|
||||
}
|
||||
if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(MemberDecl))
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
|
||||
MemberLoc, Context.OverloadTy));
|
||||
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl))
|
||||
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
|
||||
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
||||
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
||||
Enum, MemberLoc, Enum->getType()));
|
||||
}
|
||||
if (isa<TypeDecl>(MemberDecl))
|
||||
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
|
||||
<< DeclarationName(&Member) << int(OpKind == tok::arrow));
|
||||
@ -5432,6 +5439,35 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
|
||||
return false;
|
||||
}
|
||||
|
||||
Sema::ExpressionEvaluationContext
|
||||
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
|
||||
// Introduce a new set of potentially referenced declarations to the stack.
|
||||
if (NewContext == PotentiallyPotentiallyEvaluated)
|
||||
PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
|
||||
|
||||
std::swap(ExprEvalContext, NewContext);
|
||||
return NewContext;
|
||||
}
|
||||
|
||||
void
|
||||
Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
|
||||
ExpressionEvaluationContext NewContext) {
|
||||
ExprEvalContext = NewContext;
|
||||
|
||||
if (OldContext == PotentiallyPotentiallyEvaluated) {
|
||||
// Mark any remaining declarations in the current position of the stack
|
||||
// as "referenced". If they were not meant to be referenced, semantic
|
||||
// analysis would have eliminated them (e.g., in ActOnCXXTypeId).
|
||||
PotentiallyReferencedDecls RemainingDecls;
|
||||
RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
|
||||
PotentiallyReferencedDeclStack.pop_back();
|
||||
|
||||
for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
|
||||
IEnd = RemainingDecls.end();
|
||||
I != IEnd; ++I)
|
||||
MarkDeclarationReferenced(I->first, I->second);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Note that the given declaration was referenced in the source code.
|
||||
///
|
||||
@ -5446,6 +5482,9 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
|
||||
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
||||
assert(D && "No declaration?");
|
||||
|
||||
if (D->isUsed())
|
||||
return;
|
||||
|
||||
// Mark a parameter declaration "used", regardless of whether we're in a
|
||||
// template or not.
|
||||
if (isa<ParmVarDecl>(D))
|
||||
@ -5456,18 +5495,55 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
||||
if (CurContext->isDependentContext())
|
||||
return;
|
||||
|
||||
// If we are in an unevaluated operand, don't mark any definitions as used.
|
||||
if (InUnevaluatedOperand)
|
||||
return;
|
||||
|
||||
switch (ExprEvalContext) {
|
||||
case Unevaluated:
|
||||
// We are in an expression that is not potentially evaluated; do nothing.
|
||||
return;
|
||||
|
||||
case PotentiallyEvaluated:
|
||||
// We are in a potentially-evaluated expression, so this declaration is
|
||||
// "used"; handle this below.
|
||||
break;
|
||||
|
||||
case PotentiallyPotentiallyEvaluated:
|
||||
// We are in an expression that may be potentially evaluated; queue this
|
||||
// declaration reference until we know whether the expression is
|
||||
// potentially evaluated.
|
||||
PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that this declaration has been used.
|
||||
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
unsigned TypeQuals;
|
||||
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
|
||||
if (!Constructor->isUsed())
|
||||
DefineImplicitDefaultConstructor(Loc, Constructor);
|
||||
}
|
||||
else if (Constructor->isImplicit() &&
|
||||
Constructor->isCopyConstructor(Context, TypeQuals)) {
|
||||
if (!Constructor->isUsed())
|
||||
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
|
||||
}
|
||||
// FIXME: more checking for other implicits go here.
|
||||
else
|
||||
Constructor->setUsed(true);
|
||||
}
|
||||
|
||||
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
||||
// FIXME: implicit template instantiation
|
||||
// Implicit instantiation of function templates
|
||||
if (!Function->getBody(Context)) {
|
||||
if (Function->getInstantiatedFromMemberFunction())
|
||||
PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
|
||||
|
||||
// FIXME: check for function template specializations.
|
||||
}
|
||||
|
||||
|
||||
// FIXME: keep track of references to static functions
|
||||
(void)Function;
|
||||
Function->setUsed(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
||||
(void)Var;
|
||||
|
@ -71,6 +71,31 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
|
||||
|
||||
QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
|
||||
|
||||
if (!isType) {
|
||||
// C++0x [expr.typeid]p3:
|
||||
// When typeid is applied to an expression other than an lvalue of a
|
||||
// polymorphic class type [...] [the] expression is an unevaluated
|
||||
// operand.
|
||||
|
||||
// FIXME: if the type of the expression is a class type, the class
|
||||
// shall be completely defined.
|
||||
bool isUnevaluatedOperand = true;
|
||||
Expr *E = static_cast<Expr *>(TyOrExpr);
|
||||
if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
|
||||
QualType T = E->getType();
|
||||
if (const RecordType *RecordT = T->getAsRecordType()) {
|
||||
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
|
||||
if (RecordD->isPolymorphic())
|
||||
isUnevaluatedOperand = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an unevaluated operand, clear out the set of declaration
|
||||
// references we have been computing.
|
||||
if (isUnevaluatedOperand)
|
||||
PotentiallyReferencedDeclStack.back().clear();
|
||||
}
|
||||
|
||||
return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
|
||||
TypeInfoType.withConst(),
|
||||
SourceRange(OpLoc, RParenLoc)));
|
||||
|
@ -847,13 +847,14 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
|
||||
TemplateArgumentListBuilder Converted(Template->getTemplateParameters(),
|
||||
NumTemplateArgs);
|
||||
if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
|
||||
TemplateArgs, NumTemplateArgs, RAngleLoc,
|
||||
ConvertedTemplateArgs))
|
||||
Converted))
|
||||
return QualType();
|
||||
|
||||
assert((ConvertedTemplateArgs.structuredSize() ==
|
||||
assert((Converted.structuredSize() ==
|
||||
Template->getTemplateParameters()->size()) &&
|
||||
"Converted template argument list is too short!");
|
||||
|
||||
@ -871,16 +872,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
// template<typename T, typename U = T> struct A;
|
||||
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
|
||||
CanonType = Context.getTemplateSpecializationType(CanonName,
|
||||
ConvertedTemplateArgs.getFlatArgumentList(),
|
||||
ConvertedTemplateArgs.flatSize());
|
||||
Converted.getFlatArguments(),
|
||||
Converted.flatSize());
|
||||
} else if (ClassTemplateDecl *ClassTemplate
|
||||
= dyn_cast<ClassTemplateDecl>(Template)) {
|
||||
// Find the class template specialization declaration that
|
||||
// corresponds to these arguments.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ClassTemplateSpecializationDecl::Profile(ID,
|
||||
ConvertedTemplateArgs.getFlatArgumentList(),
|
||||
ConvertedTemplateArgs.flatSize());
|
||||
Converted.getFlatArguments(),
|
||||
Converted.flatSize());
|
||||
void *InsertPos = 0;
|
||||
ClassTemplateSpecializationDecl *Decl
|
||||
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
|
||||
@ -892,7 +893,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
ClassTemplate->getDeclContext(),
|
||||
TemplateLoc,
|
||||
ClassTemplate,
|
||||
ConvertedTemplateArgs, 0);
|
||||
Converted, 0);
|
||||
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
|
||||
Decl->setLexicalDeclContext(CurContext);
|
||||
}
|
||||
@ -1003,7 +1004,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
|
||||
return true;
|
||||
|
||||
// Add the converted template type argument.
|
||||
Converted.push_back(
|
||||
Converted.Append(
|
||||
TemplateArgument(Arg.getLocation(),
|
||||
Context.getCanonicalType(Arg.getAsType())));
|
||||
return false;
|
||||
@ -1061,9 +1062,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
// parameter.
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||
if (TTP->isParameterPack()) {
|
||||
// We have an empty parameter pack.
|
||||
Converted.BeginParameterPack();
|
||||
Converted.EndParameterPack();
|
||||
// We have an empty argument pack.
|
||||
Converted.BeginPack();
|
||||
Converted.EndPack();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1076,13 +1077,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
// on the previously-computed template arguments.
|
||||
if (ArgType->isDependentType()) {
|
||||
InstantiatingTemplate Inst(*this, TemplateLoc,
|
||||
Template, Converted.getFlatArgumentList(),
|
||||
Template, Converted.getFlatArguments(),
|
||||
Converted.flatSize(),
|
||||
SourceRange(TemplateLoc, RAngleLoc));
|
||||
|
||||
TemplateArgumentList TemplateArgs(Context, Converted,
|
||||
/*CopyArgs=*/false,
|
||||
/*FlattenArgs=*/false);
|
||||
/*TakeArgs=*/false);
|
||||
ArgType = InstantiateType(ArgType, TemplateArgs,
|
||||
TTP->getDefaultArgumentLoc(),
|
||||
TTP->getDeclName());
|
||||
@ -1098,13 +1098,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
break;
|
||||
|
||||
InstantiatingTemplate Inst(*this, TemplateLoc,
|
||||
Template, Converted.getFlatArgumentList(),
|
||||
Template, Converted.getFlatArguments(),
|
||||
Converted.flatSize(),
|
||||
SourceRange(TemplateLoc, RAngleLoc));
|
||||
|
||||
TemplateArgumentList TemplateArgs(Context, Converted,
|
||||
/*CopyArgs=*/false,
|
||||
/*FlattenArgs=*/false);
|
||||
/*TakeArgs=*/false);
|
||||
|
||||
Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(),
|
||||
TemplateArgs);
|
||||
@ -1130,14 +1129,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||
if (TTP->isParameterPack()) {
|
||||
Converted.BeginParameterPack();
|
||||
Converted.BeginPack();
|
||||
// Check all the remaining arguments (if any).
|
||||
for (; ArgIdx < NumArgs; ++ArgIdx) {
|
||||
if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
Converted.EndParameterPack();
|
||||
Converted.EndPack();
|
||||
} else {
|
||||
if (CheckTemplateTypeArgument(TTP, Arg, Converted))
|
||||
Invalid = true;
|
||||
@ -1152,13 +1151,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
if (NTTPType->isDependentType()) {
|
||||
// Instantiate the type of the non-type template parameter.
|
||||
InstantiatingTemplate Inst(*this, TemplateLoc,
|
||||
Template, Converted.getFlatArgumentList(),
|
||||
Template, Converted.getFlatArguments(),
|
||||
Converted.flatSize(),
|
||||
SourceRange(TemplateLoc, RAngleLoc));
|
||||
|
||||
TemplateArgumentList TemplateArgs(Context, Converted,
|
||||
/*CopyArgs=*/false,
|
||||
/*FlattenArgs=*/false);
|
||||
/*TakeArgs=*/false);
|
||||
NTTPType = InstantiateType(NTTPType, TemplateArgs,
|
||||
NTTP->getLocation(),
|
||||
NTTP->getDeclName());
|
||||
@ -1167,7 +1165,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
if (!NTTPType.isNull())
|
||||
NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
|
||||
NTTP->getLocation());
|
||||
|
||||
if (NTTPType.isNull()) {
|
||||
Invalid = true;
|
||||
break;
|
||||
@ -1185,7 +1182,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
|
||||
Invalid = true;
|
||||
else
|
||||
Converted.push_back(Result);
|
||||
Converted.Append(Result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1193,7 +1190,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
case TemplateArgument::Integral:
|
||||
// We've already checked this template argument, so just copy
|
||||
// it to the list of converted arguments.
|
||||
Converted.push_back(Arg);
|
||||
Converted.Append(Arg);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Type:
|
||||
@ -1240,7 +1237,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
// Add the converted template argument.
|
||||
Decl *D
|
||||
= Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
|
||||
Converted.push_back(TemplateArgument(Arg.getLocation(), D));
|
||||
Converted.Append(TemplateArgument(Arg.getLocation(), D));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -1257,7 +1254,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
case TemplateArgument::Declaration:
|
||||
// We've already checked this template argument, so just copy
|
||||
// it to the list of converted arguments.
|
||||
Converted.push_back(Arg);
|
||||
Converted.Append(Arg);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
@ -2102,7 +2099,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
|
||||
// accommodate variadic templates.
|
||||
MirrorsPrimaryTemplate = true;
|
||||
|
||||
const TemplateArgument *ArgList = TemplateArgs.getFlatArgumentList();
|
||||
const TemplateArgument *ArgList = TemplateArgs.getFlatArguments();
|
||||
|
||||
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
|
||||
// Determine whether the template argument list of the partial
|
||||
@ -2298,13 +2295,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
|
||||
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
|
||||
TemplateArgs.size());
|
||||
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
|
||||
TemplateArgs.data(), TemplateArgs.size(),
|
||||
RAngleLoc, ConvertedTemplateArgs))
|
||||
RAngleLoc, Converted))
|
||||
return true;
|
||||
|
||||
assert((ConvertedTemplateArgs.structuredSize() ==
|
||||
assert((Converted.structuredSize() ==
|
||||
ClassTemplate->getTemplateParameters()->size()) &&
|
||||
"Converted template argument list is too short!");
|
||||
|
||||
@ -2315,8 +2313,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
bool MirrorsPrimaryTemplate;
|
||||
if (CheckClassTemplatePartialSpecializationArgs(
|
||||
ClassTemplate->getTemplateParameters(),
|
||||
ConvertedTemplateArgs,
|
||||
MirrorsPrimaryTemplate))
|
||||
Converted, MirrorsPrimaryTemplate))
|
||||
return true;
|
||||
|
||||
if (MirrorsPrimaryTemplate) {
|
||||
@ -2338,13 +2335,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
|
||||
// FIXME: Template parameter list matters, too
|
||||
ClassTemplatePartialSpecializationDecl::Profile(ID,
|
||||
ConvertedTemplateArgs.getFlatArgumentList(),
|
||||
ConvertedTemplateArgs.flatSize());
|
||||
Converted.getFlatArguments(),
|
||||
Converted.flatSize());
|
||||
}
|
||||
else
|
||||
ClassTemplateSpecializationDecl::Profile(ID,
|
||||
ConvertedTemplateArgs.getFlatArgumentList(),
|
||||
ConvertedTemplateArgs.flatSize());
|
||||
Converted.getFlatArguments(),
|
||||
Converted.flatSize());
|
||||
void *InsertPos = 0;
|
||||
ClassTemplateSpecializationDecl *PrevDecl = 0;
|
||||
|
||||
@ -2387,7 +2384,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
TemplateNameLoc,
|
||||
TemplateParams,
|
||||
ClassTemplate,
|
||||
ConvertedTemplateArgs,
|
||||
Converted,
|
||||
PrevPartial);
|
||||
|
||||
if (PrevPartial) {
|
||||
@ -2437,7 +2434,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
ClassTemplate->getDeclContext(),
|
||||
TemplateNameLoc,
|
||||
ClassTemplate,
|
||||
ConvertedTemplateArgs,
|
||||
Converted,
|
||||
PrevDecl);
|
||||
|
||||
if (PrevDecl) {
|
||||
@ -2559,13 +2556,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
|
||||
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
|
||||
TemplateArgs.size());
|
||||
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
|
||||
TemplateArgs.data(), TemplateArgs.size(),
|
||||
RAngleLoc, ConvertedTemplateArgs))
|
||||
RAngleLoc, Converted))
|
||||
return true;
|
||||
|
||||
assert((ConvertedTemplateArgs.structuredSize() ==
|
||||
assert((Converted.structuredSize() ==
|
||||
ClassTemplate->getTemplateParameters()->size()) &&
|
||||
"Converted template argument list is too short!");
|
||||
|
||||
@ -2573,8 +2571,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
// corresponds to these arguments.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ClassTemplateSpecializationDecl::Profile(ID,
|
||||
ConvertedTemplateArgs.getFlatArgumentList(),
|
||||
ConvertedTemplateArgs.flatSize());
|
||||
Converted.getFlatArguments(),
|
||||
Converted.flatSize());
|
||||
void *InsertPos = 0;
|
||||
ClassTemplateSpecializationDecl *PrevDecl
|
||||
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
|
||||
@ -2617,7 +2615,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
ClassTemplate->getDeclContext(),
|
||||
TemplateNameLoc,
|
||||
ClassTemplate,
|
||||
ConvertedTemplateArgs, 0);
|
||||
Converted, 0);
|
||||
Specialization->setLexicalDeclContext(CurContext);
|
||||
CurContext->addDecl(Context, Specialization);
|
||||
return DeclPtrTy::make(Specialization);
|
||||
@ -2643,7 +2641,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
ClassTemplate->getDeclContext(),
|
||||
TemplateNameLoc,
|
||||
ClassTemplate,
|
||||
ConvertedTemplateArgs, 0);
|
||||
Converted, 0);
|
||||
|
||||
ClassTemplate->getSpecializations().InsertNode(Specialization,
|
||||
InsertPos);
|
||||
|
@ -654,7 +654,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
|
||||
// C++ [temp.deduct.type]p2:
|
||||
// [...] or if any template argument remains neither deduced nor
|
||||
// explicitly specified, template argument deduction fails.
|
||||
TemplateArgumentListBuilder Builder(Context);
|
||||
TemplateArgumentListBuilder Builder(Partial->getTemplateParameters(),
|
||||
Deduced.size());
|
||||
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
|
||||
if (Deduced[I].isNull()) {
|
||||
Decl *Param
|
||||
@ -669,13 +670,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
|
||||
return TDK_Incomplete;
|
||||
}
|
||||
|
||||
Builder.push_back(Deduced[I]);
|
||||
Builder.Append(Deduced[I]);
|
||||
}
|
||||
|
||||
// Form the template argument list from the deduced template arguments.
|
||||
TemplateArgumentList *DeducedArgumentList
|
||||
= new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
|
||||
/*FlattenArgs=*/true);
|
||||
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
|
||||
Info.reset(DeducedArgumentList);
|
||||
|
||||
// Substitute the deduced template arguments into the template
|
||||
|
@ -420,6 +420,7 @@ InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
|
||||
}
|
||||
|
||||
// Instantiate the size expression
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
Sema::OwningExprResult InstantiatedArraySize =
|
||||
SemaRef.InstantiateExpr(ArraySize, TemplateArgs);
|
||||
if (InstantiatedArraySize.isInvalid())
|
||||
@ -443,6 +444,10 @@ InstantiateDependentSizedExtVectorType(const DependentSizedExtVectorType *T,
|
||||
return QualType();
|
||||
}
|
||||
|
||||
// The expression in a dependent-sized extended vector type is not
|
||||
// potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
// Instantiate the size expression.
|
||||
const Expr *SizeExpr = T->getSizeExpr();
|
||||
Sema::OwningExprResult InstantiatedArraySize =
|
||||
@ -520,6 +525,9 @@ TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
|
||||
QualType
|
||||
TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
|
||||
unsigned Quals) const {
|
||||
// The expression in a typeof is not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
Sema::OwningExprResult E
|
||||
= SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
|
||||
if (E.isInvalid())
|
||||
@ -1175,6 +1183,9 @@ TemplateArgument Sema::Instantiate(TemplateArgument Arg,
|
||||
return Arg;
|
||||
|
||||
case TemplateArgument::Expression: {
|
||||
// Template argument expressions are not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
|
||||
|
||||
Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs);
|
||||
if (E.isInvalid())
|
||||
return TemplateArgument();
|
||||
|
@ -163,6 +163,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
|
||||
if (Invalid)
|
||||
BitWidth = 0;
|
||||
else if (BitWidth) {
|
||||
// The bit-width expression is not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
OwningExprResult InstantiatedBitWidth
|
||||
= SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
|
||||
if (InstantiatedBitWidth.isInvalid()) {
|
||||
@ -192,6 +195,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
|
||||
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
|
||||
Expr *AssertExpr = D->getAssertExpr();
|
||||
|
||||
// The expression in a static assertion is not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
OwningExprResult InstantiatedAssertExpr
|
||||
= SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
|
||||
if (InstantiatedAssertExpr.isInvalid())
|
||||
@ -222,8 +228,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
|
||||
EC != ECEnd; ++EC) {
|
||||
// The specified value for the enumerator.
|
||||
OwningExprResult Value = SemaRef.Owned((Expr *)0);
|
||||
if (Expr *UninstValue = EC->getInitExpr())
|
||||
if (Expr *UninstValue = EC->getInitExpr()) {
|
||||
// The enumerator's value expression is not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef,
|
||||
Action::Unevaluated);
|
||||
|
||||
Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
|
||||
}
|
||||
|
||||
// Drop the initial value and continue.
|
||||
bool isInvalid = false;
|
||||
@ -586,6 +597,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||
if (Function->isInvalidDecl())
|
||||
return;
|
||||
|
||||
assert(!Function->getBody(Context) && "Already instantiated!");
|
||||
|
||||
// Find the function body that we'll be substituting.
|
||||
const FunctionDecl *PatternDecl
|
||||
= Function->getInstantiatedFromMemberFunction();
|
||||
@ -765,3 +778,18 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
/// \brief Performs template instantiation for all implicit template
|
||||
/// instantiations we have seen until this point.
|
||||
void Sema::PerformPendingImplicitInstantiations() {
|
||||
while (!PendingImplicitInstantiations.empty()) {
|
||||
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
|
||||
PendingImplicitInstantiations.pop();
|
||||
|
||||
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
|
||||
if (!Function->getBody(Context))
|
||||
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function);
|
||||
|
||||
// FIXME: instantiation static member variables
|
||||
}
|
||||
}
|
||||
|
@ -714,9 +714,17 @@ TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
|
||||
E->getSourceRange());
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Arg = Visit(E->getArgumentExpr());
|
||||
if (Arg.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
Sema::OwningExprResult Arg(SemaRef);
|
||||
{
|
||||
// C++0x [expr.sizeof]p1:
|
||||
// The operand is either an expression, which is an unevaluated operand
|
||||
// [...]
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
Arg = Visit(E->getArgumentExpr());
|
||||
if (Arg.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Result
|
||||
= SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
|
||||
@ -949,6 +957,12 @@ TemplateExprInstantiator::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
|
||||
E->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
// We don't know whether the expression is potentially evaluated until
|
||||
// after we perform semantic analysis, so the expression is potentially
|
||||
// potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef,
|
||||
Action::PotentiallyPotentiallyEvaluated);
|
||||
|
||||
OwningExprResult Operand = Visit(E->getExprOperand());
|
||||
if (Operand.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
@ -145,6 +145,9 @@ TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) {
|
||||
}
|
||||
|
||||
Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) {
|
||||
// The case value expressions are not potentially evaluated.
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
|
||||
|
||||
// Instantiate left-hand case value.
|
||||
OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs);
|
||||
if (LHS.isInvalid())
|
||||
|
@ -33,3 +33,7 @@ void f1() {}
|
||||
// RUN: grep 'define .* @f3' %t | not grep -F '...'
|
||||
struct foo { int X, Y, Z; } f3() {
|
||||
}
|
||||
|
||||
// PR4423 - This shouldn't crash in codegen
|
||||
void f4() {}
|
||||
void f5() { f4(42); }
|
||||
|
29
test/CodeGenCXX/implicit-instantiation-1.cpp
Normal file
29
test/CodeGenCXX/implicit-instantiation-1.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
// RUN: clang-cc -emit-llvm %s -o %t &&
|
||||
|
||||
template<typename T>
|
||||
struct X {
|
||||
void f(T) { }
|
||||
void f(char) { }
|
||||
|
||||
void g(T) { }
|
||||
|
||||
void h(T) { }
|
||||
};
|
||||
|
||||
void foo(X<int> &xi, X<float> *xfp, int i, float f) {
|
||||
// RUN: grep "linkonce_odr.*_ZN1XIiE1fEi" %t | count 1 &&
|
||||
xi.f(i);
|
||||
|
||||
// RUN: grep "linkonce_odr.*_ZN1XIiE1gEi" %t | count 1 &&
|
||||
xi.g(f);
|
||||
|
||||
// RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1 &&
|
||||
xfp->f(f);
|
||||
|
||||
// RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0 &&
|
||||
|
||||
// RUN: true
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ struct X2 : X1 { // expected-note {{'struct X2' declared here}} \
|
||||
|
||||
struct X3 : public X2 {
|
||||
};
|
||||
X3 x3; // expected-error {{cannot define the default constructor for 'struct X3', because member 'struct X2' does not have any implicit default constructor}}
|
||||
X3 x3; // expected-error {{cannot define the implicit default constructor for 'struct X3', because member 'struct X2' does not have any default constructor}}
|
||||
|
||||
|
||||
struct X4 {
|
||||
@ -19,7 +19,7 @@ struct X4 {
|
||||
X2 & rx2; // expected-note {{declared at}}
|
||||
};
|
||||
|
||||
X4 x4; // expected-error {{cannot define the default constructor for 'struct X4', because base class 'struct X2' does not have any implicit default constructor}} \
|
||||
X4 x4; // expected-error {{cannot define the implicit default constructor for 'struct X4', because base class 'struct X2' does not have any default constructor}} \
|
||||
// expected-error {{cannot define the implicit default constructor for 'struct X4', because reference member rx2 cannot be default-initialized}}
|
||||
|
||||
|
||||
|
@ -35,6 +35,12 @@ template<typename> class TemplateTemplateParm; // expected-error{{template param
|
||||
|
||||
template<template<typename T, int> class X> class TemplateTemplateParm; // expected-error{{too many template parameters in template template parameter redeclaration}}
|
||||
|
||||
template<typename T>
|
||||
struct test {}; // expected-note{{previous definition}}
|
||||
|
||||
template<typename T>
|
||||
struct test : T {}; // expected-error{{redefinition}}
|
||||
|
||||
#if 0
|
||||
// FIXME: parse template declarations in these scopes, so that we can
|
||||
// complain about the one at function scope.
|
||||
|
@ -89,6 +89,21 @@ class dynarray {
|
||||
iterator end() { return Last; }
|
||||
const_iterator end() const { return Last; }
|
||||
|
||||
bool operator==(const dynarray &other) const {
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, N = size(); I != N; ++I)
|
||||
if ((*this)[I] != other[I])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const dynarray &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
public:
|
||||
T* Start, *Last, *End;
|
||||
};
|
||||
@ -100,11 +115,6 @@ struct Point {
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
// FIXME: remove these when we have implicit instantiation for member
|
||||
// functions of class templates.
|
||||
template class dynarray<int>;
|
||||
template class dynarray<Point>;
|
||||
|
||||
int main() {
|
||||
dynarray<int> di;
|
||||
di.push_back(0);
|
||||
@ -146,5 +156,13 @@ int main() {
|
||||
I != IEnd; ++I)
|
||||
assert(*I == I - di4.begin());
|
||||
|
||||
assert(di4 == di);
|
||||
di4[3] = 17;
|
||||
assert(di4 != di);
|
||||
|
||||
dynarray<Point> dp;
|
||||
dp.push_back(Point());
|
||||
assert(dp.size() == 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
16
test/SemaTemplate/implicit-instantiation-1.cpp
Normal file
16
test/SemaTemplate/implicit-instantiation-1.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template<typename T, typename U>
|
||||
struct X {
|
||||
T f(T x, U y) { return x + y; }
|
||||
|
||||
unsigned g(T x, U y) { return sizeof(f(x, y)); }
|
||||
};
|
||||
|
||||
void test(X<int, int> *xii, X<int*, int> *xpi, X<int, int*> *xip) {
|
||||
(void)xii->f(1, 2);
|
||||
(void)xpi->f(0, 2);
|
||||
(void)sizeof(xip->f(2, 0)); // okay: does not instantiate
|
||||
(void)xip->g(2, 0); // okay: does not instantiate
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user