Import Clang r74383.
This commit is contained in:
parent
f698f7e719
commit
4ebdf5c4f5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=195099 svn path=/vendor/clang/clang-r74383/; revision=195101; tag=vendor/clang/clang-r74383
1844
clang.xcodeproj/project.pbxproj
Normal file
1844
clang.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
@ -192,6 +192,7 @@ class ASTContext {
|
||||
QualType VoidPtrTy, NullPtrTy;
|
||||
QualType OverloadTy;
|
||||
QualType DependentTy;
|
||||
QualType UndeducedAutoTy;
|
||||
|
||||
ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
@ -360,6 +361,9 @@ class ASTContext {
|
||||
QualType getTypeOfExprType(Expr *e);
|
||||
QualType getTypeOfType(QualType t);
|
||||
|
||||
/// getDecltypeType - C++0x decltype.
|
||||
QualType getDecltypeType(Expr *e);
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(TagDecl *Decl);
|
||||
|
@ -72,6 +72,7 @@ class Attr {
|
||||
Packed,
|
||||
Pure,
|
||||
Regparm,
|
||||
ReqdWorkGroupSize, // OpenCL-specific
|
||||
Section,
|
||||
Sentinel,
|
||||
StdCall,
|
||||
@ -501,6 +502,27 @@ class RegparmAttr : public Attr {
|
||||
static bool classof(const RegparmAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ReqdWorkGroupSizeAttr : public Attr {
|
||||
unsigned X, Y, Z;
|
||||
public:
|
||||
ReqdWorkGroupSizeAttr(unsigned X, unsigned Y, unsigned Z)
|
||||
: Attr(ReqdWorkGroupSize), X(X), Y(Y), Z(Z) {}
|
||||
|
||||
unsigned getXDim() const { return X; }
|
||||
unsigned getYDim() const { return Y; }
|
||||
unsigned getZDim() const { return Z; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == ReqdWorkGroupSize;
|
||||
}
|
||||
static bool classof(const ReqdWorkGroupSizeAttr *A) { return true; }
|
||||
};
|
||||
|
||||
// Checker-specific attributes.
|
||||
DEF_SIMPLE_ATTR(CFReturnsRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsRetained);
|
||||
|
@ -25,7 +25,8 @@ class FunctionTemplateDecl;
|
||||
class Stmt;
|
||||
class CompoundStmt;
|
||||
class StringLiteral;
|
||||
|
||||
class TemplateArgumentList;
|
||||
|
||||
/// TranslationUnitDecl - The top declaration context.
|
||||
class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
TranslationUnitDecl()
|
||||
@ -105,6 +106,13 @@ class NamedDecl : public Decl {
|
||||
/// \brief Determine whether this declaration has linkage.
|
||||
bool hasLinkage() const;
|
||||
|
||||
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
|
||||
/// the underlying named decl.
|
||||
NamedDecl *getUnderlyingDecl();
|
||||
const NamedDecl *getUnderlyingDecl() const {
|
||||
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= NamedFirst && D->getKind() <= NamedLast;
|
||||
}
|
||||
@ -614,10 +622,17 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
None, Extern, Static, PrivateExtern
|
||||
};
|
||||
private:
|
||||
/// \brief Provides information about a function template specialization,
|
||||
/// which is a FunctionDecl that has been explicitly specialization or
|
||||
/// instantiated from a function template.
|
||||
struct TemplateSpecializationInfo {
|
||||
FunctionTemplateDecl *Template;
|
||||
const TemplateArgumentList *TemplateArguments;
|
||||
};
|
||||
|
||||
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
|
||||
/// parameters of this function. This is null if a prototype or if there are
|
||||
/// no formals. TODO: we could allocate this space immediately after the
|
||||
/// FunctionDecl object to save an allocation like FunctionType does.
|
||||
/// no formals.
|
||||
ParmVarDecl **ParamInfo;
|
||||
|
||||
LazyDeclStmtPtr Body;
|
||||
@ -664,8 +679,12 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
/// pointer to a FunctionTemplateDecl. For member functions
|
||||
/// of class template specializations, this will be the
|
||||
/// FunctionDecl from which the member function was instantiated.
|
||||
llvm::PointerUnion<FunctionTemplateDecl*, FunctionDecl*>
|
||||
TemplateOrInstantiation;
|
||||
/// For function template specializations, this will be a
|
||||
/// FunctionTemplateSpecializationInfo, which contains information about
|
||||
/// the template being specialized and the template arguments involved in
|
||||
/// that specialization.
|
||||
llvm::PointerUnion3<FunctionTemplateDecl*, FunctionDecl*,
|
||||
TemplateSpecializationInfo*> TemplateOrSpecialization;
|
||||
|
||||
protected:
|
||||
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
@ -678,7 +697,7 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
SClass(S), IsInline(isInline), C99InlineDefinition(false),
|
||||
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
|
||||
HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
|
||||
EndRangeLoc(L), TemplateOrInstantiation() {}
|
||||
EndRangeLoc(L), TemplateOrSpecialization() {}
|
||||
|
||||
virtual ~FunctionDecl() {}
|
||||
virtual void Destroy(ASTContext& C);
|
||||
@ -887,13 +906,13 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
/// X<int>::A is required, it will be instantiated from the
|
||||
/// declaration returned by getInstantiatedFromMemberFunction().
|
||||
FunctionDecl *getInstantiatedFromMemberFunction() const {
|
||||
return TemplateOrInstantiation.dyn_cast<FunctionDecl*>();
|
||||
return TemplateOrSpecialization.dyn_cast<FunctionDecl*>();
|
||||
}
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member function RD.
|
||||
void setInstantiationOfMemberFunction(FunctionDecl *RD) {
|
||||
TemplateOrInstantiation = RD;
|
||||
TemplateOrSpecialization = RD;
|
||||
}
|
||||
|
||||
/// \brief Retrieves the function template that is described by this
|
||||
@ -909,13 +928,54 @@ class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
/// getDescribedFunctionTemplate() retrieves the
|
||||
/// FunctionTemplateDecl from a FunctionDecl.
|
||||
FunctionTemplateDecl *getDescribedFunctionTemplate() const {
|
||||
return TemplateOrInstantiation.dyn_cast<FunctionTemplateDecl*>();
|
||||
return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>();
|
||||
}
|
||||
|
||||
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
|
||||
TemplateOrInstantiation = Template;
|
||||
TemplateOrSpecialization = Template;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the primary template that this function template
|
||||
/// specialization either specializes or was instantiated from.
|
||||
///
|
||||
/// If this function declaration is not a function template specialization,
|
||||
/// returns NULL.
|
||||
FunctionTemplateDecl *getPrimaryTemplate() const {
|
||||
if (TemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
|
||||
return Info->Template;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments used to produce this function
|
||||
/// template specialization from the primary template.
|
||||
///
|
||||
/// If this function declaration is not a function template specialization,
|
||||
/// returns NULL.
|
||||
const TemplateArgumentList *getTemplateSpecializationArgs() const {
|
||||
if (TemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>()) {
|
||||
return Info->TemplateArguments;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Specify that this function declaration is actually a function
|
||||
/// template specialization.
|
||||
///
|
||||
/// \param Context the AST context in which this function resides.
|
||||
///
|
||||
/// \param Template the function template that this function template
|
||||
/// specialization specializes.
|
||||
///
|
||||
/// \param TemplateArgs the template arguments that produced this
|
||||
/// function template specialization from the template.
|
||||
void setFunctionTemplateSpecialization(ASTContext &Context,
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
|
||||
|
@ -329,6 +329,9 @@ class Decl {
|
||||
/// template parameter pack.
|
||||
bool isTemplateParameterPack() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
|
@ -27,6 +27,40 @@ class CXXConversionDecl;
|
||||
class CXXMethodDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
|
||||
/// \brief Represents any kind of function declaration, whether it is a
|
||||
/// concrete function or a function template.
|
||||
class AnyFunctionDecl {
|
||||
NamedDecl *Function;
|
||||
|
||||
public:
|
||||
AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { }
|
||||
AnyFunctionDecl(FunctionTemplateDecl *FTD);
|
||||
|
||||
/// \brief Implicily converts any function or function template into a
|
||||
/// named declaration.
|
||||
operator NamedDecl *() const { return Function; }
|
||||
|
||||
/// \brief Retrieve the underlying function or function template.
|
||||
NamedDecl *get() const { return Function; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
/// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from
|
||||
/// AnyFunctionDecl to any function or function template declaration.
|
||||
template<> struct simplify_type<const ::clang::AnyFunctionDecl> {
|
||||
typedef ::clang::NamedDecl* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::AnyFunctionDecl &Val) {
|
||||
return Val;
|
||||
}
|
||||
};
|
||||
template<> struct simplify_type< ::clang::AnyFunctionDecl>
|
||||
: public simplify_type<const ::clang::AnyFunctionDecl> {};
|
||||
} // end namespace llvm
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// OverloadedFunctionDecl - An instance of this class represents a
|
||||
/// set of overloaded functions. All of the functions have the same
|
||||
/// name and occur within the same scope.
|
||||
@ -43,15 +77,15 @@ class OverloadedFunctionDecl : public NamedDecl {
|
||||
|
||||
/// Functions - the set of overloaded functions contained in this
|
||||
/// overload set.
|
||||
llvm::SmallVector<FunctionDecl *, 4> Functions;
|
||||
llvm::SmallVector<AnyFunctionDecl, 4> Functions;
|
||||
|
||||
// FIXME: This should go away when we stop using
|
||||
// OverloadedFunctionDecl to store conversions in CXXRecordDecl.
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator;
|
||||
typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator
|
||||
typedef llvm::SmallVector<AnyFunctionDecl, 4>::iterator function_iterator;
|
||||
typedef llvm::SmallVector<AnyFunctionDecl, 4>::const_iterator
|
||||
function_const_iterator;
|
||||
|
||||
static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
@ -71,30 +105,18 @@ class OverloadedFunctionDecl : public NamedDecl {
|
||||
this->setLocation(FD->getLocation());
|
||||
}
|
||||
|
||||
/// addOverload - Add an overloaded function template FTD to this set of
|
||||
/// overloaded functions.
|
||||
void addOverload(FunctionTemplateDecl *FTD);
|
||||
|
||||
function_iterator function_begin() { return Functions.begin(); }
|
||||
function_iterator function_end() { return Functions.end(); }
|
||||
function_const_iterator function_begin() const { return Functions.begin(); }
|
||||
function_const_iterator function_end() const { return Functions.end(); }
|
||||
|
||||
/// getNumFunctions - the number of overloaded functions stored in
|
||||
/// \brief Returns the number of overloaded functions stored in
|
||||
/// this set.
|
||||
unsigned getNumFunctions() const { return Functions.size(); }
|
||||
|
||||
/// getFunction - retrieve the ith function in the overload set.
|
||||
const FunctionDecl *getFunction(unsigned i) const {
|
||||
assert(i < getNumFunctions() && "Illegal function #");
|
||||
return Functions[i];
|
||||
}
|
||||
FunctionDecl *getFunction(unsigned i) {
|
||||
assert(i < getNumFunctions() && "Illegal function #");
|
||||
return Functions[i];
|
||||
}
|
||||
|
||||
// getDeclContext - Get the context of these overloaded functions.
|
||||
DeclContext *getDeclContext() {
|
||||
assert(getNumFunctions() > 0 && "Context of an empty overload set");
|
||||
return getFunction(0)->getDeclContext();
|
||||
}
|
||||
unsigned size() const { return Functions.size(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
@ -449,6 +471,15 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// getDestructor - Returns the destructor decl for this class.
|
||||
const CXXDestructorDecl *getDestructor(ASTContext &Context);
|
||||
|
||||
/// isLocalClass - If the class is a local class [class.local], returns
|
||||
/// the enclosing function declaration.
|
||||
const FunctionDecl *isLocalClass() const {
|
||||
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getDeclContext()))
|
||||
return RD->isLocalClass();
|
||||
|
||||
return dyn_cast<FunctionDecl>(getDeclContext());
|
||||
}
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
@ -1070,17 +1101,25 @@ class UsingDecl : public NamedDecl {
|
||||
public:
|
||||
/// \brief Returns the source range that covers the nested-name-specifier
|
||||
/// preceding the namespace name.
|
||||
SourceRange getNestedNameRange() { return(NestedNameRange); }
|
||||
SourceRange getNestedNameRange() { return NestedNameRange; }
|
||||
|
||||
/// \brief Returns the source location of the target declaration name.
|
||||
SourceLocation getTargetNameLocation() { return(TargetNameLocation); }
|
||||
SourceLocation getTargetNameLocation() { return TargetNameLocation; }
|
||||
|
||||
/// \brief Returns the source location of the "using" location itself.
|
||||
SourceLocation getUsingLocation() { return(UsingLocation); }
|
||||
SourceLocation getUsingLocation() { return UsingLocation; }
|
||||
|
||||
/// \brief getTargetDecl - Returns target specified by using-decl.
|
||||
NamedDecl *getTargetDecl() { return(TargetDecl); }
|
||||
NamedDecl *getTargetDecl() { return TargetDecl; }
|
||||
const NamedDecl *getTargetDecl() const { return TargetDecl; }
|
||||
|
||||
/// \brief Get target nested name declaration.
|
||||
NestedNameSpecifier* getTargetNestedNameDecl() { return(TargetNestedNameDecl); }
|
||||
NestedNameSpecifier* getTargetNestedNameDecl() {
|
||||
return TargetNestedNameDecl;
|
||||
}
|
||||
|
||||
/// isTypeName - Return true if using decl had 'typename'.
|
||||
bool isTypeName() const { return(IsTypeName); }
|
||||
bool isTypeName() const { return IsTypeName; }
|
||||
|
||||
static UsingDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
|
||||
|
@ -153,7 +153,7 @@ class TemplateDecl : public NamedDecl {
|
||||
NamedDecl *TemplatedDecl;
|
||||
TemplateParameterList* TemplateParams;
|
||||
};
|
||||
|
||||
|
||||
/// Declaration of a template function.
|
||||
class FunctionTemplateDecl : public TemplateDecl {
|
||||
protected:
|
||||
@ -580,6 +580,30 @@ class TemplateArgument {
|
||||
return reinterpret_cast<Expr *>(TypeOrValue);
|
||||
}
|
||||
|
||||
/// \brief Iterator that traverses the elements of a template argument pack.
|
||||
typedef const TemplateArgument * pack_iterator;
|
||||
|
||||
/// \brief Iterator referencing the first argument of a template argument
|
||||
/// pack.
|
||||
pack_iterator pack_begin() const {
|
||||
assert(Kind == Pack);
|
||||
return Args.Args;
|
||||
}
|
||||
|
||||
/// \brief Iterator referencing one past the last argument of a template
|
||||
/// argument pack.
|
||||
pack_iterator pack_end() const {
|
||||
assert(Kind == Pack);
|
||||
return Args.Args + Args.NumArgs;
|
||||
}
|
||||
|
||||
/// \brief The number of template arguments in the given template argument
|
||||
/// pack.
|
||||
unsigned pack_size() const {
|
||||
assert(Kind == Pack);
|
||||
return Args.NumArgs;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location where the template argument starts.
|
||||
SourceLocation getLocation() const { return StartLoc; }
|
||||
|
||||
@ -957,6 +981,10 @@ class ClassTemplateDecl : public TemplateDecl {
|
||||
virtual void Destroy(ASTContext& C);
|
||||
};
|
||||
|
||||
/// Implementation of inline functions that require the template declarations
|
||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
||||
: Function(FTD) { }
|
||||
|
||||
} /* end of namespace clang */
|
||||
|
||||
#endif
|
||||
|
@ -572,7 +572,10 @@ class BuiltinType : public Type {
|
||||
NullPtr, // This is the type of C++0x 'nullptr'.
|
||||
|
||||
Overload, // This represents the type of an overloaded function declaration.
|
||||
Dependent // This represents the type of a type-dependent expression.
|
||||
Dependent, // This represents the type of a type-dependent expression.
|
||||
|
||||
UndeducedAuto // In C++0x, this represents the type of an auto variable
|
||||
// that has not been deduced yet.
|
||||
};
|
||||
private:
|
||||
Kind TypeKind;
|
||||
@ -1103,11 +1106,17 @@ class ExtVectorType : public VectorType {
|
||||
case '7': return 7;
|
||||
case '8': return 8;
|
||||
case '9': return 9;
|
||||
case 'A':
|
||||
case 'a': return 10;
|
||||
case 'B':
|
||||
case 'b': return 11;
|
||||
case 'C':
|
||||
case 'c': return 12;
|
||||
case 'D':
|
||||
case 'd': return 13;
|
||||
case 'E':
|
||||
case 'e': return 14;
|
||||
case 'F':
|
||||
case 'f': return 15;
|
||||
}
|
||||
}
|
||||
@ -1358,6 +1367,21 @@ class TypeOfType : public Type {
|
||||
static bool classof(const TypeOfType *) { return true; }
|
||||
};
|
||||
|
||||
/// DecltypeType (C++0x)
|
||||
class DecltypeType : public Type {
|
||||
Expr *E;
|
||||
DecltypeType(Expr *E, QualType can);
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
Expr *getUnderlyingExpr() const { return E; }
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString,
|
||||
const PrintingPolicy &Policy) const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
|
||||
static bool classof(const DecltypeType *) { return true; }
|
||||
};
|
||||
|
||||
class TagType : public Type {
|
||||
/// Stores the TagDecl associated with this type. The decl will
|
||||
/// point to the TagDecl that actually defines the entity (or is a
|
||||
|
@ -69,6 +69,7 @@ TYPE(FunctionNoProto, FunctionType)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_TYPE(TypeOfExpr, Type)
|
||||
NON_CANONICAL_TYPE(TypeOf, Type)
|
||||
NON_CANONICAL_TYPE(Decltype, Type)
|
||||
ABSTRACT_TYPE(Tag, Type)
|
||||
TYPE(Record, TagType)
|
||||
TYPE(Enum, TagType)
|
||||
|
@ -37,7 +37,6 @@ void CheckDeadStores(LiveVariables& L, BugReporter& BR);
|
||||
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
|
||||
bool FullUninitTaint=false);
|
||||
|
||||
GRTransferFuncs* MakeGRSimpleValsTF();
|
||||
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
const LangOptions& lopts);
|
||||
|
||||
|
@ -45,7 +45,7 @@ class ConstraintManager {
|
||||
virtual const GRState *RemoveDeadBindings(const GRState *state,
|
||||
SymbolReaper& SymReaper) = 0;
|
||||
|
||||
virtual void print(const GRState *state, std::ostream& Out,
|
||||
virtual void print(const GRState *state, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
|
||||
virtual void EndPath(const GRState *state) {}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/SValuator.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
@ -67,6 +68,9 @@ class GRExprEngine {
|
||||
/// ValMgr - Object that manages/creates SVals.
|
||||
ValueManager &ValMgr;
|
||||
|
||||
/// SVator - SValuator object that creates SVals from expressions.
|
||||
llvm::OwningPtr<SValuator> SVator;
|
||||
|
||||
/// EntryNode - The immediate predecessor node.
|
||||
NodeTy* EntryNode;
|
||||
|
||||
@ -603,41 +607,32 @@ class GRExprEngine {
|
||||
return X;
|
||||
|
||||
if (isa<Loc>(X))
|
||||
return getTF().EvalCast(*this, cast<Loc>(X), CastT);
|
||||
return SVator->EvalCast(cast<Loc>(X), CastT);
|
||||
else
|
||||
return getTF().EvalCast(*this, cast<NonLoc>(X), CastT);
|
||||
return SVator->EvalCast(cast<NonLoc>(X), CastT);
|
||||
}
|
||||
|
||||
SVal EvalMinus(UnaryOperator* U, SVal X) {
|
||||
return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X;
|
||||
SVal EvalMinus(SVal X) {
|
||||
return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
SVal EvalComplement(SVal X) {
|
||||
return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X;
|
||||
return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T)
|
||||
: R;
|
||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) {
|
||||
return SVator->EvalBinOpNN(op, L, R, T);
|
||||
}
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L,
|
||||
cast<NonLoc>(R), T) : R;
|
||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) {
|
||||
return R.isValid() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R;
|
||||
}
|
||||
|
||||
void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
|
||||
ExplodedNode<GRState>* Pred, QualType T);
|
||||
|
||||
void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T);
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R,
|
||||
QualType T);
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
|
||||
SVal lhs, SVal rhs, QualType T);
|
||||
|
||||
protected:
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred);
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
@ -198,6 +198,14 @@ class GRState : public llvm::FoldingSetNode {
|
||||
const GRState *assumeInBound(SVal idx, SVal upperBound,
|
||||
bool assumption) const;
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Utility methods for getting regions.
|
||||
//==---------------------------------------------------------------------==//
|
||||
|
||||
const VarRegion* getRegion(const VarDecl* D) const;
|
||||
|
||||
const MemRegion* getSelfRegion() const;
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Binding and retrieving values to/from the environment and symbolic store.
|
||||
//==---------------------------------------------------------------------==//
|
||||
@ -218,6 +226,10 @@ class GRState : public llvm::FoldingSetNode {
|
||||
return bindExpr(Ex, V, true, false);
|
||||
}
|
||||
|
||||
const GRState *bindDecl(const VarDecl* VD, SVal IVal) const;
|
||||
|
||||
const GRState *bindDeclWithNoInit(const VarDecl* VD) const;
|
||||
|
||||
const GRState *bindLoc(Loc location, SVal V) const;
|
||||
|
||||
const GRState *bindLoc(SVal location, SVal V) const;
|
||||
@ -314,17 +326,17 @@ class GRState : public llvm::FoldingSetNode {
|
||||
class Printer {
|
||||
public:
|
||||
virtual ~Printer() {}
|
||||
virtual void Print(std::ostream& Out, const GRState* state,
|
||||
virtual void Print(llvm::raw_ostream& Out, const GRState* state,
|
||||
const char* nl, const char* sep) = 0;
|
||||
};
|
||||
|
||||
// Pretty-printing.
|
||||
void print(std::ostream& Out, const char *nl = "\n",
|
||||
void print(llvm::raw_ostream& Out, const char *nl = "\n",
|
||||
const char *sep = "") const;
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
void printDOT(std::ostream& Out) const;
|
||||
void printDOT(llvm::raw_ostream& Out) const;
|
||||
|
||||
// Tags used for the Generic Data Map.
|
||||
struct NullDerefTag {
|
||||
@ -427,18 +439,7 @@ class GRStateManager {
|
||||
/// Liveness - live-variables information of the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to get initial store and prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
private:
|
||||
|
||||
Environment RemoveBlkExpr(const Environment& Env, Expr* E) {
|
||||
return EnvMgr.RemoveBlkExpr(Env, E);
|
||||
}
|
||||
|
||||
// FIXME: Remove when we do lazy initializaton of variable bindings.
|
||||
// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) {
|
||||
// return SetSVal(St, getLoc(D), V);
|
||||
// }
|
||||
|
||||
public:
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
@ -460,7 +461,7 @@ class GRStateManager {
|
||||
|
||||
~GRStateManager();
|
||||
|
||||
const GRState* getInitialState();
|
||||
const GRState *getInitialState();
|
||||
|
||||
ASTContext &getContext() { return ValueMgr.getContext(); }
|
||||
const ASTContext &getContext() const { return ValueMgr.getContext(); }
|
||||
@ -498,16 +499,6 @@ class GRStateManager {
|
||||
StoreManager& getStoreManager() { return *StoreMgr; }
|
||||
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
|
||||
|
||||
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDecl(St, VD, IVal);
|
||||
}
|
||||
|
||||
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDeclWithNoInit(St, VD);
|
||||
}
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
SymbolReaper& SymReaper);
|
||||
|
||||
@ -516,55 +507,7 @@ class GRStateManager {
|
||||
NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
|
||||
// Utility methods for getting regions.
|
||||
|
||||
VarRegion* getRegion(const VarDecl* D) {
|
||||
return getRegionManager().getVarRegion(D);
|
||||
}
|
||||
|
||||
const MemRegion* getSelfRegion(const GRState* state) {
|
||||
return StoreMgr->getSelfRegion(state->getStore());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, const Stmt* Ex) {
|
||||
return St->getEnvironment().GetBlkExprSVal(Ex, ValueMgr);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, const Stmt* Ex, SVal V,
|
||||
bool isBlkExpr, bool Invalidate) {
|
||||
|
||||
const Environment& OldEnv = St->getEnvironment();
|
||||
Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate);
|
||||
|
||||
if (NewEnv == OldEnv)
|
||||
return St;
|
||||
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = NewEnv;
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, const Stmt* Ex, SVal V,
|
||||
bool Invalidate = true) {
|
||||
|
||||
bool isBlkExpr = false;
|
||||
|
||||
if (Ex == CurrentStmt) {
|
||||
// FIXME: Should this just be an assertion? When would we want to set
|
||||
// the value of a block-level expression if it wasn't CurrentStmt?
|
||||
isBlkExpr = cfg.isBlkExpr(Ex);
|
||||
|
||||
if (!isBlkExpr)
|
||||
return St;
|
||||
}
|
||||
|
||||
return BindExpr(St, Ex, V, isBlkExpr, Invalidate);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
SVal ArrayToPointer(Loc Array) {
|
||||
@ -579,37 +522,7 @@ class GRStateManager {
|
||||
void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
|
||||
StoreMgr->iterBindings(state->getStore(), F);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* state, const MemRegion* R) {
|
||||
return StoreMgr->Retrieve(state, loc::MemRegionVal(R));
|
||||
}
|
||||
|
||||
SVal GetSValAsScalarOrLoc(const GRState* state, const MemRegion *R) {
|
||||
// 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())
|
||||
return UnknownVal();
|
||||
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
QualType T = TR->getValueType(getContext());
|
||||
if (Loc::IsLocType(T) || T->isIntegerType())
|
||||
return GetSVal(state, R);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
|
||||
return StoreMgr->Bind(St, LV, V);
|
||||
}
|
||||
|
||||
void Unbind(GRState& St, Loc LV) {
|
||||
St.St = StoreMgr->Remove(St.St, LV);
|
||||
}
|
||||
|
||||
const GRState* Unbind(const GRState* St, Loc LV);
|
||||
|
||||
const GRState* getPersistentState(GRState& Impl);
|
||||
|
||||
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
|
||||
@ -695,6 +608,14 @@ class GRStateManager {
|
||||
// Out-of-line method definitions for GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
inline const VarRegion* GRState::getRegion(const VarDecl* D) const {
|
||||
return Mgr->getRegionManager().getVarRegion(D);
|
||||
}
|
||||
|
||||
inline const MemRegion* GRState::getSelfRegion() const {
|
||||
return Mgr->StoreMgr->getSelfRegion(getStore());
|
||||
}
|
||||
|
||||
inline const GRState *GRState::assume(SVal Cond, bool Assumption) const {
|
||||
return Mgr->ConstraintMgr->Assume(this, Cond, Assumption);
|
||||
}
|
||||
@ -709,18 +630,16 @@ inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL
|
||||
return Mgr->StoreMgr->BindCompoundLiteral(this, CL, V);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
|
||||
bool Invalidate) const {
|
||||
return Mgr->BindExpr(this, Ex, V, isBlkExpr, Invalidate);
|
||||
inline const GRState *GRState::bindDecl(const VarDecl* VD, SVal IVal) const {
|
||||
return Mgr->StoreMgr->BindDecl(this, VD, IVal);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindExpr(const Stmt* Ex, SVal V,
|
||||
bool Invalidate) const {
|
||||
return Mgr->BindExpr(this, Ex, V, Invalidate);
|
||||
inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD) const {
|
||||
return Mgr->StoreMgr->BindDeclWithNoInit(this, VD);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindLoc(Loc LV, SVal V) const {
|
||||
return Mgr->BindLoc(this, LV, V);
|
||||
return Mgr->StoreMgr->Bind(this, LV, V);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
|
||||
@ -756,11 +675,11 @@ inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
|
||||
}
|
||||
|
||||
inline SVal GRState::getSVal(const Stmt* Ex) const {
|
||||
return getEnvironment().GetSVal(Ex, Mgr->ValueMgr);
|
||||
return Env.GetSVal(Ex, Mgr->ValueMgr);
|
||||
}
|
||||
|
||||
inline SVal GRState::getBlkExprSVal(const Stmt* Ex) const {
|
||||
return Mgr->GetBlkExprSVal(this, Ex);
|
||||
return Env.GetBlkExprSVal(Ex, Mgr->ValueMgr);
|
||||
}
|
||||
|
||||
inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
|
||||
@ -778,11 +697,7 @@ inline SVal GRState::getSVal(Loc LV, QualType T) const {
|
||||
}
|
||||
|
||||
inline SVal GRState::getSVal(const MemRegion* R) const {
|
||||
return Mgr->GetSVal(this, R);
|
||||
}
|
||||
|
||||
inline SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
|
||||
return Mgr->GetSValAsScalarOrLoc(this, R);
|
||||
return Mgr->StoreMgr->Retrieve(this, loc::MemRegionVal(R));
|
||||
}
|
||||
|
||||
inline BasicValueFactory &GRState::getBasicVals() const {
|
||||
@ -842,10 +757,6 @@ CB GRState::scanReachableSymbols(SVal val) const {
|
||||
scanReachableSymbols(val, cb);
|
||||
return cb;
|
||||
}
|
||||
|
||||
inline const GRState *GRState::unbindLoc(Loc LV) const {
|
||||
return Mgr->Unbind(this, LV);
|
||||
}
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
|
@ -22,20 +22,12 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
class BugReporter;
|
||||
class ObjCMessageExpr;
|
||||
class GRStmtNodeBuilderRef;
|
||||
class GRExprEngine;
|
||||
class BugReporter;
|
||||
class ObjCMessageExpr;
|
||||
class GRStmtNodeBuilderRef;
|
||||
|
||||
class GRTransferFuncs {
|
||||
friend class GRExprEngine;
|
||||
protected:
|
||||
virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R, QualType T) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
@ -43,33 +35,7 @@ class GRTransferFuncs {
|
||||
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
|
||||
virtual void RegisterChecks(BugReporter& BR) {}
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0;
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0;
|
||||
|
||||
virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
// FIXME: We're moving back towards using GREXprEngine directly. No need
|
||||
// for OStates
|
||||
virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng,
|
||||
const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
|
||||
QualType T);
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
Loc L, Loc R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0;
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
@ -108,8 +74,7 @@ class GRTransferFuncs {
|
||||
ReturnStmt* S,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Assumptions.
|
||||
|
||||
// Assumptions.
|
||||
virtual const GRState* EvalAssume(const GRState *state,
|
||||
SVal Cond, bool Assumption) {
|
||||
return state;
|
||||
|
@ -111,7 +111,6 @@ class SVal {
|
||||
/// return that expression. Otherwise return NULL.
|
||||
const SymExpr *getAsSymbolicExpression() const;
|
||||
|
||||
void print(std::ostream& OS) const;
|
||||
void print(llvm::raw_ostream& OS) const;
|
||||
void printStdErr() const;
|
||||
|
||||
@ -255,12 +254,12 @@ class ConcreteInt : public NonLoc {
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const;
|
||||
ConcreteInt evalComplement(ValueManager &ValMgr) const;
|
||||
|
||||
ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const;
|
||||
ConcreteInt evalMinus(ValueManager &ValMgr) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SVal* V) {
|
||||
|
55
include/clang/Analysis/PathSensitive/SValuator.h
Normal file
55
include/clang/Analysis/PathSensitive/SValuator.h
Normal file
@ -0,0 +1,55 @@
|
||||
// SValuator.h - Construction of SVals from evaluating expressions -*- 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 SValuator, a class that defines the interface for
|
||||
// "symbolical evaluators" which construct an SVal from an expression.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR
|
||||
#define LLVM_CLANG_ANALYSIS_SVALUATOR
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRState;
|
||||
class ValueManager;
|
||||
|
||||
class SValuator {
|
||||
protected:
|
||||
ValueManager &ValMgr;
|
||||
|
||||
public:
|
||||
SValuator(ValueManager &valMgr) : ValMgr(valMgr) {}
|
||||
virtual ~SValuator() {}
|
||||
|
||||
virtual SVal EvalCast(NonLoc val, QualType castTy) = 0;
|
||||
|
||||
virtual SVal EvalCast(Loc val, QualType castTy) = 0;
|
||||
|
||||
virtual SVal EvalMinus(NonLoc val) = 0;
|
||||
|
||||
virtual SVal EvalComplement(NonLoc val) = 0;
|
||||
|
||||
virtual SVal EvalBinOpNN(BinaryOperator::Opcode Op, NonLoc lhs,
|
||||
NonLoc rhs, QualType resultTy) = 0;
|
||||
|
||||
virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs,
|
||||
QualType resultTy) = 0;
|
||||
|
||||
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
|
||||
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
|
||||
};
|
||||
|
||||
SValuator* CreateSimpleSValuator(ValueManager &valMgr);
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
@ -21,7 +21,6 @@
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -139,7 +138,7 @@ class StoreManager {
|
||||
|
||||
/// EvalBinOp - Perform pointer arithmetic.
|
||||
virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,
|
||||
Loc lhs, NonLoc rhs) {
|
||||
Loc lhs, NonLoc rhs, QualType resultTy) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
@ -171,7 +170,7 @@ class StoreManager {
|
||||
return state;
|
||||
}
|
||||
|
||||
virtual void print(Store store, std::ostream& Out,
|
||||
virtual void print(Store store, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
|
||||
class BindingsHandler {
|
||||
|
@ -328,9 +328,4 @@ namespace llvm {
|
||||
llvm::raw_ostream& operator<<(llvm::raw_ostream& Out,
|
||||
const clang::SymExpr *SE);
|
||||
}
|
||||
namespace std {
|
||||
std::ostream& operator<<(std::ostream& Out,
|
||||
const clang::SymExpr *SE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -87,14 +87,18 @@ class ValueManager {
|
||||
return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const IntegerLiteral* I) {
|
||||
nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
|
||||
I->getType()->isUnsignedIntegerType()));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const llvm::APSInt& V) {
|
||||
nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
|
||||
loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
|
||||
return loc::ConcreteInt(BasicVals.getValue(v));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
|
||||
|
@ -60,6 +60,12 @@ def warn_pch_heinous_extensions : Error<
|
||||
def warn_pch_lax_vector_conversions : Error<
|
||||
"lax vector conversions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_altivec : Error<
|
||||
"AltiVec initializers were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_opencl : Error<
|
||||
"OpenCL language extensions were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_exceptions : Error<
|
||||
"exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
|
@ -398,6 +398,15 @@ def err_init_reference_member_uninitialized : Error<
|
||||
def note_uninit_reference_member : Note<
|
||||
"uninitialized reference member is here">;
|
||||
|
||||
// C++0x auto
|
||||
def err_auto_variable_cannot_appear_in_own_initializer : Error<
|
||||
"variable %0 declared with 'auto' type cannot appear in its own initializer">;
|
||||
def err_illegal_decl_array_of_auto : Error<
|
||||
"'%0' declared as array of 'auto'">;
|
||||
def err_auto_not_allowed : Error<
|
||||
"'auto' not allowed in %select{function prototype|struct member|union member"
|
||||
"|class member|exception declaration|template parameter|block literal}0">;
|
||||
|
||||
// Objective-C++
|
||||
def err_objc_decls_may_only_appear_in_global_scope : Error<
|
||||
"Objective-C declarations may only appear in global scope">;
|
||||
@ -584,6 +593,12 @@ def err_defining_default_ctor : Error<
|
||||
"%2 does not have any default constructor">;
|
||||
def note_previous_class_decl : Note<
|
||||
"%0 declared here">;
|
||||
def err_uninitialized_member_for_assign : Error<
|
||||
"cannot define the implicit default assignment operator for %0, because "
|
||||
"non-static %select{reference|const}1 member %2 can't use default "
|
||||
"assignment operator">;
|
||||
def note_first_required_here : Note<
|
||||
"synthesized method is first required here">;
|
||||
def err_unintialized_member : Error<
|
||||
"cannot define the implicit default constructor for %0, because "
|
||||
"%select{reference|const}1 member %2 cannot be default-initialized">;
|
||||
@ -651,6 +666,7 @@ def note_template_export_unsupported : Note<
|
||||
def err_template_outside_namespace_or_class_scope : Error<
|
||||
"templates can only be declared in namespace or class scope">;
|
||||
def err_template_linkage : Error<"templates must have C++ linkage">;
|
||||
def err_template_typedef : Error<"a typedef cannot be a template">;
|
||||
def err_template_unnamed_class : Error<
|
||||
"cannot declare a class template with no name">;
|
||||
def err_template_param_list_different_arity : Error<
|
||||
@ -697,14 +713,15 @@ def err_template_arg_must_be_expr : Error<
|
||||
def err_template_arg_nontype_ambig : Error<
|
||||
"template argument for non-type template parameter is treated as type %0">;
|
||||
def err_template_arg_must_be_template : Error<
|
||||
"template argument for template template parameter must be a template">;
|
||||
"template argument for template template parameter must be a class template">;
|
||||
def err_template_arg_local_type : Error<"template argument uses local type %0">;
|
||||
def err_template_arg_unnamed_type : Error<
|
||||
"template argument uses unnamed type">;
|
||||
def note_template_unnamed_type_here : Note<
|
||||
"unnamed type used in template argument was declared here">;
|
||||
def err_template_arg_not_class_template : Error<
|
||||
"template argument does not refer to a class template">;
|
||||
"template argument does not refer to a class template or template "
|
||||
"template parameter">;
|
||||
def note_template_arg_refers_here_func : Note<
|
||||
"template argument refers to function template %0, here">;
|
||||
def err_template_arg_template_params_mismatch : Error<
|
||||
@ -813,6 +830,9 @@ def note_template_member_class_here : Note<
|
||||
"in instantiation of member class %0 requested here">;
|
||||
def note_template_member_function_here : Note<
|
||||
"in instantiation of member function %q0 requested here">;
|
||||
def note_function_template_spec_here : Note<
|
||||
"in instantiation of function template specialization %q0 requested here">;
|
||||
|
||||
def note_default_arg_instantiation_here : Note<
|
||||
"in instantiation of default argument for '%0' required here">;
|
||||
def note_partial_spec_deduct_instantiation_here : Note<
|
||||
@ -1602,6 +1622,14 @@ def err_anonymous_record_nonpublic_member : Error<
|
||||
"anonymous %select{struct|union}0 cannot contain a "
|
||||
"%select{private|protected}1 data member">;
|
||||
|
||||
// C++ local classes
|
||||
def err_reference_to_local_var_in_enclosing_function : Error<
|
||||
"reference to local variable %0 declared in enclosed function %1">;
|
||||
def note_local_variable_declared_here : Note<
|
||||
"%0 declared here">;
|
||||
def err_static_data_member_not_allowed_in_local_class : Error<
|
||||
"static data member %0 not allowed in local class %1">;
|
||||
|
||||
// C++ derived classes
|
||||
def err_base_clause_on_union : Error<"unions cannot have base classes">;
|
||||
def err_base_must_be_class : Error<"base specifier must name a class">;
|
||||
@ -1841,6 +1869,9 @@ def err_selector_element_type : Error<
|
||||
def err_collection_expr_type : Error<
|
||||
"collection expression type %0 is not a valid object">;
|
||||
|
||||
def err_invalid_conversion_between_ext_vectors : Error<
|
||||
"invalid conversion between ext-vector type %0 and %1">;
|
||||
|
||||
// Type
|
||||
def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
|
||||
def warn_receiver_forward_class : Warning<
|
||||
|
@ -43,6 +43,7 @@ class LangOptions {
|
||||
unsigned PascalStrings : 1; // Allow Pascal strings
|
||||
unsigned WritableStrings : 1; // Allow writable strings
|
||||
unsigned LaxVectorConversions : 1;
|
||||
unsigned AltiVec : 1; // Support AltiVec-style vector initializers.
|
||||
unsigned Exceptions : 1; // Support exception handling.
|
||||
|
||||
unsigned NeXTRuntime : 1; // Use NeXT runtime.
|
||||
@ -80,6 +81,10 @@ class LangOptions {
|
||||
unsigned AccessControl : 1; // Whether C++ access control should
|
||||
// be enabled.
|
||||
unsigned CharIsSigned : 1; // Whether char is a signed or unsigned type
|
||||
|
||||
unsigned OpenCL : 1; // OpenCL C99 language extensions.
|
||||
|
||||
|
||||
private:
|
||||
unsigned GC : 2; // Objective-C Garbage Collection modes. We declare
|
||||
// this enum as unsigned because MSVC insists on making enums
|
||||
@ -111,6 +116,7 @@ class LangOptions {
|
||||
Exceptions = NeXTRuntime = Freestanding = NoBuiltin = 0;
|
||||
LaxVectorConversions = 1;
|
||||
HeinousExtensions = 0;
|
||||
AltiVec = OpenCL = 0;
|
||||
|
||||
SymbolVisibility = (unsigned) Default;
|
||||
|
||||
|
@ -326,6 +326,11 @@ class SourceManager {
|
||||
// Statistics for -print-stats.
|
||||
mutable unsigned NumLinearScans, NumBinaryProbes;
|
||||
|
||||
// Cache results for the isBeforeInTranslationUnit method.
|
||||
mutable FileID LastLFIDForBeforeTUCheck;
|
||||
mutable FileID LastRFIDForBeforeTUCheck;
|
||||
mutable bool LastResForBeforeTUCheck;
|
||||
|
||||
// SourceManager doesn't support copy construction.
|
||||
explicit SourceManager(const SourceManager&);
|
||||
void operator=(const SourceManager&);
|
||||
@ -637,6 +642,11 @@ class SourceManager {
|
||||
SourceLocation getLocation(const FileEntry *SourceFile,
|
||||
unsigned Line, unsigned Col) const;
|
||||
|
||||
/// \brief Determines the order of 2 source locations in the translation unit.
|
||||
///
|
||||
/// \returns true if LHS source location comes before RHS, false otherwise.
|
||||
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
|
||||
|
||||
// Iterators over FileInfos.
|
||||
typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
|
||||
::const_iterator fileinfo_iterator;
|
||||
|
@ -224,7 +224,7 @@ KEYWORD(__func__ , KEYALL)
|
||||
|
||||
// C++ 2.11p1: Keywords.
|
||||
KEYWORD(asm , KEYCXX|KEYGNU)
|
||||
KEYWORD(bool , KEYCXX)
|
||||
KEYWORD(bool , KEYCXX|BOOLSUPPORT)
|
||||
KEYWORD(catch , KEYCXX)
|
||||
KEYWORD(class , KEYCXX)
|
||||
KEYWORD(const_cast , KEYCXX)
|
||||
@ -232,7 +232,7 @@ KEYWORD(delete , KEYCXX)
|
||||
KEYWORD(dynamic_cast , KEYCXX)
|
||||
KEYWORD(explicit , KEYCXX)
|
||||
KEYWORD(export , KEYCXX)
|
||||
KEYWORD(false , KEYCXX)
|
||||
KEYWORD(false , KEYCXX|BOOLSUPPORT)
|
||||
KEYWORD(friend , KEYCXX)
|
||||
KEYWORD(mutable , KEYCXX)
|
||||
KEYWORD(namespace , KEYCXX)
|
||||
@ -246,7 +246,7 @@ KEYWORD(static_cast , KEYCXX)
|
||||
KEYWORD(template , KEYCXX)
|
||||
KEYWORD(this , KEYCXX)
|
||||
KEYWORD(throw , KEYCXX)
|
||||
KEYWORD(true , KEYCXX)
|
||||
KEYWORD(true , KEYCXX|BOOLSUPPORT)
|
||||
KEYWORD(try , KEYCXX)
|
||||
KEYWORD(typename , KEYCXX)
|
||||
KEYWORD(typeid , KEYCXX)
|
||||
|
@ -41,13 +41,9 @@ ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc",
|
||||
ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
|
||||
"Warn about private ivars that are never used", ObjCImplementation)
|
||||
|
||||
ANALYSIS(CheckerSimple, "checker-simple",
|
||||
"Perform simple path-sensitive checks.", Code)
|
||||
|
||||
ANALYSIS(CheckerCFRef, "checker-cfref",
|
||||
"Run the [Core] Foundation reference count checker", Code)
|
||||
|
||||
|
||||
#ifndef ANALYSIS_STORE
|
||||
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
|
||||
#endif
|
||||
|
85
include/clang/Frontend/CommandLineSourceLoc.h
Normal file
85
include/clang/Frontend/CommandLineSourceLoc.h
Normal file
@ -0,0 +1,85 @@
|
||||
//===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Command line parsing for source locations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
|
||||
#define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief A source location that has been parsed on the command line.
|
||||
struct ParsedSourceLocation {
|
||||
std::string FileName;
|
||||
unsigned Line;
|
||||
unsigned Column;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace cl {
|
||||
/// \brief Command-line option parser that parses source locations.
|
||||
///
|
||||
/// Source locations are of the form filename:line:column.
|
||||
template<>
|
||||
class parser<clang::ParsedSourceLocation>
|
||||
: public basic_parser<clang::ParsedSourceLocation> {
|
||||
public:
|
||||
bool parse(Option &O, const char *ArgName,
|
||||
const std::string &ArgValue,
|
||||
clang::ParsedSourceLocation &Val);
|
||||
};
|
||||
|
||||
bool
|
||||
parser<clang::ParsedSourceLocation>::
|
||||
parse(Option &O, const char *ArgName, const std::string &ArgValue,
|
||||
clang::ParsedSourceLocation &Val) {
|
||||
using namespace clang;
|
||||
|
||||
const char *ExpectedFormat
|
||||
= "source location must be of the form filename:line:column";
|
||||
std::string::size_type SecondColon = ArgValue.rfind(':');
|
||||
if (SecondColon == std::string::npos) {
|
||||
std::fprintf(stderr, "%s\n", ExpectedFormat);
|
||||
return true;
|
||||
}
|
||||
char *EndPtr;
|
||||
long Column
|
||||
= std::strtol(ArgValue.c_str() + SecondColon + 1, &EndPtr, 10);
|
||||
if (EndPtr != ArgValue.c_str() + ArgValue.size()) {
|
||||
std::fprintf(stderr, "%s\n", ExpectedFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1);
|
||||
if (FirstColon == std::string::npos) {
|
||||
std::fprintf(stderr, "%s\n", ExpectedFormat);
|
||||
return true;
|
||||
}
|
||||
long Line = std::strtol(ArgValue.c_str() + FirstColon + 1, &EndPtr, 10);
|
||||
if (EndPtr != ArgValue.c_str() + SecondColon) {
|
||||
std::fprintf(stderr, "%s\n", ExpectedFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
Val.FileName = ArgValue.substr(0, FirstColon);
|
||||
Val.Line = Line;
|
||||
Val.Column = Column;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -387,7 +387,9 @@ namespace clang {
|
||||
/// \brief An ObjCQualifiedInterfaceType record.
|
||||
TYPE_OBJC_QUALIFIED_INTERFACE = 22,
|
||||
/// \brief An ObjCObjectPointerType record.
|
||||
TYPE_OBJC_OBJECT_POINTER = 23
|
||||
TYPE_OBJC_OBJECT_POINTER = 23,
|
||||
/// \brief a DecltypeType record.
|
||||
TYPE_DECLTYPE = 24
|
||||
};
|
||||
|
||||
/// \brief The type IDs for special types constructed by semantic
|
||||
|
@ -32,6 +32,10 @@ class IdentifierTable;
|
||||
class SourceManager;
|
||||
class PreprocessorFactory;
|
||||
class LangOptions;
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class ASTContext;
|
||||
class SourceLocation;
|
||||
|
||||
/// ProcessWarningOptions - Initialize the diagnostic client and process the
|
||||
/// warning options specified on the command line.
|
||||
@ -74,6 +78,33 @@ void AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
|
||||
/// a seekable stream.
|
||||
void CacheTokens(Preprocessor& PP, llvm::raw_fd_ostream* OS);
|
||||
|
||||
/// \brief Returns the AST node that a source location points to.
|
||||
///
|
||||
/// Returns a pair of Decl* and Stmt*. If no AST node is found for the source
|
||||
/// location, the pair will contain null pointers.
|
||||
///
|
||||
/// If the source location points to just a declaration, the statement part of
|
||||
/// the pair will be null, e.g.,
|
||||
/// @code
|
||||
/// int foo;
|
||||
/// @endcode
|
||||
/// If the source location points at 'foo', the pair will contain the VarDecl
|
||||
/// of foo and a null Stmt.
|
||||
///
|
||||
/// If the source location points to a statement node, the returned declaration
|
||||
/// will be the immediate 'parent' declaration of the statement node, e.g.,
|
||||
/// @code
|
||||
/// void f() {
|
||||
/// int foo = 100;
|
||||
/// ++foo;
|
||||
/// }
|
||||
/// @endcode
|
||||
/// Pointing at '100' will return a <VarDecl 'foo', IntegerLiteral '100'> pair.
|
||||
/// Pointing at '++foo' will return a <FunctionDecl 'f', UnaryOperator> pair.
|
||||
///
|
||||
std::pair<Decl *, Stmt *> ResolveLocationInAST(ASTContext &Ctx,
|
||||
SourceLocation Loc);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -967,12 +967,13 @@ class Action : public ActionBase {
|
||||
|
||||
/// ActOnUsingDirective - This is called when using-directive is parsed.
|
||||
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
|
||||
SourceLocation UsingLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdentLoc,
|
||||
IdentifierInfo *TargetName,
|
||||
AttributeList *AttrList,
|
||||
bool IsTypeName);
|
||||
SourceLocation UsingLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdentLoc,
|
||||
IdentifierInfo *TargetName,
|
||||
OverloadedOperatorKind Op,
|
||||
AttributeList *AttrList,
|
||||
bool IsTypeName);
|
||||
|
||||
/// ActOnParamDefaultArgument - Parse default argument for function parameter
|
||||
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
|
||||
@ -1453,6 +1454,26 @@ class Action : public ActionBase {
|
||||
return DeclResult();
|
||||
}
|
||||
|
||||
/// \brief Invoked when a declarator that has one or more template parameter
|
||||
/// lists has been parsed.
|
||||
///
|
||||
/// This action is similar to ActOnDeclarator(), except that the declaration
|
||||
/// being created somehow involves a template, e.g., it is a template
|
||||
/// declaration or specialization.
|
||||
virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D) {
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
/// \brief Invoked when the parser is beginning to parse a function template
|
||||
/// or function template specialization definition.
|
||||
virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D) {
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
/// \brief Process the explicit instantiation of a class template
|
||||
/// specialization.
|
||||
///
|
||||
|
@ -97,6 +97,7 @@ class AttributeList {
|
||||
AT_warn_unused_result,
|
||||
AT_weak,
|
||||
AT_weak_import,
|
||||
AT_reqd_wg_size,
|
||||
IgnoredAttribute,
|
||||
UnknownAttribute
|
||||
};
|
||||
|
@ -82,6 +82,8 @@ class DeclSpec {
|
||||
TST_typename, // Typedef, C++ class-name or enum name, etc.
|
||||
TST_typeofType,
|
||||
TST_typeofExpr,
|
||||
TST_decltype, // C++0x decltype
|
||||
TST_auto, // C++0x auto
|
||||
TST_error // erroneous type
|
||||
};
|
||||
|
||||
|
@ -636,7 +636,8 @@ class Parser {
|
||||
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
|
||||
AccessSpecifier AS = AS_none);
|
||||
|
||||
DeclPtrTy ParseFunctionDefinition(Declarator &D);
|
||||
DeclPtrTy ParseFunctionDefinition(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
|
||||
void ParseKNRParamDeclarations(Declarator &D);
|
||||
// EndLoc, if non-NULL, is filled with the location of the last token of
|
||||
// the simple-asm.
|
||||
@ -909,7 +910,8 @@ class Parser {
|
||||
DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
bool RequireSemi = true);
|
||||
DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D);
|
||||
DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
|
||||
DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D);
|
||||
DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl);
|
||||
DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl);
|
||||
@ -1069,6 +1071,7 @@ class Parser {
|
||||
AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0);
|
||||
AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0);
|
||||
void ParseTypeofSpecifier(DeclSpec &DS);
|
||||
void ParseDecltypeSpecifier(DeclSpec &DS);
|
||||
|
||||
/// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
|
||||
/// enter a new C++ declarator scope and exit it when the function is
|
||||
@ -1190,7 +1193,7 @@ class Parser {
|
||||
TemplateArgLocationList &TemplateArgLocations,
|
||||
SourceLocation &RAngleLoc);
|
||||
|
||||
void AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
const CXXScopeSpec *SS,
|
||||
SourceLocation TemplateKWLoc = SourceLocation(),
|
||||
bool AllowTypeAnnotation = true);
|
||||
|
@ -179,6 +179,10 @@ void ASTContext::InitBuiltinTypes() {
|
||||
// expressions.
|
||||
InitBuiltinType(DependentTy, BuiltinType::Dependent);
|
||||
|
||||
// Placeholder type for C++0x auto declarations whose real type has
|
||||
// not yet been deduced.
|
||||
InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
|
||||
|
||||
// C99 6.2.5p11.
|
||||
FloatComplexTy = getComplexType(FloatTy);
|
||||
DoubleComplexTy = getComplexType(DoubleTy);
|
||||
@ -460,6 +464,10 @@ ASTContext::getTypeInfo(const Type *T) {
|
||||
case Type::TypeOf:
|
||||
return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
|
||||
|
||||
case Type::Decltype:
|
||||
return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
|
||||
.getTypePtr());
|
||||
|
||||
case Type::QualifiedName:
|
||||
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
|
||||
|
||||
@ -1659,6 +1667,50 @@ QualType ASTContext::getTypeOfType(QualType tofType) {
|
||||
return QualType(tot, 0);
|
||||
}
|
||||
|
||||
/// getDecltypeForExpr - Given an expr, will return the decltype for that
|
||||
/// expression, according to the rules in C++0x [dcl.type.simple]p4
|
||||
static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
|
||||
if (e->isTypeDependent())
|
||||
return Context.DependentTy;
|
||||
|
||||
// If e is an id expression or a class member access, decltype(e) is defined
|
||||
// as the type of the entity named by e.
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
|
||||
if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
|
||||
return VD->getType();
|
||||
}
|
||||
if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) {
|
||||
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
|
||||
return FD->getType();
|
||||
}
|
||||
// If e is a function call or an invocation of an overloaded operator,
|
||||
// (parentheses around e are ignored), decltype(e) is defined as the
|
||||
// return type of that function.
|
||||
if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
|
||||
return CE->getCallReturnType();
|
||||
|
||||
QualType T = e->getType();
|
||||
|
||||
// Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
|
||||
// defined as T&, otherwise decltype(e) is defined as T.
|
||||
if (e->isLvalue(Context) == Expr::LV_Valid)
|
||||
T = Context.getLValueReferenceType(T);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
|
||||
/// DecltypeType AST's. The only motivation to unique these nodes would be
|
||||
/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
|
||||
/// an issue. This doesn't effect the type checker, since it operates
|
||||
/// on canonical type's (which are always unique).
|
||||
QualType ASTContext::getDecltypeType(Expr *e) {
|
||||
QualType T = getDecltypeForExpr(e, *this);
|
||||
DecltypeType *dt = new (*this, 8) DecltypeType(e, getCanonicalType(T));
|
||||
Types.push_back(dt);
|
||||
return QualType(dt, 0);
|
||||
}
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType ASTContext::getTagDeclType(TagDecl *Decl) {
|
||||
|
@ -22,9 +22,6 @@
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <llvm/Support/Allocator.h>
|
||||
#include <llvm/Support/Format.h>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -1887,7 +1884,8 @@ void CFG::viewCFG() const {
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
|
||||
static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
|
||||
static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
|
||||
bool ShortNames) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::string OutSStr;
|
||||
|
@ -269,6 +269,14 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
|
||||
// For function declarations, we keep track of redeclarations.
|
||||
return FD->getPreviousDeclaration() == OldD;
|
||||
|
||||
// For function templates, the underlying function declarations are linked.
|
||||
if (const FunctionTemplateDecl *FunctionTemplate
|
||||
= dyn_cast<FunctionTemplateDecl>(this))
|
||||
if (const FunctionTemplateDecl *OldFunctionTemplate
|
||||
= dyn_cast<FunctionTemplateDecl>(OldD))
|
||||
return FunctionTemplate->getTemplatedDecl()
|
||||
->declarationReplaces(OldFunctionTemplate->getTemplatedDecl());
|
||||
|
||||
// For method declarations, we keep track of redeclarations.
|
||||
if (isa<ObjCMethodDecl>(this))
|
||||
return false;
|
||||
@ -289,6 +297,19 @@ bool NamedDecl::hasLinkage() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
NamedDecl *NamedDecl::getUnderlyingDecl() {
|
||||
NamedDecl *ND = this;
|
||||
while (true) {
|
||||
if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
|
||||
ND = UD->getTargetDecl();
|
||||
else if (ObjCCompatibleAliasDecl *AD
|
||||
= dyn_cast<ObjCCompatibleAliasDecl>(ND))
|
||||
return AD->getClassInterface();
|
||||
else
|
||||
return ND;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VarDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -351,6 +372,10 @@ void FunctionDecl::Destroy(ASTContext& C) {
|
||||
|
||||
C.Deallocate(ParamInfo);
|
||||
|
||||
if (TemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>())
|
||||
C.Deallocate(Info);
|
||||
|
||||
Decl::Destroy(C);
|
||||
}
|
||||
|
||||
@ -547,6 +572,20 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
|
||||
return OO_None;
|
||||
}
|
||||
|
||||
void
|
||||
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs) {
|
||||
TemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<TemplateSpecializationInfo*>();
|
||||
if (!Info)
|
||||
Info = new (Context) TemplateSpecializationInfo;
|
||||
|
||||
Info->Template = Template;
|
||||
Info->TemplateArguments = TemplateArgs;
|
||||
TemplateOrSpecialization = Info;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TagDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -96,6 +96,13 @@ bool Decl::isTemplateParameterPack() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Decl::isFunctionOrFunctionTemplate() const {
|
||||
if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
|
||||
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
|
||||
|
||||
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PrettyStackTraceDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -420,6 +420,15 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
return new (C) OverloadedFunctionDecl(DC, N);
|
||||
}
|
||||
|
||||
void OverloadedFunctionDecl::addOverload(FunctionTemplateDecl *FTD) {
|
||||
Functions.push_back(FTD);
|
||||
|
||||
// An overloaded function declaration always has the location of
|
||||
// the most-recently-added function declaration.
|
||||
if (FTD->getLocation().isValid())
|
||||
this->setLocation(FTD->getLocation());
|
||||
}
|
||||
|
||||
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
||||
DeclContext *DC,
|
||||
SourceLocation L,
|
||||
|
@ -1496,7 +1496,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
|
||||
return false;
|
||||
|
||||
// Advance past s-char prefix on hex swizzles.
|
||||
if (*compStr == 's') {
|
||||
if (*compStr == 's' || *compStr == 'S') {
|
||||
compStr++;
|
||||
length--;
|
||||
}
|
||||
@ -1514,7 +1514,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const {
|
||||
void ExtVectorElementExpr::getEncodedElementAccess(
|
||||
llvm::SmallVectorImpl<unsigned> &Elts) const {
|
||||
const char *compStr = Accessor->getName();
|
||||
if (*compStr == 's')
|
||||
if (*compStr == 's' || *compStr == 'S')
|
||||
compStr++;
|
||||
|
||||
bool isHi = !strcmp(compStr, "hi");
|
||||
|
@ -486,12 +486,28 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
|
||||
|
||||
APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
|
||||
const Expr* SE = E->getSubExpr();
|
||||
QualType SETy = SE->getType();
|
||||
APValue Result = APValue();
|
||||
|
||||
// Check for vector->vector bitcast.
|
||||
if (SE->getType()->isVectorType())
|
||||
// Check for vector->vector bitcast and scalar->vector splat.
|
||||
if (SETy->isVectorType()) {
|
||||
return this->Visit(const_cast<Expr*>(SE));
|
||||
} else if (SETy->isIntegerType()) {
|
||||
APSInt IntResult;
|
||||
if (EvaluateInteger(SE, IntResult, Info))
|
||||
Result = APValue(IntResult);
|
||||
} else if (SETy->isRealFloatingType()) {
|
||||
APFloat F(0.0);
|
||||
if (EvaluateFloat(SE, F, Info))
|
||||
Result = APValue(F);
|
||||
}
|
||||
|
||||
return APValue();
|
||||
if (Result.isInt() || Result.isFloat()) {
|
||||
unsigned NumElts = E->getType()->getAsVectorType()->getNumElements();
|
||||
llvm::SmallVector<APValue, 4> Elts(NumElts, Result);
|
||||
Result = APValue(&Elts[0], Elts.size());
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
APValue
|
||||
|
@ -31,7 +31,8 @@ void Stmt::viewAST() const {
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
|
||||
static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
|
||||
static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph,
|
||||
bool ShortNames) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::string OutSStr;
|
||||
|
@ -112,6 +112,8 @@ QualType Type::getDesugaredType(bool ForDisplay) const {
|
||||
return TOE->getUnderlyingExpr()->getType().getDesugaredType();
|
||||
if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
|
||||
return TOT->getUnderlyingType().getDesugaredType();
|
||||
if (const DecltypeType *DTT = dyn_cast<DecltypeType>(this))
|
||||
return DTT->getUnderlyingExpr()->getType().getDesugaredType();
|
||||
if (const TemplateSpecializationType *Spec
|
||||
= dyn_cast<TemplateSpecializationType>(this)) {
|
||||
if (ForDisplay)
|
||||
@ -962,6 +964,7 @@ const char *BuiltinType::getName(bool CPlusPlus) const {
|
||||
case NullPtr: return "nullptr_t";
|
||||
case Overload: return "<overloaded function type>";
|
||||
case Dependent: return "<dependent type>";
|
||||
case UndeducedAuto: return "<undeduced auto type>";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1052,6 +1055,13 @@ TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
|
||||
assert(!isa<TypedefType>(can) && "Invalid canonical type");
|
||||
}
|
||||
|
||||
DecltypeType::DecltypeType(Expr *E, QualType can)
|
||||
: Type(Decltype, can, E->isTypeDependent()), E(E) {
|
||||
assert(can->isDependentType() == E->isTypeDependent() &&
|
||||
"type dependency mismatch!");
|
||||
assert(!isa<TypedefType>(can) && "Invalid canonical type");
|
||||
}
|
||||
|
||||
TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
|
||||
: Type(TC, can, D->isDependentType()), decl(D, 0) {}
|
||||
|
||||
@ -1421,6 +1431,16 @@ void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPol
|
||||
InnerString = "typeof(" + Tmp + ")" + InnerString;
|
||||
}
|
||||
|
||||
void DecltypeType::getAsStringInternal(std::string &InnerString,
|
||||
const PrintingPolicy &Policy) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::string Str;
|
||||
llvm::raw_string_ostream s(Str);
|
||||
getUnderlyingExpr()->printPretty(s, 0, Policy);
|
||||
InnerString = "decltype(" + s.str() + ")" + InnerString;
|
||||
}
|
||||
|
||||
void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
|
||||
// If needed for precedence reasons, wrap the inner part in grouping parens.
|
||||
if (!S.empty())
|
||||
|
@ -83,7 +83,7 @@ class VISIBILITY_HIDDEN BasicConstraintManager
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper);
|
||||
|
||||
void print(const GRState* state, std::ostream& Out,
|
||||
void print(const GRState* state, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep);
|
||||
};
|
||||
|
||||
@ -280,7 +280,7 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state,
|
||||
return state->set<ConstNotEq>(CNE);
|
||||
}
|
||||
|
||||
void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
|
||||
void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep) {
|
||||
// Print equality constraints.
|
||||
|
||||
@ -288,12 +288,8 @@ void BasicConstraintManager::print(const GRState* state, std::ostream& Out,
|
||||
|
||||
if (!CE.isEmpty()) {
|
||||
Out << nl << sep << "'==' constraints:";
|
||||
|
||||
for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
|
||||
Out << nl << " $" << I.getKey();
|
||||
llvm::raw_os_ostream OS(Out);
|
||||
OS << " : " << *I.getData();
|
||||
}
|
||||
for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
|
||||
Out << nl << " $" << I.getKey() << " : " << *I.getData();
|
||||
}
|
||||
|
||||
// Print != constraints.
|
||||
|
@ -112,7 +112,8 @@ class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
|
||||
return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
|
||||
}
|
||||
|
||||
void print(Store store, std::ostream& Out, const char* nl, const char *sep);
|
||||
void print(Store store, llvm::raw_ostream& Out, const char* nl,
|
||||
const char *sep);
|
||||
|
||||
private:
|
||||
ASTContext& getContext() { return StateMgr.getContext(); }
|
||||
@ -535,7 +536,7 @@ Store BasicStoreManager::getInitialStore() {
|
||||
|
||||
// Initialize globals and parameters to symbolic values.
|
||||
// Initialize local variables to undefined.
|
||||
const MemRegion *R = StateMgr.getRegion(VD);
|
||||
const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD);
|
||||
SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
|
||||
isa<ImplicitParamDecl>(VD))
|
||||
? ValMgr.getRegionValueSymbolVal(R)
|
||||
@ -602,18 +603,19 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
|
||||
return store;
|
||||
}
|
||||
|
||||
void BasicStoreManager::print(Store store, std::ostream& O,
|
||||
void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep) {
|
||||
|
||||
llvm::raw_os_ostream Out(O);
|
||||
BindingsTy B = GetBindings(store);
|
||||
Out << "Variables:" << nl;
|
||||
|
||||
bool isFirst = true;
|
||||
|
||||
for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
|
||||
if (isFirst) isFirst = false;
|
||||
else Out << nl;
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
Out << nl;
|
||||
|
||||
Out << ' ' << I.getKey() << " : ";
|
||||
I.getData().print(Out);
|
||||
|
@ -8,7 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines BugReporter, a utility class for generating
|
||||
// PathDiagnostics for analyses based on GRSimpleVals.
|
||||
// PathDiagnostics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRSimpleVals.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
|
||||
@ -22,6 +21,7 @@
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/Analysis/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
@ -30,7 +30,6 @@
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <ostream>
|
||||
#include <stdarg.h>
|
||||
|
||||
using namespace clang;
|
||||
@ -1674,10 +1673,10 @@ class VISIBILITY_HIDDEN RefVal {
|
||||
ID.Add(T);
|
||||
}
|
||||
|
||||
void print(std::ostream& Out) const;
|
||||
void print(llvm::raw_ostream& Out) const;
|
||||
};
|
||||
|
||||
void RefVal::print(std::ostream& Out) const {
|
||||
void RefVal::print(llvm::raw_ostream& Out) const {
|
||||
if (!T.isNull())
|
||||
Out << "Tracked Type:" << T.getAsString() << '\n';
|
||||
|
||||
@ -1827,11 +1826,11 @@ static const GRState * SendAutorelease(const GRState *state,
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
|
||||
class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
|
||||
public:
|
||||
class BindingsPrinter : public GRState::Printer {
|
||||
public:
|
||||
virtual void Print(std::ostream& Out, const GRState* state,
|
||||
virtual void Print(llvm::raw_ostream& Out, const GRState* state,
|
||||
const char* nl, const char* sep);
|
||||
};
|
||||
|
||||
@ -1959,7 +1958,8 @@ class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
|
||||
static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
|
||||
const GRState *state) {
|
||||
Out << ' ';
|
||||
if (Sym)
|
||||
Out << Sym->getSymbolID();
|
||||
@ -1975,10 +1975,9 @@ static void PrintPool(std::ostream &Out, SymbolRef Sym, const GRState *state) {
|
||||
Out << '}';
|
||||
}
|
||||
|
||||
void CFRefCount::BindingsPrinter::Print(std::ostream& Out, const GRState* state,
|
||||
void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
|
||||
const GRState* state,
|
||||
const char* nl, const char* sep) {
|
||||
|
||||
|
||||
|
||||
RefBindings B = state->get<RefBindings>();
|
||||
|
||||
@ -2790,10 +2789,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
if (Summ.getArg(idx) == DoNothingByRef)
|
||||
continue;
|
||||
|
||||
// Invalidate the value of the variable passed by reference.
|
||||
|
||||
// FIXME: Either this logic should also be replicated in GRSimpleVals
|
||||
// or should be pulled into a separate "constraint engine."
|
||||
// Invalidate the value of the variable passed by reference.
|
||||
|
||||
// FIXME: We can have collisions on the conjured symbol if the
|
||||
// expression *I also creates conjured symbols. We probably want
|
||||
@ -2942,11 +2938,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||
default:
|
||||
assert (false && "Unhandled RetEffect."); break;
|
||||
|
||||
case RetEffect::NoRet: {
|
||||
|
||||
case RetEffect::NoRet: {
|
||||
// Make up a symbol for the return value (not reference counted).
|
||||
// FIXME: This is basically copy-and-paste from GRSimpleVals. We
|
||||
// should compose behavior, not copy it.
|
||||
// FIXME: Most of this logic is not specific to the retain/release
|
||||
// checker.
|
||||
|
||||
// FIXME: We eventually should handle structs and other compound types
|
||||
// that are returned by value.
|
||||
@ -3091,7 +3086,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
if (Expr* Receiver = ME->getReceiver()) {
|
||||
SVal X = St->getSValAsScalarOrLoc(Receiver);
|
||||
if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
|
||||
if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
|
||||
if (L->getRegion() == St->getSelfRegion()) {
|
||||
// Update the summary to make the default argument effect
|
||||
// 'StopTracking'.
|
||||
Summ = Summaries.copySummary(Summ);
|
||||
|
@ -18,15 +18,14 @@ add_clang_library(clangAnalysis
|
||||
GRCoreEngine.cpp
|
||||
GRExprEngine.cpp
|
||||
GRExprEngineInternalChecks.cpp
|
||||
GRSimpleVals.cpp
|
||||
GRState.cpp
|
||||
GRTransferFuncs.cpp
|
||||
LiveVariables.cpp
|
||||
MemRegion.cpp
|
||||
PathDiagnostic.cpp
|
||||
RangeConstraintManager.cpp
|
||||
RegionStore.cpp
|
||||
SimpleConstraintManager.cpp
|
||||
SimpleSValuator.cpp
|
||||
Store.cpp
|
||||
SVals.cpp
|
||||
SymbolManager.cpp
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -97,8 +96,8 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
|
||||
// Find ivars that are unused.
|
||||
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
|
||||
if (I->second == Unused) {
|
||||
|
||||
std::ostringstream os;
|
||||
std::string sbuf;
|
||||
llvm::raw_string_ostream os(sbuf);
|
||||
os << "Instance variable '" << I->first->getNameAsString()
|
||||
<< "' in class '" << ID->getNameAsString()
|
||||
<< "' is never used by the methods in its @implementation "
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
@ -29,7 +28,6 @@
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
using namespace clang;
|
||||
@ -126,6 +124,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx,
|
||||
StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L),
|
||||
SymMgr(StateMgr.getSymbolManager()),
|
||||
ValMgr(StateMgr.getValueManager()),
|
||||
SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later.
|
||||
CurrentStmt(NULL),
|
||||
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
|
||||
RaiseSel(GetNullarySelector("raise", G.getContext())),
|
||||
@ -176,7 +175,7 @@ const GRState* GRExprEngine::getInitialState() {
|
||||
const ParmVarDecl *PD = FD->getParamDecl(0);
|
||||
QualType T = PD->getType();
|
||||
if (T->isIntegerType())
|
||||
if (const MemRegion *R = StateMgr.getRegion(PD)) {
|
||||
if (const MemRegion *R = state->getRegion(PD)) {
|
||||
SVal V = state->getSVal(loc::MemRegionVal(R));
|
||||
SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V,
|
||||
ValMgr.makeZeroVal(T),
|
||||
@ -1046,7 +1045,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
else {
|
||||
// We are binding to a value other than 'unknown'. Perform the binding
|
||||
// using the StoreManager.
|
||||
newState = StateMgr.BindLoc(state, cast<Loc>(location), Val);
|
||||
newState = state->bindLoc(cast<Loc>(location), Val);
|
||||
}
|
||||
|
||||
// The next thing to do is check if the GRTransferFuncs object wants to
|
||||
@ -1296,9 +1295,8 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst,
|
||||
SVal oldValueVal = stateLoad->getSVal(oldValueExpr);
|
||||
|
||||
// Perform the comparison.
|
||||
SVal Cmp = Engine.EvalBinOp(stateLoad,
|
||||
BinaryOperator::EQ, theValueVal, oldValueVal,
|
||||
Engine.getContext().IntTy);
|
||||
SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal,
|
||||
oldValueVal, Engine.getContext().IntTy);
|
||||
|
||||
const GRState *stateEqual = stateLoad->assume(Cmp, true);
|
||||
|
||||
@ -2247,17 +2245,17 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
|
||||
InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count);
|
||||
}
|
||||
|
||||
state = StateMgr.BindDecl(state, VD, InitVal);
|
||||
state = state->bindDecl(VD, InitVal);
|
||||
|
||||
// The next thing to do is check if the GRTransferFuncs object wants to
|
||||
// update the state based on the new binding. If the GRTransferFunc
|
||||
// object doesn't do anything, just auto-propagate the current state.
|
||||
GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true);
|
||||
getTF().EvalBind(BuilderRef, loc::MemRegionVal(StateMgr.getRegion(VD)),
|
||||
getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD)),
|
||||
InitVal);
|
||||
}
|
||||
else {
|
||||
state = StateMgr.BindDeclWithNoInit(state, VD);
|
||||
state = state->bindDeclWithNoInit(VD);
|
||||
MakeNode(Dst, DS, *I, state);
|
||||
}
|
||||
}
|
||||
@ -2562,7 +2560,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
|
||||
case UnaryOperator::Minus:
|
||||
// FIXME: Do we need to handle promotions?
|
||||
state = state->bindExpr(U, EvalMinus(U, cast<NonLoc>(V)));
|
||||
state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V)));
|
||||
break;
|
||||
|
||||
case UnaryOperator::LNot:
|
||||
@ -2571,25 +2569,21 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
//
|
||||
// Note: technically we do "E == 0", but this is the same in the
|
||||
// transfer functions as "0 == E".
|
||||
SVal Result;
|
||||
|
||||
if (isa<Loc>(V)) {
|
||||
Loc X = ValMgr.makeNull();
|
||||
SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X,
|
||||
U->getType());
|
||||
state = state->bindExpr(U, Result);
|
||||
Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X,
|
||||
U->getType());
|
||||
}
|
||||
else {
|
||||
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
|
||||
#if 0
|
||||
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
|
||||
state = SetSVal(state, U, Result);
|
||||
#else
|
||||
EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I,
|
||||
U->getType());
|
||||
continue;
|
||||
#endif
|
||||
Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X,
|
||||
U->getType());
|
||||
}
|
||||
|
||||
state = state->bindExpr(U, Result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2640,8 +2634,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
|
||||
Builder->getCurrentBlockCount());
|
||||
|
||||
// If the value is a location, ++/-- should always preserve
|
||||
// non-nullness. Check if the original value was non-null, and if so propagate
|
||||
// that constraint.
|
||||
// non-nullness. Check if the original value was non-null, and if so
|
||||
// propagate that constraint.
|
||||
if (Loc::IsLocType(U->getType())) {
|
||||
SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2,
|
||||
ValMgr.makeZeroVal(U->getType()),
|
||||
@ -2907,9 +2901,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
|
||||
if (B->isAssignmentOp())
|
||||
break;
|
||||
|
||||
// Process non-assignements except commas or short-circuited
|
||||
// logical expressions (LAnd and LOr).
|
||||
|
||||
// Process non-assignments except commas or short-circuited
|
||||
// logical expressions (LAnd and LOr).
|
||||
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
|
||||
|
||||
if (Result.isUnknown()) {
|
||||
@ -3024,7 +3017,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
|
||||
}
|
||||
|
||||
// Compute the result of the operation.
|
||||
SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
|
||||
SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
|
||||
B->getType());
|
||||
|
||||
if (Result.isUndef()) {
|
||||
@ -3073,26 +3066,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
|
||||
// Transfer-function Helpers.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R,
|
||||
ExplodedNode<GRState>* Pred, QualType T) {
|
||||
|
||||
GRStateSet OStates;
|
||||
EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T);
|
||||
|
||||
for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
|
||||
MakeNode(Dst, Ex, Pred, *I);
|
||||
}
|
||||
|
||||
void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state,
|
||||
Expr* Ex, BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R, QualType T) {
|
||||
|
||||
GRStateSet::AutoPopulate AP(OStates, state);
|
||||
if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T);
|
||||
}
|
||||
|
||||
SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
|
||||
SVal L, SVal R, QualType T) {
|
||||
|
||||
@ -3104,9 +3077,9 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
|
||||
|
||||
if (isa<Loc>(L)) {
|
||||
if (isa<Loc>(R))
|
||||
return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R));
|
||||
return SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
|
||||
else
|
||||
return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R));
|
||||
return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T);
|
||||
}
|
||||
|
||||
if (isa<Loc>(R)) {
|
||||
@ -3116,11 +3089,10 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
|
||||
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
|
||||
|
||||
// Commute the operands.
|
||||
return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L));
|
||||
return SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T);
|
||||
}
|
||||
else
|
||||
return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L),
|
||||
cast<NonLoc>(R), T);
|
||||
return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -3156,8 +3128,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
|
||||
std::ostringstream Out;
|
||||
static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*,
|
||||
bool ShortNames) {
|
||||
|
||||
std::string sbuf;
|
||||
llvm::raw_string_ostream Out(sbuf);
|
||||
|
||||
// Program Location.
|
||||
ProgramPoint Loc = N->getLocation();
|
||||
@ -3179,9 +3154,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
|
||||
SourceLocation SLoc = S->getLocStart();
|
||||
|
||||
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
|
||||
llvm::raw_os_ostream OutS(Out);
|
||||
S->printPretty(OutS);
|
||||
OutS.flush();
|
||||
S->printPretty(Out);
|
||||
|
||||
if (SLoc.isFileID()) {
|
||||
Out << "\\lline="
|
||||
@ -3235,10 +3208,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
|
||||
SourceLocation SLoc = T->getLocStart();
|
||||
|
||||
Out << "\\|Terminator: ";
|
||||
|
||||
llvm::raw_os_ostream OutS(Out);
|
||||
E.getSrc()->printTerminator(OutS);
|
||||
OutS.flush();
|
||||
E.getSrc()->printTerminator(Out);
|
||||
|
||||
if (SLoc.isFileID()) {
|
||||
Out << "\\lline="
|
||||
@ -3253,14 +3223,11 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
|
||||
if (Label) {
|
||||
if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
|
||||
Out << "\\lcase ";
|
||||
llvm::raw_os_ostream OutS(Out);
|
||||
C->getLHS()->printPretty(OutS);
|
||||
OutS.flush();
|
||||
C->getLHS()->printPretty(Out);
|
||||
|
||||
if (Stmt* RHS = C->getRHS()) {
|
||||
Out << " .. ";
|
||||
RHS->printPretty(OutS);
|
||||
OutS.flush();
|
||||
RHS->printPretty(Out);
|
||||
}
|
||||
|
||||
Out << ":";
|
||||
|
@ -672,7 +672,6 @@ class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
|
||||
return NULL;
|
||||
|
||||
if (!StoreSite) {
|
||||
GRStateManager &StateMgr = BRC.getStateManager();
|
||||
const ExplodedNode<GRState> *Node = N, *Last = NULL;
|
||||
|
||||
for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
|
||||
@ -686,7 +685,7 @@ class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
if (StateMgr.GetSVal(Node->getState(), R) != V)
|
||||
if (Node->getState()->getSVal(R) != V)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,415 +0,0 @@
|
||||
// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that
|
||||
// provides transfer functions for performing simple value tracking with
|
||||
// limited support for symbolics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRSimpleVals.h"
|
||||
#include "BasicObjCFoundationChecks.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer Function creation for External clients.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for Casts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) {
|
||||
|
||||
if (!isa<nonloc::ConcreteInt>(X))
|
||||
return UnknownVal();
|
||||
|
||||
bool isLocType = Loc::IsLocType(T);
|
||||
|
||||
// Only handle casts from integers to integers.
|
||||
if (!isLocType && !T->isIntegerType())
|
||||
return UnknownVal();
|
||||
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
|
||||
llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue();
|
||||
V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
|
||||
V.extOrTrunc(Eng.getContext().getTypeSize(T));
|
||||
|
||||
if (isLocType)
|
||||
return loc::ConcreteInt(BasicVals.getValue(V));
|
||||
else
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
|
||||
// Casts.
|
||||
|
||||
SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
|
||||
|
||||
// Casts from pointers -> pointers, just return the lval.
|
||||
//
|
||||
// Casts from pointers -> references, just return the lval. These
|
||||
// can be introduced by the frontend for corner cases, e.g
|
||||
// casting from va_list* to __builtin_va_list&.
|
||||
//
|
||||
assert (!X.isUnknownOrUndef());
|
||||
|
||||
if (Loc::IsLocType(T) || T->isReferenceType())
|
||||
return X;
|
||||
|
||||
// FIXME: Handle transparent unions where a value can be "transparently"
|
||||
// lifted into a union type.
|
||||
if (T->isUnionType())
|
||||
return UnknownVal();
|
||||
|
||||
assert (T->isIntegerType());
|
||||
BasicValueFactory& BasicVals = Eng.getBasicVals();
|
||||
unsigned BitWidth = Eng.getContext().getTypeSize(T);
|
||||
|
||||
if (!isa<loc::ConcreteInt>(X))
|
||||
return Eng.getValueManager().makeLocAsInteger(X, BitWidth);
|
||||
|
||||
llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
|
||||
V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
|
||||
V.extOrTrunc(BitWidth);
|
||||
return nonloc::ConcreteInt(BasicVals.getValue(V));
|
||||
}
|
||||
|
||||
// Unary operators.
|
||||
|
||||
SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonloc::ConcreteIntKind:
|
||||
return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
|
||||
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) {
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonloc::ConcreteIntKind:
|
||||
return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
|
||||
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
// Binary operators.
|
||||
|
||||
static unsigned char LNotOpMap[] = {
|
||||
(unsigned char) BinaryOperator::GE, /* LT => GE */
|
||||
(unsigned char) BinaryOperator::LE, /* GT => LE */
|
||||
(unsigned char) BinaryOperator::GT, /* LE => GT */
|
||||
(unsigned char) BinaryOperator::LT, /* GE => LT */
|
||||
(unsigned char) BinaryOperator::NE, /* EQ => NE */
|
||||
(unsigned char) BinaryOperator::EQ /* NE => EQ */
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
switch (subkind) {
|
||||
default:
|
||||
return UnknownVal();
|
||||
|
||||
case nonloc::LocAsIntegerKind: {
|
||||
Loc LL = cast<nonloc::LocAsInteger>(L).getLoc();
|
||||
|
||||
switch (R.getSubKind()) {
|
||||
case nonloc::LocAsIntegerKind:
|
||||
return EvalBinOp(Eng, Op, LL,
|
||||
cast<nonloc::LocAsInteger>(R).getLoc());
|
||||
|
||||
case nonloc::ConcreteIntKind: {
|
||||
// Transform the integer into a location and compare.
|
||||
ASTContext& Ctx = Eng.getContext();
|
||||
llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
|
||||
V.setIsUnsigned(true);
|
||||
V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
|
||||
return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V));
|
||||
}
|
||||
|
||||
default:
|
||||
switch (Op) {
|
||||
case BinaryOperator::EQ:
|
||||
return ValMgr.makeTruthVal(false);
|
||||
case BinaryOperator::NE:
|
||||
return ValMgr.makeTruthVal(true);
|
||||
default:
|
||||
// This case also handles pointer arithmetic.
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case nonloc::SymExprValKind: {
|
||||
// Logical not?
|
||||
if (!(Op == BinaryOperator::EQ && R.isZeroConstant()))
|
||||
return UnknownVal();
|
||||
|
||||
const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression();
|
||||
|
||||
// Only handle ($sym op constant) for now.
|
||||
if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) {
|
||||
BinaryOperator::Opcode Opc = E->getOpcode();
|
||||
|
||||
if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE)
|
||||
return UnknownVal();
|
||||
|
||||
// For comparison operators, translate the constraint by
|
||||
// changing the opcode.
|
||||
int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT;
|
||||
|
||||
assert (idx >= 0 &&
|
||||
(unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char));
|
||||
|
||||
Opc = (BinaryOperator::Opcode) LNotOpMap[idx];
|
||||
assert(E->getType(Eng.getContext()) == T);
|
||||
E = Eng.getSymbolManager().getSymIntExpr(E->getLHS(), Opc,
|
||||
E->getRHS(), T);
|
||||
return nonloc::SymExprVal(E);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
case nonloc::ConcreteIntKind:
|
||||
|
||||
if (isa<nonloc::ConcreteInt>(R)) {
|
||||
const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L);
|
||||
const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R);
|
||||
return L_CI.EvalBinOp(BasicVals, Op, R_CI);
|
||||
}
|
||||
else {
|
||||
subkind = R.getSubKind();
|
||||
NonLoc tmp = R;
|
||||
R = L;
|
||||
L = tmp;
|
||||
|
||||
// Swap the operators.
|
||||
switch (Op) {
|
||||
case BinaryOperator::LT: Op = BinaryOperator::GT; break;
|
||||
case BinaryOperator::GT: Op = BinaryOperator::LT; break;
|
||||
case BinaryOperator::LE: Op = BinaryOperator::GE; break;
|
||||
case BinaryOperator::GE: Op = BinaryOperator::LE; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case nonloc::SymbolValKind:
|
||||
if (isa<nonloc::ConcreteInt>(R)) {
|
||||
ValueManager &ValMgr = Eng.getValueManager();
|
||||
return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(L).getSymbol(), Op,
|
||||
cast<nonloc::ConcreteInt>(R).getValue(), T);
|
||||
}
|
||||
else
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Binary Operators (except assignments and comma).
|
||||
|
||||
SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
|
||||
Loc L, Loc R) {
|
||||
|
||||
switch (Op) {
|
||||
default:
|
||||
return UnknownVal();
|
||||
case BinaryOperator::EQ:
|
||||
case BinaryOperator::NE:
|
||||
return EvalEquality(Eng, L, R, Op == BinaryOperator::EQ);
|
||||
}
|
||||
}
|
||||
|
||||
SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state,
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R) {
|
||||
|
||||
// Special case: 'R' is an integer that has the same width as a pointer and
|
||||
// we are using the integer location in a comparison. Normally this cannot be
|
||||
// triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
|
||||
// can generate comparisons that trigger this code.
|
||||
// FIXME: Are all locations guaranteed to have pointer width?
|
||||
if (BinaryOperator::isEqualityOp(Op)) {
|
||||
if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) {
|
||||
const llvm::APSInt *X = &RInt->getValue();
|
||||
ASTContext &C = Eng.getContext();
|
||||
if (C.getTypeSize(C.VoidPtrTy) == X->getBitWidth()) {
|
||||
// Convert the signedness of the integer (if necessary).
|
||||
if (X->isSigned())
|
||||
X = &Eng.getBasicVals().getValue(*X, true);
|
||||
|
||||
return EvalBinOp(Eng, Op, L, loc::ConcreteInt(*X));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate pointer arithmetic to store manager.
|
||||
return Eng.getStoreManager().EvalBinOp(state, Op, L, R);
|
||||
}
|
||||
|
||||
// Equality operators for Locs.
|
||||
// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
|
||||
// implemented.
|
||||
|
||||
SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
|
||||
|
||||
ValueManager& ValMgr = Eng.getValueManager();
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
default:
|
||||
assert(false && "EQ/NE not implemented for this Loc.");
|
||||
return UnknownVal();
|
||||
|
||||
case loc::ConcreteIntKind:
|
||||
|
||||
if (isa<loc::ConcreteInt>(R)) {
|
||||
bool b = cast<loc::ConcreteInt>(L).getValue() ==
|
||||
cast<loc::ConcreteInt>(R).getValue();
|
||||
|
||||
// Are we computing '!='? Flip the result.
|
||||
if (!isEqual)
|
||||
b = !b;
|
||||
|
||||
return ValMgr.makeTruthVal(b);
|
||||
}
|
||||
else if (SymbolRef Sym = R.getAsSymbol()) {
|
||||
const SymIntExpr * SE =
|
||||
Eng.getSymbolManager().getSymIntExpr(Sym,
|
||||
isEqual ? BinaryOperator::EQ
|
||||
: BinaryOperator::NE,
|
||||
cast<loc::ConcreteInt>(L).getValue(),
|
||||
Eng.getContext().IntTy);
|
||||
return nonloc::SymExprVal(SE);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case loc::MemRegionKind: {
|
||||
if (SymbolRef LSym = L.getAsLocSymbol()) {
|
||||
if (isa<loc::ConcreteInt>(R)) {
|
||||
const SymIntExpr *SE =
|
||||
Eng.getSymbolManager().getSymIntExpr(LSym,
|
||||
isEqual ? BinaryOperator::EQ
|
||||
: BinaryOperator::NE,
|
||||
cast<loc::ConcreteInt>(R).getValue(),
|
||||
Eng.getContext().IntTy);
|
||||
|
||||
return nonloc::SymExprVal(SE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall-through.
|
||||
|
||||
case loc::GotoLabelKind:
|
||||
return ValMgr.makeTruthVal(isEqual ? L == R : L != R);
|
||||
}
|
||||
|
||||
return ValMgr.makeTruthVal(isEqual ? false : true);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for function calls.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Eng,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
CallExpr* CE, SVal L,
|
||||
ExplodedNode<GRState>* Pred) {
|
||||
|
||||
GRStateManager& StateMgr = Eng.getStateManager();
|
||||
const GRState* St = Builder.GetState(Pred);
|
||||
|
||||
// Invalidate all arguments passed in by reference (Locs).
|
||||
|
||||
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
|
||||
I != E; ++I) {
|
||||
|
||||
SVal V = St->getSVal(*I);
|
||||
|
||||
if (isa<loc::MemRegionVal>(V)) {
|
||||
const MemRegion *R = cast<loc::MemRegionVal>(V).getRegion();
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
// Make up a symbol for the return value of this function.
|
||||
// FIXME: We eventually should handle structs and other compound types
|
||||
// that are returned by value.
|
||||
QualType T = CE->getType();
|
||||
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
|
||||
unsigned Count = Builder.getCurrentBlockCount();
|
||||
SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count);
|
||||
St = St->bindExpr(CE, X, Eng.getCFG().isBlkExpr(CE), false);
|
||||
}
|
||||
|
||||
Builder.MakeNode(Dst, CE, Pred, St);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for Objective-C message expressions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Eng,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<GRState>* Pred) {
|
||||
|
||||
|
||||
// The basic transfer function logic for message expressions does nothing.
|
||||
// We just invalidate all arguments passed in by references.
|
||||
const GRState *St = Builder.GetState(Pred);
|
||||
|
||||
for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
|
||||
I != E; ++I) {
|
||||
|
||||
SVal V = St->getSVal(*I);
|
||||
|
||||
if (isa<Loc>(V))
|
||||
St = St->bindLoc(cast<Loc>(V), UnknownVal());
|
||||
}
|
||||
|
||||
Builder.MakeNode(Dst, ME, Pred, St);
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// GRSimpleVals.h - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that
|
||||
// provides transfer functions for performing simple value tracking with
|
||||
// limited support for symbolics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
|
||||
#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnostic;
|
||||
class ASTContext;
|
||||
|
||||
class GRSimpleVals : public GRTransferFuncs {
|
||||
protected:
|
||||
|
||||
virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R, QualType T);
|
||||
|
||||
public:
|
||||
GRSimpleVals() {}
|
||||
virtual ~GRSimpleVals() {}
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT);
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT);
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X);
|
||||
|
||||
virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X);
|
||||
|
||||
// Binary Operators.
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
Loc L, Loc R);
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R);
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
CallExpr* CE, SVal L,
|
||||
ExplodedNode<GRState>* Pred);
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<GRState>* Pred);
|
||||
|
||||
|
||||
|
||||
static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
|
||||
ExplodedNode<GRState>* N);
|
||||
|
||||
protected:
|
||||
|
||||
// Equality (==, !=) operators for Locs.
|
||||
SVal EvalEquality(GRExprEngine& Engine, Loc L, Loc R, bool isEqual);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//= GRState*cpp - Path-Sens. "State" for tracking valuues -----*- C++ -*--=//
|
||||
//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines SymbolRef, ExprBindKey, and GRState*
|
||||
// This file implements GRState and GRStateManager.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
using namespace clang;
|
||||
|
||||
// Give the vtable for ConstraintManager somewhere to live.
|
||||
// FIXME: Move this elsewhere.
|
||||
ConstraintManager::~ConstraintManager() {}
|
||||
|
||||
GRStateManager::~GRStateManager() {
|
||||
@ -56,16 +57,63 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
|
||||
SymReaper);
|
||||
}
|
||||
|
||||
const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
|
||||
Store OldStore = St->getStore();
|
||||
Store NewStore = StoreMgr->Remove(OldStore, LV);
|
||||
const GRState *GRState::unbindLoc(Loc LV) const {
|
||||
Store OldStore = getStore();
|
||||
Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV);
|
||||
|
||||
if (NewStore == OldStore)
|
||||
return St;
|
||||
return this;
|
||||
|
||||
GRState NewSt = *St;
|
||||
GRState NewSt = *this;
|
||||
NewSt.St = NewStore;
|
||||
return getPersistentState(NewSt);
|
||||
return Mgr->getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
|
||||
// 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())
|
||||
return UnknownVal();
|
||||
|
||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
|
||||
QualType T = TR->getValueType(Mgr->getContext());
|
||||
if (Loc::IsLocType(T) || T->isIntegerType())
|
||||
return getSVal(R);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
|
||||
bool Invalidate) const {
|
||||
|
||||
Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate);
|
||||
|
||||
if (NewEnv == Env)
|
||||
return this;
|
||||
|
||||
GRState NewSt = *this;
|
||||
NewSt.Env = NewEnv;
|
||||
return Mgr->getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState *GRState::bindExpr(const Stmt* Ex, SVal V,
|
||||
bool Invalidate) const {
|
||||
|
||||
bool isBlkExpr = false;
|
||||
|
||||
if (Ex == Mgr->CurrentStmt) {
|
||||
// FIXME: Should this just be an assertion? When would we want to set
|
||||
// the value of a block-level expression if it wasn't CurrentStmt?
|
||||
isBlkExpr = Mgr->cfg.isBlkExpr(Ex);
|
||||
|
||||
if (!isBlkExpr)
|
||||
return this;
|
||||
}
|
||||
|
||||
return bindExpr(Ex, V, isBlkExpr, Invalidate);
|
||||
}
|
||||
|
||||
const GRState* GRStateManager::getInitialState() {
|
||||
@ -101,7 +149,8 @@ const GRState* GRState::makeWithStore(Store store) const {
|
||||
// State pretty-printing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
|
||||
void GRState::print(llvm::raw_ostream& Out, const char* nl,
|
||||
const char* sep) const {
|
||||
// Print the store.
|
||||
Mgr->getStoreManager().print(getStore(), Out, nl, sep);
|
||||
|
||||
@ -117,9 +166,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
|
||||
else { Out << nl; }
|
||||
|
||||
Out << " (" << (void*) I.getKey() << ") ";
|
||||
llvm::raw_os_ostream OutS(Out);
|
||||
I.getKey()->printPretty(OutS);
|
||||
OutS.flush();
|
||||
I.getKey()->printPretty(Out);
|
||||
Out << " : ";
|
||||
I.getData().print(Out);
|
||||
}
|
||||
@ -136,9 +183,7 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
|
||||
else { Out << nl; }
|
||||
|
||||
Out << " (" << (void*) I.getKey() << ") ";
|
||||
llvm::raw_os_ostream OutS(Out);
|
||||
I.getKey()->printPretty(OutS);
|
||||
OutS.flush();
|
||||
I.getKey()->printPretty(Out);
|
||||
Out << " : ";
|
||||
I.getData().print(Out);
|
||||
}
|
||||
@ -152,12 +197,12 @@ void GRState::print(std::ostream& Out, const char* nl, const char* sep) const {
|
||||
}
|
||||
}
|
||||
|
||||
void GRState::printDOT(std::ostream& Out) const {
|
||||
void GRState::printDOT(llvm::raw_ostream& Out) const {
|
||||
print(Out, "\\l", "\\|");
|
||||
}
|
||||
|
||||
void GRState::printStdErr() const {
|
||||
print(*llvm::cerr);
|
||||
print(llvm::errs());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1,27 +0,0 @@
|
||||
//== GRTransferFuncs.cpp - Path-Sens. Transfer Functions Interface -*- 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 GRTransferFuncs, which provides a base-class that
|
||||
// defines an interface for transfer functions used by GRExprEngine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates,
|
||||
GRExprEngine& Eng,
|
||||
const GRState *St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R, QualType T) {
|
||||
|
||||
OStates.Add(St->bindExpr(Ex, DetermEvalBinOpNN(Eng, Op, L, R, T)));
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::isa;
|
||||
|
@ -200,7 +200,7 @@ class VISIBILITY_HIDDEN RangeSet {
|
||||
return newRanges;
|
||||
}
|
||||
|
||||
void Print(std::ostream &os) const {
|
||||
void print(llvm::raw_ostream &os) const {
|
||||
bool isFirst = true;
|
||||
os << "{ ";
|
||||
for (iterator i = begin(), e = end(); i != e; ++i) {
|
||||
@ -265,7 +265,7 @@ class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
|
||||
|
||||
void print(const GRState* St, std::ostream& Out,
|
||||
void print(const GRState* St, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep);
|
||||
|
||||
private:
|
||||
@ -341,7 +341,7 @@ AssumeX(GE)
|
||||
// Pretty-printing.
|
||||
//===------------------------------------------------------------------------===/
|
||||
|
||||
void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
|
||||
void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
|
||||
const char* nl, const char *sep) {
|
||||
|
||||
ConstraintRangeTy Ranges = St->get<ConstraintRange>();
|
||||
@ -353,6 +353,6 @@ void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
|
||||
|
||||
for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
|
||||
Out << nl << ' ' << I.getKey() << " : ";
|
||||
I.getData().Print(Out);
|
||||
I.getData().print(Out);
|
||||
}
|
||||
}
|
||||
|
@ -102,25 +102,6 @@ namespace clang {
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Region "killsets".
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// RegionStore lazily adds value bindings to regions when the analyzer handles
|
||||
// assignment statements. Killsets track which default values have been
|
||||
// killed, thus distinguishing between "unknown" values and default
|
||||
// values. Regions are added to killset only when they are assigned "unknown"
|
||||
// directly, otherwise we should have their value in the region bindings.
|
||||
//
|
||||
namespace { class VISIBILITY_HIDDEN RegionKills {}; }
|
||||
static int RegionKillsIndex = 0;
|
||||
namespace clang {
|
||||
template<> struct GRStateTrait<RegionKills>
|
||||
: public GRStatePartialTrait< llvm::ImmutableSet<const MemRegion*> > {
|
||||
static void* GDMIndex() { return &RegionKillsIndex; }
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Regions with default values.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -238,10 +219,8 @@ class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
|
||||
CastResult CastRegion(const GRState *state, const MemRegion* R,
|
||||
QualType CastToTy);
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,NonLoc R);
|
||||
|
||||
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
|
||||
NonLoc R, QualType resultTy);
|
||||
|
||||
Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
|
||||
|
||||
@ -260,8 +239,6 @@ class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
|
||||
|
||||
return SelfRegion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===-------------------------------------------------------------------===//
|
||||
// Binding values to regions.
|
||||
@ -306,7 +283,11 @@ class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
|
||||
/// else
|
||||
/// return symbolic
|
||||
SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
|
||||
|
||||
|
||||
SVal RetrieveElement(const GRState* state, const ElementRegion* R);
|
||||
|
||||
SVal RetrieveField(const GRState* state, const FieldRegion* R);
|
||||
|
||||
/// Retrieve the values in a struct and return a CompoundVal, used when doing
|
||||
/// struct copy:
|
||||
/// struct s x, y;
|
||||
@ -352,7 +333,8 @@ class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
|
||||
return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
|
||||
}
|
||||
|
||||
void print(Store store, std::ostream& Out, const char* nl, const char *sep);
|
||||
void print(Store store, llvm::raw_ostream& Out, const char* nl,
|
||||
const char *sep);
|
||||
|
||||
void iterBindings(Store store, BindingsHandler& f) {
|
||||
// FIXME: Implement.
|
||||
@ -740,7 +722,8 @@ RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R) {
|
||||
BinaryOperator::Opcode Op, Loc L, NonLoc R,
|
||||
QualType resultTy) {
|
||||
// Assume the base location is MemRegionVal.
|
||||
if (!isa<loc::MemRegionVal>(L))
|
||||
return UnknownVal();
|
||||
@ -798,7 +781,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||
//
|
||||
nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(),
|
||||
Offset->getValue()));
|
||||
SVal NewIdx = Base->EvalBinOp(getBasicVals(), Op, OffConverted);
|
||||
SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted);
|
||||
const MemRegion* NewER =
|
||||
MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
|
||||
getContext());
|
||||
@ -839,6 +822,12 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
const TypedRegion *R = cast<TypedRegion>(MR);
|
||||
assert(R && "bad region");
|
||||
|
||||
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
|
||||
return RetrieveField(state, FR);
|
||||
|
||||
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
|
||||
return RetrieveElement(state, ER);
|
||||
|
||||
// FIXME: We should eventually handle funny addressing. e.g.:
|
||||
//
|
||||
// int x = ...;
|
||||
@ -867,42 +856,6 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
if (V)
|
||||
return *V;
|
||||
|
||||
// Check if the region is in killset.
|
||||
if (state->contains<RegionKills>(R))
|
||||
return UnknownVal();
|
||||
|
||||
// Check if the region is an element region of a string literal.
|
||||
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
|
||||
if (const StringRegion *StrR=dyn_cast<StringRegion>(ER->getSuperRegion())) {
|
||||
const StringLiteral *Str = StrR->getStringLiteral();
|
||||
SVal Idx = ER->getIndex();
|
||||
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
|
||||
int64_t i = CI->getValue().getSExtValue();
|
||||
char c;
|
||||
if (i == Str->getByteLength())
|
||||
c = '\0';
|
||||
else
|
||||
c = Str->getStrData()[i];
|
||||
const llvm::APSInt &V = getBasicVals().getValue(c, getContext().CharTy);
|
||||
return nonloc::ConcreteInt(V);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the region is an element or field, it may have a default value.
|
||||
if (isa<ElementRegion>(R) || isa<FieldRegion>(R)) {
|
||||
const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
|
||||
GRStateTrait<RegionDefaultValue>::lookup_type D =
|
||||
state->get<RegionDefaultValue>(SuperR);
|
||||
if (D) {
|
||||
// If the default value is symbolic, we need to create a new symbol.
|
||||
if (D->hasConjuredSymbol())
|
||||
return ValMgr.getRegionValueSymbolVal(R);
|
||||
else
|
||||
return *D;
|
||||
}
|
||||
}
|
||||
|
||||
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
|
||||
const MemRegion *SR = IVR->getSuperRegion();
|
||||
|
||||
@ -961,6 +914,97 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal RegionStoreManager::RetrieveElement(const GRState* state,
|
||||
const ElementRegion* R) {
|
||||
// Check if the region has a binding.
|
||||
RegionBindingsTy B = GetRegionBindings(state->getStore());
|
||||
const SVal* V = B.lookup(R);
|
||||
if (V)
|
||||
return *V;
|
||||
|
||||
// Check if the region is an element region of a string literal.
|
||||
if (const StringRegion *StrR=dyn_cast<StringRegion>(R->getSuperRegion())) {
|
||||
const StringLiteral *Str = StrR->getStringLiteral();
|
||||
SVal Idx = R->getIndex();
|
||||
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
|
||||
int64_t i = CI->getValue().getSExtValue();
|
||||
char c;
|
||||
if (i == Str->getByteLength())
|
||||
c = '\0';
|
||||
else
|
||||
c = Str->getStrData()[i];
|
||||
return ValMgr.makeIntVal(c, getContext().CharTy);
|
||||
}
|
||||
}
|
||||
|
||||
const MemRegion* SuperR = R->getSuperRegion();
|
||||
const SVal* D = state->get<RegionDefaultValue>(SuperR);
|
||||
|
||||
if (D) {
|
||||
if (D->hasConjuredSymbol())
|
||||
return ValMgr.getRegionValueSymbolVal(R);
|
||||
else
|
||||
return *D;
|
||||
}
|
||||
|
||||
if (R->hasHeapOrStackStorage())
|
||||
return UndefinedVal();
|
||||
|
||||
QualType Ty = R->getValueType(getContext());
|
||||
|
||||
// If the region is already cast to another type, use that type to create the
|
||||
// symbol value.
|
||||
if (const QualType *p = state->get<RegionCasts>(R))
|
||||
Ty = (*p)->getAsPointerType()->getPointeeType();
|
||||
|
||||
if (Loc::IsLocType(Ty) || Ty->isIntegerType())
|
||||
return ValMgr.getRegionValueSymbolVal(R, Ty);
|
||||
else
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal RegionStoreManager::RetrieveField(const GRState* state,
|
||||
const FieldRegion* R) {
|
||||
QualType Ty = R->getValueType(getContext());
|
||||
|
||||
// Check if the region has a binding.
|
||||
RegionBindingsTy B = GetRegionBindings(state->getStore());
|
||||
const SVal* V = B.lookup(R);
|
||||
if (V)
|
||||
return *V;
|
||||
|
||||
const MemRegion* SuperR = R->getSuperRegion();
|
||||
const SVal* D = state->get<RegionDefaultValue>(SuperR);
|
||||
if (D) {
|
||||
if (D->hasConjuredSymbol())
|
||||
return ValMgr.getRegionValueSymbolVal(R);
|
||||
|
||||
if (D->isZeroConstant())
|
||||
return ValMgr.makeZeroVal(Ty);
|
||||
|
||||
if (D->isUnknown())
|
||||
return *D;
|
||||
|
||||
assert(0 && "Unknown default value");
|
||||
}
|
||||
|
||||
if (R->hasHeapOrStackStorage())
|
||||
return UndefinedVal();
|
||||
|
||||
// If the region is already cast to another type, use that type to create the
|
||||
// symbol value.
|
||||
if (const QualType *p = state->get<RegionCasts>(R)) {
|
||||
QualType tmp = *p;
|
||||
Ty = tmp->getAsPointerType()->getPointeeType();
|
||||
}
|
||||
|
||||
// All other integer values are symbolic.
|
||||
if (Loc::IsLocType(Ty) || Ty->isIntegerType())
|
||||
return ValMgr.getRegionValueSymbolVal(R, Ty);
|
||||
else
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal RegionStoreManager::RetrieveStruct(const GRState *state,
|
||||
const TypedRegion* R){
|
||||
QualType T = R->getValueType(getContext());
|
||||
@ -1040,12 +1084,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
|
||||
|
||||
RegionBindingsTy B = GetRegionBindings(state->getStore());
|
||||
|
||||
if (V.isUnknown()) {
|
||||
B = RBFactory.Remove(B, R); // Remove the binding.
|
||||
state = state->add<RegionKills>(R); // Add the region to the killset.
|
||||
}
|
||||
else
|
||||
B = RBFactory.Add(B, R, V);
|
||||
B = RBFactory.Add(B, R, V);
|
||||
|
||||
return state->makeWithStore(B.getRoot());
|
||||
}
|
||||
@ -1127,15 +1166,12 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
|
||||
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());
|
||||
// If the init list is shorter than the array length, set the array default
|
||||
// value.
|
||||
if (i < Size) {
|
||||
if (ElementTy->isIntegerType()) {
|
||||
SVal V = ValMgr.makeZeroVal(ElementTy);
|
||||
state = Bind(state, ValMgr.makeLoc(ER), V);
|
||||
++i;
|
||||
state = setDefaultValue(state, R, V);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1186,15 +1222,8 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (FI != FE)
|
||||
state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false));
|
||||
|
||||
return state;
|
||||
}
|
||||
@ -1202,20 +1231,17 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
|
||||
const GRState *RegionStoreManager::KillStruct(const GRState *state,
|
||||
const TypedRegion* R){
|
||||
|
||||
// (1) Kill the struct region because it is assigned "unknown".
|
||||
// (2) Set the default value of the struct region to "unknown".
|
||||
state = state->add<RegionKills>(R)->set<RegionDefaultValue>(R, UnknownVal());
|
||||
Store store = state->getStore();
|
||||
RegionBindingsTy B = GetRegionBindings(store);
|
||||
// Set the default value of the struct region to "unknown".
|
||||
state = state->set<RegionDefaultValue>(R, UnknownVal());
|
||||
|
||||
// Remove all bindings for the subregions of the struct.
|
||||
Store store = state->getStore();
|
||||
RegionBindingsTy B = GetRegionBindings(store);
|
||||
for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
|
||||
const MemRegion* R = I.getKey();
|
||||
if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
|
||||
if (subRegion->isSubRegionOf(R))
|
||||
store = Remove(store, ValMgr.makeLoc(subRegion));
|
||||
// FIXME: Maybe we should also remove the bindings for the "views" of the
|
||||
// subregions.
|
||||
}
|
||||
|
||||
return state->makeWithStore(store);
|
||||
@ -1427,9 +1453,8 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
|
||||
// Utility methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void RegionStoreManager::print(Store store, std::ostream& Out,
|
||||
void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
|
||||
const char* nl, const char *sep) {
|
||||
llvm::raw_os_ostream OS(Out);
|
||||
RegionBindingsTy B = GetRegionBindings(store);
|
||||
OS << "Store:" << nl;
|
||||
|
||||
|
@ -188,12 +188,11 @@ bool SVal::isZeroConstant() const {
|
||||
// Transfer function dispatch for Non-Locs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
|
||||
BinaryOperator::Opcode Op,
|
||||
const nonloc::ConcreteInt& R) const {
|
||||
|
||||
SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const nonloc::ConcreteInt& R) const {
|
||||
const llvm::APSInt* X =
|
||||
BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
|
||||
ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue());
|
||||
|
||||
if (X)
|
||||
return nonloc::ConcreteInt(*X);
|
||||
@ -201,20 +200,13 @@ SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
|
||||
return UndefinedVal();
|
||||
}
|
||||
|
||||
// Bitwise-Complement.
|
||||
|
||||
nonloc::ConcreteInt
|
||||
nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const {
|
||||
return BasicVals.getValue(~getValue());
|
||||
nonloc::ConcreteInt::evalComplement(ValueManager &ValMgr) const {
|
||||
return ValMgr.makeIntVal(~getValue());
|
||||
}
|
||||
|
||||
// Unary Minus.
|
||||
|
||||
nonloc::ConcreteInt
|
||||
nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const {
|
||||
assert (U->getType() == U->getSubExpr()->getType());
|
||||
assert (U->getType()->isIntegerType());
|
||||
return BasicVals.getValue(-getValue());
|
||||
nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const {
|
||||
return ValMgr.makeIntVal(-getValue());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -242,11 +234,6 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
|
||||
|
||||
void SVal::printStdErr() const { print(llvm::errs()); }
|
||||
|
||||
void SVal::print(std::ostream& Out) const {
|
||||
llvm::raw_os_ostream out(Out);
|
||||
print(out);
|
||||
}
|
||||
|
||||
void SVal::print(llvm::raw_ostream& Out) const {
|
||||
|
||||
switch (getBaseKind()) {
|
||||
|
346
lib/Analysis/SimpleSValuator.cpp
Normal file
346
lib/Analysis/SimpleSValuator.cpp
Normal file
@ -0,0 +1,346 @@
|
||||
// SimpleSValuator.cpp - A basic SValuator ------------------------*- 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 SimpleSValuator, a basic implementation of SValuator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SValuator.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
|
||||
public:
|
||||
SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
|
||||
virtual ~SimpleSValuator() {}
|
||||
|
||||
virtual SVal EvalCast(NonLoc val, QualType castTy);
|
||||
virtual SVal EvalCast(Loc val, QualType castTy);
|
||||
virtual SVal EvalMinus(NonLoc val);
|
||||
virtual SVal EvalComplement(NonLoc val);
|
||||
virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
|
||||
QualType resultTy);
|
||||
virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
|
||||
QualType resultTy);
|
||||
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
|
||||
Loc lhs, NonLoc rhs, QualType resultTy);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
|
||||
return new SimpleSValuator(valMgr);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for Casts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) {
|
||||
if (!isa<nonloc::ConcreteInt>(val))
|
||||
return UnknownVal();
|
||||
|
||||
bool isLocType = Loc::IsLocType(castTy);
|
||||
|
||||
// Only handle casts from integers to integers.
|
||||
if (!isLocType && !castTy->isIntegerType())
|
||||
return UnknownVal();
|
||||
|
||||
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
|
||||
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
|
||||
i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy));
|
||||
|
||||
if (isLocType)
|
||||
return ValMgr.makeIntLocVal(i);
|
||||
else
|
||||
return ValMgr.makeIntVal(i);
|
||||
}
|
||||
|
||||
SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) {
|
||||
|
||||
// Casts from pointers -> pointers, just return the lval.
|
||||
//
|
||||
// Casts from pointers -> references, just return the lval. These
|
||||
// can be introduced by the frontend for corner cases, e.g
|
||||
// casting from va_list* to __builtin_va_list&.
|
||||
//
|
||||
assert(!val.isUnknownOrUndef());
|
||||
|
||||
if (Loc::IsLocType(castTy) || castTy->isReferenceType())
|
||||
return val;
|
||||
|
||||
// FIXME: Handle transparent unions where a value can be "transparently"
|
||||
// lifted into a union type.
|
||||
if (castTy->isUnionType())
|
||||
return UnknownVal();
|
||||
|
||||
assert(castTy->isIntegerType());
|
||||
unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
|
||||
|
||||
if (!isa<loc::ConcreteInt>(val))
|
||||
return ValMgr.makeLocAsInteger(val, BitWidth);
|
||||
|
||||
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
|
||||
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
|
||||
i.extOrTrunc(BitWidth);
|
||||
return ValMgr.makeIntVal(i);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for unary operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SVal SimpleSValuator::EvalMinus(NonLoc val) {
|
||||
switch (val.getSubKind()) {
|
||||
case nonloc::ConcreteIntKind:
|
||||
return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr);
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
SVal SimpleSValuator::EvalComplement(NonLoc X) {
|
||||
switch (X.getSubKind()) {
|
||||
case nonloc::ConcreteIntKind:
|
||||
return cast<nonloc::ConcreteInt>(X).evalComplement(ValMgr);
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for binary operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
|
||||
switch (op) {
|
||||
default:
|
||||
assert(false && "Invalid opcode.");
|
||||
case BinaryOperator::LT: return BinaryOperator::GE;
|
||||
case BinaryOperator::GT: return BinaryOperator::LE;
|
||||
case BinaryOperator::LE: return BinaryOperator::GT;
|
||||
case BinaryOperator::GE: return BinaryOperator::LT;
|
||||
case BinaryOperator::EQ: return BinaryOperator::NE;
|
||||
case BinaryOperator::NE: return BinaryOperator::EQ;
|
||||
}
|
||||
}
|
||||
|
||||
// Equality operators for Locs.
|
||||
// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
|
||||
// implemented.
|
||||
|
||||
static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
|
||||
QualType resultTy) {
|
||||
|
||||
switch (lhs.getSubKind()) {
|
||||
default:
|
||||
assert(false && "EQ/NE not implemented for this Loc.");
|
||||
return UnknownVal();
|
||||
|
||||
case loc::ConcreteIntKind: {
|
||||
if (SymbolRef rSym = rhs.getAsSymbol())
|
||||
return ValMgr.makeNonLoc(rSym,
|
||||
isEqual ? BinaryOperator::EQ
|
||||
: BinaryOperator::NE,
|
||||
cast<loc::ConcreteInt>(lhs).getValue(),
|
||||
resultTy);
|
||||
break;
|
||||
}
|
||||
case loc::MemRegionKind: {
|
||||
if (SymbolRef lSym = lhs.getAsLocSymbol()) {
|
||||
if (isa<loc::ConcreteInt>(rhs)) {
|
||||
return ValMgr.makeNonLoc(lSym,
|
||||
isEqual ? BinaryOperator::EQ
|
||||
: BinaryOperator::NE,
|
||||
cast<loc::ConcreteInt>(rhs).getValue(),
|
||||
resultTy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case loc::GotoLabelKind:
|
||||
break;
|
||||
}
|
||||
|
||||
return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
|
||||
}
|
||||
|
||||
SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
|
||||
NonLoc lhs, NonLoc rhs,
|
||||
QualType resultTy) {
|
||||
while (1) {
|
||||
switch (lhs.getSubKind()) {
|
||||
default:
|
||||
return UnknownVal();
|
||||
case nonloc::LocAsIntegerKind: {
|
||||
Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
|
||||
switch (rhs.getSubKind()) {
|
||||
case nonloc::LocAsIntegerKind:
|
||||
return EvalBinOpLL(op, lhsL, cast<nonloc::LocAsInteger>(rhs).getLoc(),
|
||||
resultTy);
|
||||
case nonloc::ConcreteIntKind: {
|
||||
// Transform the integer into a location and compare.
|
||||
ASTContext& Ctx = ValMgr.getContext();
|
||||
llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
|
||||
i.setIsUnsigned(true);
|
||||
i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
|
||||
return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy);
|
||||
}
|
||||
default:
|
||||
switch (op) {
|
||||
case BinaryOperator::EQ:
|
||||
return ValMgr.makeTruthVal(false, resultTy);
|
||||
case BinaryOperator::NE:
|
||||
return ValMgr.makeTruthVal(true, resultTy);
|
||||
default:
|
||||
// This case also handles pointer arithmetic.
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
case nonloc::SymExprValKind: {
|
||||
// Logical not?
|
||||
if (!(op == BinaryOperator::EQ && rhs.isZeroConstant()))
|
||||
return UnknownVal();
|
||||
|
||||
const SymExpr *symExpr =
|
||||
cast<nonloc::SymExprVal>(lhs).getSymbolicExpression();
|
||||
|
||||
// Only handle ($sym op constant) for now.
|
||||
if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) {
|
||||
BinaryOperator::Opcode opc = symIntExpr->getOpcode();
|
||||
switch (opc) {
|
||||
case BinaryOperator::LAnd:
|
||||
case BinaryOperator::LOr:
|
||||
assert(false && "Logical operators handled by branching logic.");
|
||||
return UnknownVal();
|
||||
case BinaryOperator::Assign:
|
||||
case BinaryOperator::MulAssign:
|
||||
case BinaryOperator::DivAssign:
|
||||
case BinaryOperator::RemAssign:
|
||||
case BinaryOperator::AddAssign:
|
||||
case BinaryOperator::SubAssign:
|
||||
case BinaryOperator::ShlAssign:
|
||||
case BinaryOperator::ShrAssign:
|
||||
case BinaryOperator::AndAssign:
|
||||
case BinaryOperator::XorAssign:
|
||||
case BinaryOperator::OrAssign:
|
||||
case BinaryOperator::Comma:
|
||||
assert(false && "'=' and ',' operators handled by GRExprEngine.");
|
||||
return UnknownVal();
|
||||
case BinaryOperator::PtrMemD:
|
||||
case BinaryOperator::PtrMemI:
|
||||
assert(false && "Pointer arithmetic not handled here.");
|
||||
return UnknownVal();
|
||||
case BinaryOperator::Mul:
|
||||
case BinaryOperator::Div:
|
||||
case BinaryOperator::Rem:
|
||||
case BinaryOperator::Add:
|
||||
case BinaryOperator::Sub:
|
||||
case BinaryOperator::Shl:
|
||||
case BinaryOperator::Shr:
|
||||
case BinaryOperator::And:
|
||||
case BinaryOperator::Xor:
|
||||
case BinaryOperator::Or:
|
||||
// Not handled yet.
|
||||
return UnknownVal();
|
||||
case BinaryOperator::LT:
|
||||
case BinaryOperator::GT:
|
||||
case BinaryOperator::LE:
|
||||
case BinaryOperator::GE:
|
||||
case BinaryOperator::EQ:
|
||||
case BinaryOperator::NE:
|
||||
opc = NegateComparison(opc);
|
||||
assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
|
||||
return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
|
||||
symIntExpr->getRHS(), resultTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
case nonloc::ConcreteIntKind: {
|
||||
if (isa<nonloc::ConcreteInt>(rhs)) {
|
||||
const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
|
||||
return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs));
|
||||
}
|
||||
else {
|
||||
// Swap the left and right sides and flip the operator if doing so
|
||||
// allows us to better reason about the expression (this is a form
|
||||
// of expression canonicalization).
|
||||
NonLoc tmp = rhs;
|
||||
rhs = lhs;
|
||||
lhs = tmp;
|
||||
|
||||
switch (op) {
|
||||
case BinaryOperator::LT: op = BinaryOperator::GT; continue;
|
||||
case BinaryOperator::GT: op = BinaryOperator::LT; continue;
|
||||
case BinaryOperator::LE: op = BinaryOperator::GE; continue;
|
||||
case BinaryOperator::GE: op = BinaryOperator::LE; continue;
|
||||
case BinaryOperator::EQ:
|
||||
case BinaryOperator::NE:
|
||||
case BinaryOperator::Add:
|
||||
case BinaryOperator::Mul:
|
||||
continue;
|
||||
default:
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
case nonloc::SymbolValKind: {
|
||||
if (isa<nonloc::ConcreteInt>(rhs)) {
|
||||
return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op,
|
||||
cast<nonloc::ConcreteInt>(rhs).getValue(),
|
||||
resultTy);
|
||||
}
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
|
||||
QualType resultTy) {
|
||||
switch (op) {
|
||||
default:
|
||||
return UnknownVal();
|
||||
case BinaryOperator::EQ:
|
||||
case BinaryOperator::NE:
|
||||
return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
|
||||
}
|
||||
}
|
||||
|
||||
SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
|
||||
BinaryOperator::Opcode op,
|
||||
Loc lhs, NonLoc rhs, QualType resultTy) {
|
||||
// Special case: 'rhs' is an integer that has the same width as a pointer and
|
||||
// we are using the integer location in a comparison. Normally this cannot be
|
||||
// triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
|
||||
// can generate comparisons that trigger this code.
|
||||
// FIXME: Are all locations guaranteed to have pointer width?
|
||||
if (BinaryOperator::isEqualityOp(op)) {
|
||||
if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
|
||||
const llvm::APSInt *x = &rhsInt->getValue();
|
||||
ASTContext &ctx = ValMgr.getContext();
|
||||
if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
|
||||
// Convert the signedness of the integer (if necessary).
|
||||
if (x->isSigned())
|
||||
x = &ValMgr.getBasicValueFactory().getValue(*x, true);
|
||||
|
||||
return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate pointer arithmetic to the StoreManager.
|
||||
return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
|
||||
rhs, resultTy);
|
||||
}
|
@ -85,12 +85,6 @@ llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) {
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& std::operator<<(std::ostream& os, const SymExpr *SE) {
|
||||
llvm::raw_os_ostream O(os);
|
||||
print(O, SE);
|
||||
return os;
|
||||
}
|
||||
|
||||
const SymbolRegionValue*
|
||||
SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) {
|
||||
llvm::FoldingSetNodeID profile;
|
||||
|
@ -66,7 +66,8 @@ namespace {
|
||||
KEYCXX = 4,
|
||||
KEYCXX0X = 8,
|
||||
KEYGNU = 16,
|
||||
KEYMS = 32
|
||||
KEYMS = 32,
|
||||
BOOLSUPPORT = 64
|
||||
};
|
||||
}
|
||||
|
||||
@ -88,6 +89,7 @@ static void AddKeyword(const char *Keyword, unsigned KWLen,
|
||||
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
|
||||
else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
|
||||
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
|
||||
else if (LangOpts.OpenCL && (Flags & BOOLSUPPORT)) AddResult = 2;
|
||||
|
||||
// Don't add this keyword if disabled in this language.
|
||||
if (AddResult == 0) return;
|
||||
|
@ -943,7 +943,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
|
||||
return SourceLocation();
|
||||
|
||||
unsigned FilePos = Content->SourceLineCache[Line - 1];
|
||||
const char *Buf = Content->getBuffer()->getBufferStart();
|
||||
const char *Buf = Content->getBuffer()->getBufferStart() + FilePos;
|
||||
unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf;
|
||||
unsigned i = 0;
|
||||
|
||||
@ -957,6 +957,107 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
|
||||
getFileLocWithOffset(FilePos + Col - 1);
|
||||
}
|
||||
|
||||
/// \brief Determines the order of 2 source locations in the translation unit.
|
||||
///
|
||||
/// \returns true if LHS source location comes before RHS, false otherwise.
|
||||
bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
|
||||
SourceLocation RHS) const {
|
||||
assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
|
||||
if (LHS == RHS)
|
||||
return false;
|
||||
|
||||
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
|
||||
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
|
||||
|
||||
// If the source locations are in the same file, just compare offsets.
|
||||
if (LOffs.first == ROffs.first)
|
||||
return LOffs.second < ROffs.second;
|
||||
|
||||
// If we are comparing a source location with multiple locations in the same
|
||||
// file, we get a big win by caching the result.
|
||||
|
||||
if (LastLFIDForBeforeTUCheck == LOffs.first &&
|
||||
LastRFIDForBeforeTUCheck == ROffs.first)
|
||||
return LastResForBeforeTUCheck;
|
||||
|
||||
LastLFIDForBeforeTUCheck = LOffs.first;
|
||||
LastRFIDForBeforeTUCheck = ROffs.first;
|
||||
|
||||
// "Traverse" the include/instantiation stacks of both locations and try to
|
||||
// find a common "ancestor".
|
||||
//
|
||||
// First we traverse the stack of the right location and check each level
|
||||
// against the level of the left location, while collecting all levels in a
|
||||
// "stack map".
|
||||
|
||||
std::map<FileID, unsigned> ROffsMap;
|
||||
ROffsMap[ROffs.first] = ROffs.second;
|
||||
|
||||
while (1) {
|
||||
SourceLocation UpperLoc;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(ROffs.first);
|
||||
if (Entry.isInstantiation())
|
||||
UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
|
||||
else
|
||||
UpperLoc = Entry.getFile().getIncludeLoc();
|
||||
|
||||
if (UpperLoc.isInvalid())
|
||||
break; // We reached the top.
|
||||
|
||||
ROffs = getDecomposedLoc(UpperLoc);
|
||||
|
||||
if (LOffs.first == ROffs.first)
|
||||
return LastResForBeforeTUCheck = LOffs.second < ROffs.second;
|
||||
|
||||
ROffsMap[ROffs.first] = ROffs.second;
|
||||
}
|
||||
|
||||
// We didn't find a common ancestor. Now traverse the stack of the left
|
||||
// location, checking against the stack map of the right location.
|
||||
|
||||
while (1) {
|
||||
SourceLocation UpperLoc;
|
||||
const SrcMgr::SLocEntry &Entry = getSLocEntry(LOffs.first);
|
||||
if (Entry.isInstantiation())
|
||||
UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
|
||||
else
|
||||
UpperLoc = Entry.getFile().getIncludeLoc();
|
||||
|
||||
if (UpperLoc.isInvalid())
|
||||
break; // We reached the top.
|
||||
|
||||
LOffs = getDecomposedLoc(UpperLoc);
|
||||
|
||||
std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first);
|
||||
if (I != ROffsMap.end())
|
||||
return LastResForBeforeTUCheck = LOffs.second < I->second;
|
||||
}
|
||||
|
||||
// No common ancestor.
|
||||
// Now we are getting into murky waters. Most probably this is because one
|
||||
// location is in the predefines buffer.
|
||||
|
||||
const FileEntry *LEntry =
|
||||
getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
|
||||
const FileEntry *REntry =
|
||||
getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
|
||||
|
||||
// If the locations are in two memory buffers we give up, we can't answer
|
||||
// which one should be considered first.
|
||||
// FIXME: Should there be a way to "include" memory buffers in the translation
|
||||
// unit ?
|
||||
assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers.");
|
||||
(void) REntry;
|
||||
|
||||
// Consider the memory buffer as coming before the file in the translation
|
||||
// unit.
|
||||
if (LEntry == 0)
|
||||
return LastResForBeforeTUCheck = true;
|
||||
else {
|
||||
assert(REntry == 0 && "Locations in not #included files ?");
|
||||
return LastResForBeforeTUCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// PrintStats - Print statistics to stderr.
|
||||
///
|
||||
|
@ -930,7 +930,7 @@ class WindowsX86_32TargetInfo : public X86_32TargetInfo {
|
||||
WindowsX86_32TargetInfo(const std::string& triple)
|
||||
: X86_32TargetInfo(triple) {
|
||||
TLSSupported = false;
|
||||
WCharType = SignedShort;
|
||||
WCharType = UnsignedShort;
|
||||
WCharWidth = WCharAlign = 16;
|
||||
DoubleAlign = LongLongAlign = 64;
|
||||
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
|
||||
|
@ -50,24 +50,6 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
|
||||
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
|
||||
/// one if necessary. This returns null for invalid source locations.
|
||||
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
|
||||
|
||||
// Each input file is encoded as a separate compile unit in LLVM
|
||||
// debugging information output. However, many target specific tool chains
|
||||
// prefer to encode only one compile unit in an object file. In this
|
||||
// situation, the LLVM code generator will include debugging information
|
||||
// entities in the compile unit that is marked as main compile unit. The
|
||||
// code generator accepts maximum one main compile unit per module. If a
|
||||
// module does not contain any main compile unit then the code generator
|
||||
// will emit multiple compile units in the output object file. Create main
|
||||
// compile unit if there is not one available.
|
||||
const LangOptions &LO = M->getLangOptions();
|
||||
if (isMainCompileUnitCreated == false) {
|
||||
if (LO.getMainFileName()) {
|
||||
createCompileUnit(LO.getMainFileName(), true /* isMain */);
|
||||
isMainCompileUnitCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get source file information.
|
||||
const char *FileName = "<unknown>";
|
||||
SourceManager &SM = M->getContext().getSourceManager();
|
||||
@ -90,26 +72,25 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
|
||||
AbsFileName = tmp;
|
||||
}
|
||||
|
||||
// There is only one main source file at a time whose compile unit
|
||||
// is already created.
|
||||
Unit = createCompileUnit(FileName, false /* isMain */);
|
||||
return Unit;
|
||||
}
|
||||
|
||||
/// createCompileUnit - Create a new unit for the given file.
|
||||
llvm::DICompileUnit CGDebugInfo::createCompileUnit(const char *FileName,
|
||||
bool isMain) {
|
||||
|
||||
// Get absolute path name.
|
||||
llvm::sys::Path AbsFileName(FileName);
|
||||
if (!AbsFileName.isAbsolute()) {
|
||||
llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
|
||||
tmp.appendComponent(FileName);
|
||||
AbsFileName = tmp;
|
||||
// See if thie compile unit is representing main source file. Each source
|
||||
// file has corresponding compile unit. There is only one main source
|
||||
// file at a time.
|
||||
bool isMain = false;
|
||||
const LangOptions &LO = M->getLangOptions();
|
||||
const char *MainFileName = LO.getMainFileName();
|
||||
if (isMainCompileUnitCreated == false) {
|
||||
if (MainFileName) {
|
||||
if (!strcmp(AbsFileName.getLast().c_str(), MainFileName))
|
||||
isMain = true;
|
||||
} else {
|
||||
if (Loc.isValid() && SM.isFromMainFile(Loc))
|
||||
isMain = true;
|
||||
}
|
||||
if (isMain)
|
||||
isMainCompileUnitCreated = true;
|
||||
}
|
||||
|
||||
unsigned LangTag;
|
||||
const LangOptions &LO = M->getLangOptions();
|
||||
if (LO.CPlusPlus) {
|
||||
if (LO.ObjC1)
|
||||
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
|
||||
@ -133,13 +114,12 @@ llvm::DICompileUnit CGDebugInfo::createCompileUnit(const char *FileName,
|
||||
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
|
||||
|
||||
// Create new compile unit.
|
||||
return DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
|
||||
AbsFileName.getDirname(),
|
||||
Producer, isMain, isOptimized,
|
||||
Flags, RuntimeVers);
|
||||
return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
|
||||
AbsFileName.getDirname(),
|
||||
Producer, isMain, isOptimized,
|
||||
Flags, RuntimeVers);
|
||||
}
|
||||
|
||||
|
||||
/// CreateType - Get the Basic type from the cache or create a new
|
||||
/// one if necessary.
|
||||
llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
|
||||
@ -810,6 +790,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
|
||||
case Type::TypeOf:
|
||||
return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(),
|
||||
Unit);
|
||||
case Type::Decltype:
|
||||
return Slot = getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingExpr()
|
||||
->getType(), Unit);
|
||||
}
|
||||
|
||||
return Slot;
|
||||
|
@ -111,9 +111,7 @@ class CGDebugInfo {
|
||||
void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
|
||||
CGBuilderTy &Builder);
|
||||
|
||||
/// createCompileUnit - Create a new unit for the given file.
|
||||
llvm::DICompileUnit createCompileUnit(const char *FileName, bool isMain);
|
||||
|
||||
|
||||
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
|
||||
/// new one if necessary.
|
||||
llvm::DICompileUnit getOrCreateCompileUnit(SourceLocation Loc);
|
||||
|
@ -234,7 +234,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty,
|
||||
}
|
||||
// FIXME: Align this on at least an Align boundary, assert if we can't.
|
||||
assert((Align <= unsigned(Target.getPointerAlign(0))/8)
|
||||
&& "Can't align more thqn pointer yet");
|
||||
&& "Can't align more than pointer yet");
|
||||
Types[needsCopyDispose*2 + 4] = LTy;
|
||||
return llvm::StructType::get(Types, false);
|
||||
}
|
||||
|
@ -606,11 +606,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
|
||||
cast<llvm::VectorType>(Vec->getType())->getNumElements();
|
||||
if (NumDstElts == NumSrcElts) {
|
||||
// Use shuffle vector is the src and destination are the same number
|
||||
// of elements
|
||||
llvm::SmallVector<llvm::Constant*, 4> Mask;
|
||||
// of elements and restore the vector mask since it is on the side
|
||||
// it will be stored.
|
||||
llvm::SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
|
||||
for (unsigned i = 0; i != NumSrcElts; ++i) {
|
||||
unsigned InIdx = getAccessedFieldNo(i, Elts);
|
||||
Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
|
||||
Mask[InIdx] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
|
||||
}
|
||||
|
||||
llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
|
||||
|
@ -139,6 +139,7 @@ class CGObjCGNU : public CodeGen::CGObjCRuntime {
|
||||
const ObjCProtocolDecl *PD);
|
||||
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
|
||||
virtual llvm::Function *ModuleInitFunction();
|
||||
virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
|
||||
virtual llvm::Function *GetPropertyGetFunction();
|
||||
virtual llvm::Function *GetPropertySetFunction();
|
||||
virtual llvm::Function *EnumerationMutationFunction();
|
||||
@ -998,6 +999,10 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
||||
Classes.push_back(ClassStruct);
|
||||
}
|
||||
|
||||
void CGObjCGNU::MergeMetadataGlobals(
|
||||
std::vector<llvm::Constant*> &UsedArray) {
|
||||
}
|
||||
|
||||
llvm::Function *CGObjCGNU::ModuleInitFunction() {
|
||||
// Only emit an ObjC load function if no Objective-C stuff has been called
|
||||
if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
|
||||
|
@ -911,6 +911,8 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
|
||||
const CallArgList &CallArgs,
|
||||
const ObjCCommonTypesHelper &ObjCTypes);
|
||||
|
||||
virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray);
|
||||
|
||||
public:
|
||||
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm)
|
||||
{ }
|
||||
@ -3426,6 +3428,16 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
|
||||
NameOut += ']';
|
||||
}
|
||||
|
||||
void CGObjCCommonMac::MergeMetadataGlobals(
|
||||
std::vector<llvm::Constant*> &UsedArray) {
|
||||
llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
|
||||
e = UsedGlobals.end(); i != e; ++i) {
|
||||
UsedArray.push_back(llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(*i),
|
||||
i8PTy));
|
||||
}
|
||||
}
|
||||
|
||||
void CGObjCMac::FinishModule() {
|
||||
EmitModuleInfo();
|
||||
|
||||
@ -3447,22 +3459,6 @@ void CGObjCMac::FinishModule() {
|
||||
Values));
|
||||
}
|
||||
|
||||
std::vector<llvm::Constant*> Used;
|
||||
for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
|
||||
e = UsedGlobals.end(); i != e; ++i) {
|
||||
Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
|
||||
}
|
||||
|
||||
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
|
||||
llvm::GlobalValue *GV =
|
||||
new llvm::GlobalVariable(AT, false,
|
||||
llvm::GlobalValue::AppendingLinkage,
|
||||
llvm::ConstantArray::get(AT, Used),
|
||||
"llvm.used",
|
||||
&CGM.getModule());
|
||||
|
||||
GV->setSection("llvm.metadata");
|
||||
|
||||
// Add assembler directives to add lazy undefined symbol references
|
||||
// for classes which are referenced but not defined. This is
|
||||
// important for correct linker interaction.
|
||||
@ -4111,24 +4107,6 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
|
||||
IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
|
||||
IMGV->setConstant(true);
|
||||
UsedGlobals.push_back(IMGV);
|
||||
|
||||
std::vector<llvm::Constant*> Used;
|
||||
|
||||
for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
|
||||
e = UsedGlobals.end(); i != e; ++i) {
|
||||
Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
|
||||
}
|
||||
|
||||
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
|
||||
llvm::GlobalValue *GV =
|
||||
new llvm::GlobalVariable(AT, false,
|
||||
llvm::GlobalValue::AppendingLinkage,
|
||||
llvm::ConstantArray::get(AT, Used),
|
||||
"llvm.used",
|
||||
&CGM.getModule());
|
||||
|
||||
GV->setSection("llvm.metadata");
|
||||
|
||||
}
|
||||
|
||||
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
|
||||
@ -5036,16 +5014,13 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
|
||||
}
|
||||
}
|
||||
else if (!IsSuper && ResultType->isFloatingType()) {
|
||||
if (const BuiltinType *BT = ResultType->getAsBuiltinType()) {
|
||||
BuiltinType::Kind k = BT->getKind();
|
||||
if (k == BuiltinType::LongDouble) {
|
||||
Fn = ObjCTypes.getMessageSendFpretFixupFn();
|
||||
Name += "objc_msgSend_fpret_fixup";
|
||||
}
|
||||
else {
|
||||
Fn = ObjCTypes.getMessageSendFixupFn();
|
||||
Name += "objc_msgSend_fixup";
|
||||
}
|
||||
if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) {
|
||||
Fn = ObjCTypes.getMessageSendFpretFixupFn();
|
||||
Name += "objc_msgSend_fpret_fixup";
|
||||
}
|
||||
else {
|
||||
Fn = ObjCTypes.getMessageSendFixupFn();
|
||||
Name += "objc_msgSend_fixup";
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -95,6 +95,9 @@ class CGObjCRuntime {
|
||||
/// this compilation unit with the runtime library.
|
||||
virtual llvm::Function *ModuleInitFunction() = 0;
|
||||
|
||||
/// Add metadata globals to the 'used' globals for final output.
|
||||
virtual void MergeMetadataGlobals(std::vector<llvm::Constant*> &UsedArray) = 0;
|
||||
|
||||
/// Get a selector for the specified name and type values. The
|
||||
/// return value should have the LLVM type for pointer-to
|
||||
/// ASTContext::getObjCSelType().
|
||||
|
@ -406,11 +406,12 @@ void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
|
||||
|
||||
void CodeGenModule::EmitLLVMUsed() {
|
||||
// Don't create llvm.used if there is no need.
|
||||
if (LLVMUsed.empty())
|
||||
// FIXME. Runtime indicates that there might be more 'used' symbols; but not
|
||||
// necessariy. So, this test is not accurate for emptiness.
|
||||
if (LLVMUsed.empty() && !Runtime)
|
||||
return;
|
||||
|
||||
llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, LLVMUsed.size());
|
||||
|
||||
// Convert LLVMUsed to what ConstantArray needs.
|
||||
std::vector<llvm::Constant*> UsedArray;
|
||||
@ -420,6 +421,12 @@ void CodeGenModule::EmitLLVMUsed() {
|
||||
llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]), i8PTy);
|
||||
}
|
||||
|
||||
if (Runtime)
|
||||
Runtime->MergeMetadataGlobals(UsedArray);
|
||||
if (UsedArray.empty())
|
||||
return;
|
||||
llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size());
|
||||
|
||||
llvm::GlobalVariable *GV =
|
||||
new llvm::GlobalVariable(ATy, false,
|
||||
llvm::GlobalValue::AppendingLinkage,
|
||||
|
@ -539,6 +539,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
|
||||
assert(false &&
|
||||
"Overloaded and dependent types shouldn't get to name mangling");
|
||||
break;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Should not see undeduced auto here");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,14 +113,10 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
|
||||
break;
|
||||
|
||||
case PCHReader::Failure:
|
||||
// Unrecoverable failure: don't even try to process the input
|
||||
// file.
|
||||
case PCHReader::IgnorePCH:
|
||||
if (ErrMsg)
|
||||
*ErrMsg = "Could not load PCH file";
|
||||
return NULL;
|
||||
|
||||
case PCHReader::IgnorePCH:
|
||||
assert(0 && "Is there a validation that should not have happened ?");
|
||||
}
|
||||
|
||||
// PCH loaded successfully. Now create the preprocessor.
|
||||
|
@ -469,10 +469,6 @@ static void ActionCheckerCFRef(AnalysisManager& mgr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionCheckerSimple(AnalysisManager& mgr) {
|
||||
ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
|
||||
}
|
||||
|
||||
static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
|
||||
if (LiveVariables* L = mgr.getLiveVariables()) {
|
||||
mgr.DisplayFunction();
|
||||
|
@ -3,6 +3,7 @@ set(LLVM_NO_RTTI 1)
|
||||
add_clang_library(clangFrontend
|
||||
AnalysisConsumer.cpp
|
||||
ASTConsumers.cpp
|
||||
ASTUnit.cpp
|
||||
Backend.cpp
|
||||
CacheTokens.cpp
|
||||
DeclXML.cpp
|
||||
@ -25,6 +26,7 @@ add_clang_library(clangFrontend
|
||||
PlistDiagnostics.cpp
|
||||
PrintParserCallbacks.cpp
|
||||
PrintPreprocessedOutput.cpp
|
||||
ResolveLocation.cpp
|
||||
RewriteBlocks.cpp
|
||||
RewriteMacros.cpp
|
||||
RewriteObjC.cpp
|
||||
@ -36,4 +38,7 @@ add_clang_library(clangFrontend
|
||||
Warnings.cpp
|
||||
)
|
||||
|
||||
add_dependencies(clangFrontend ClangDiagnosticFrontend)
|
||||
add_dependencies(clangFrontend
|
||||
ClangDiagnosticFrontend
|
||||
ClangDiagnosticLex
|
||||
ClangDiagnosticSema)
|
||||
|
@ -71,6 +71,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
|
||||
PARSE_LANGOPT_BENIGN(WritableStrings);
|
||||
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
|
||||
diag::warn_pch_lax_vector_conversions);
|
||||
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
|
||||
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
|
||||
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
|
||||
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
|
||||
@ -105,6 +106,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
|
||||
}
|
||||
PARSE_LANGOPT_BENIGN(getVisibilityMode());
|
||||
PARSE_LANGOPT_BENIGN(InstantiationDepth);
|
||||
PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
|
||||
#undef PARSE_LANGOPT_IRRELEVANT
|
||||
#undef PARSE_LANGOPT_BENIGN
|
||||
|
||||
@ -1629,6 +1631,7 @@ bool PCHReader::ParseLanguageOptions(
|
||||
PARSE_LANGOPT(PascalStrings);
|
||||
PARSE_LANGOPT(WritableStrings);
|
||||
PARSE_LANGOPT(LaxVectorConversions);
|
||||
PARSE_LANGOPT(AltiVec);
|
||||
PARSE_LANGOPT(Exceptions);
|
||||
PARSE_LANGOPT(NeXTRuntime);
|
||||
PARSE_LANGOPT(Freestanding);
|
||||
@ -1652,6 +1655,7 @@ bool PCHReader::ParseLanguageOptions(
|
||||
LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]);
|
||||
++Idx;
|
||||
PARSE_LANGOPT(InstantiationDepth);
|
||||
PARSE_LANGOPT(OpenCL);
|
||||
#undef PARSE_LANGOPT
|
||||
|
||||
return Listener->ReadLanguageOptions(LangOpts);
|
||||
@ -1822,7 +1826,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
||||
QualType UnderlyingType = GetType(Record[0]);
|
||||
return Context->getTypeOfType(UnderlyingType);
|
||||
}
|
||||
|
||||
|
||||
case pch::TYPE_DECLTYPE:
|
||||
return Context->getDecltypeType(ReadTypeExpr());
|
||||
|
||||
case pch::TYPE_RECORD:
|
||||
assert(Record.size() == 1 && "incorrect encoding of record type");
|
||||
return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
|
||||
|
@ -489,6 +489,14 @@ Attr *PCHReader::ReadAttributes() {
|
||||
New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
|
||||
break;
|
||||
}
|
||||
|
||||
case Attr::ReqdWorkGroupSize: {
|
||||
unsigned X = Record[Idx++];
|
||||
unsigned Y = Record[Idx++];
|
||||
unsigned Z = Record[Idx++];
|
||||
New = ::new (*Context) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
break;
|
||||
}
|
||||
|
||||
SIMPLE_ATTR(ObjCException);
|
||||
SIMPLE_ATTR(ObjCNSObject);
|
||||
|
@ -185,6 +185,11 @@ void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) {
|
||||
Code = pch::TYPE_TYPEOF;
|
||||
}
|
||||
|
||||
void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) {
|
||||
Writer.AddStmt(T->getUnderlyingExpr());
|
||||
Code = pch::TYPE_DECLTYPE;
|
||||
}
|
||||
|
||||
void PCHTypeWriter::VisitTagType(const TagType *T) {
|
||||
Writer.AddDeclRef(T->getDecl(), Record);
|
||||
assert(!T->isBeingDefined() &&
|
||||
@ -526,6 +531,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
|
||||
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
|
||||
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
|
||||
Record.push_back(LangOpts.LaxVectorConversions);
|
||||
Record.push_back(LangOpts.AltiVec);
|
||||
Record.push_back(LangOpts.Exceptions); // Support exception handling.
|
||||
|
||||
Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
|
||||
@ -563,6 +569,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
|
||||
Record.push_back(LangOpts.getGCMode());
|
||||
Record.push_back(LangOpts.getVisibilityMode());
|
||||
Record.push_back(LangOpts.InstantiationDepth);
|
||||
Record.push_back(LangOpts.OpenCL);
|
||||
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
|
||||
}
|
||||
|
||||
@ -1615,6 +1622,12 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
|
||||
case Attr::Regparm:
|
||||
Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
|
||||
break;
|
||||
|
||||
case Attr::ReqdWorkGroupSize:
|
||||
Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getXDim());
|
||||
Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getYDim());
|
||||
Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getZDim());
|
||||
break;
|
||||
|
||||
case Attr::Section:
|
||||
AddString(cast<SectionAttr>(Attr)->getName(), Record);
|
||||
@ -1896,6 +1909,9 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
|
||||
case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break;
|
||||
case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
|
||||
case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Should not see undeduced auto here");
|
||||
break;
|
||||
}
|
||||
|
||||
Record.push_back((ID << 3) | T.getCVRQualifiers());
|
||||
|
322
lib/Frontend/ResolveLocation.cpp
Normal file
322
lib/Frontend/ResolveLocation.cpp
Normal file
@ -0,0 +1,322 @@
|
||||
//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This defines the ResolveLocationInAST function, which resolves a
|
||||
// source location into a <Decl *, Stmt *> pair.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/AST/DeclVisitor.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
/// \brief Base for the LocResolver classes. Mostly does source range checking.
|
||||
class VISIBILITY_HIDDEN LocResolverBase {
|
||||
protected:
|
||||
ASTContext &Ctx;
|
||||
SourceLocation Loc;
|
||||
|
||||
Decl *Dcl;
|
||||
Stmt *Stm;
|
||||
bool PassedLoc;
|
||||
|
||||
/// \brief Checks whether Loc is in the source range of 'D'.
|
||||
///
|
||||
/// If it is, updates Dcl. If Loc is passed the source range, it sets
|
||||
/// PassedLoc, otherwise it does nothing.
|
||||
void CheckRange(Decl *D);
|
||||
|
||||
/// \brief Checks whether Loc is in the source range of 'Node'.
|
||||
///
|
||||
/// If it is, updates Stm. If Loc is passed the source range, it sets
|
||||
/// PassedLoc, otherwise it does nothing.
|
||||
void CheckRange(Stmt *Node);
|
||||
|
||||
/// \brief Updates the end source range to cover the full length of the token
|
||||
/// positioned at the end of the source range.
|
||||
///
|
||||
/// e.g.,
|
||||
/// @code
|
||||
/// int foo
|
||||
/// ^ ^
|
||||
/// @endcode
|
||||
/// will be updated to
|
||||
/// @code
|
||||
/// int foo
|
||||
/// ^ ^
|
||||
/// @endcode
|
||||
void FixRange(SourceRange &Range);
|
||||
|
||||
public:
|
||||
LocResolverBase(ASTContext &ctx, SourceLocation loc)
|
||||
: Ctx(ctx), Loc(loc), Dcl(0), Stm(0), PassedLoc(0) {}
|
||||
|
||||
/// \brief We found a AST node that corresponds to the source location.
|
||||
bool FoundIt() const { return Dcl != 0 || Stm != 0; }
|
||||
|
||||
/// \brief We either found a AST node or we passed the source location while
|
||||
/// searching.
|
||||
bool Finished() const { return FoundIt() || PassedLoc; }
|
||||
|
||||
Decl *getDecl() const { return Dcl; }
|
||||
Stmt *getStmt() const { return Stm; }
|
||||
|
||||
std::pair<Decl *, Stmt *> getResult() const {
|
||||
return std::make_pair(getDecl(), getStmt());
|
||||
}
|
||||
|
||||
/// \brief Debugging output.
|
||||
void print(Decl *D);
|
||||
/// \brief Debugging output.
|
||||
void print(Stmt *Node);
|
||||
};
|
||||
|
||||
/// \brief Searches a statement for the AST node that corresponds to a source
|
||||
/// location.
|
||||
class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
|
||||
public StmtVisitor<StmtLocResolver> {
|
||||
public:
|
||||
StmtLocResolver(ASTContext &ctx, SourceLocation loc)
|
||||
: LocResolverBase(ctx, loc) {}
|
||||
|
||||
void VisitDeclStmt(DeclStmt *Node);
|
||||
void VisitStmt(Stmt *Node);
|
||||
};
|
||||
|
||||
/// \brief Searches a declaration for the AST node that corresponds to a source
|
||||
/// location.
|
||||
class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
|
||||
public DeclVisitor<DeclLocResolver> {
|
||||
public:
|
||||
DeclLocResolver(ASTContext &ctx, SourceLocation loc)
|
||||
: LocResolverBase(ctx, loc) {}
|
||||
|
||||
void VisitDeclContext(DeclContext *DC);
|
||||
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
|
||||
void VisitVarDecl(VarDecl *D);
|
||||
void VisitFunctionDecl(FunctionDecl *D);
|
||||
void VisitDecl(Decl *D);
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
|
||||
CheckRange(Node);
|
||||
if (!FoundIt())
|
||||
return;
|
||||
assert(Stm == Node && "Result not updated ?");
|
||||
|
||||
// Search all declarations of this DeclStmt. If we found the one corresponding
|
||||
// to the source location, update this StmtLocResolver's result.
|
||||
DeclLocResolver DLR(Ctx, Loc);
|
||||
for (DeclStmt::decl_iterator
|
||||
I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
|
||||
DLR.Visit(*I);
|
||||
if (DLR.Finished()) {
|
||||
if (DLR.FoundIt())
|
||||
llvm::tie(Dcl, Stm) = DLR.getResult();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StmtLocResolver::VisitStmt(Stmt *Node) {
|
||||
CheckRange(Node);
|
||||
if (!FoundIt())
|
||||
return;
|
||||
assert(Stm == Node && "Result not updated ?");
|
||||
|
||||
// Search the child statements.
|
||||
StmtLocResolver SLR(Ctx, Loc);
|
||||
for (Stmt::child_iterator
|
||||
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
|
||||
SLR.Visit(*I);
|
||||
if (!SLR.Finished())
|
||||
continue;
|
||||
|
||||
// We either found it or we passed the source location.
|
||||
|
||||
if (SLR.FoundIt()) {
|
||||
// Only update Dcl if we found another more immediate 'parent' Decl for
|
||||
// the statement.
|
||||
if (SLR.getDecl())
|
||||
Dcl = SLR.getDecl();
|
||||
Stm = SLR.getStmt();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DeclLocResolver::VisitDeclContext(DeclContext *DC) {
|
||||
DeclLocResolver DLR(Ctx, Loc);
|
||||
for (DeclContext::decl_iterator
|
||||
I = DC->decls_begin(Ctx), E = DC->decls_end(Ctx); I != E; ++I) {
|
||||
DLR.Visit(*I);
|
||||
if (DLR.Finished()) {
|
||||
if (DLR.FoundIt())
|
||||
llvm::tie(Dcl, Stm) = DLR.getResult();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
|
||||
VisitDeclContext(TU);
|
||||
}
|
||||
|
||||
void DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
|
||||
CheckRange(D);
|
||||
if (!FoundIt())
|
||||
return;
|
||||
assert(Dcl == D && "Result not updated ?");
|
||||
|
||||
// First, search through the parameters of the function.
|
||||
DeclLocResolver ParmRes(Ctx, Loc);
|
||||
for (FunctionDecl::param_iterator
|
||||
I = D->param_begin(), E = D->param_end(); I != E; ++I) {
|
||||
ParmRes.Visit(*I);
|
||||
if (ParmRes.Finished()) {
|
||||
if (ParmRes.FoundIt())
|
||||
llvm::tie(Dcl, Stm) = ParmRes.getResult();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't found the location in the parameters and we didn't get passed it.
|
||||
|
||||
// Second, search through the declarations that are part of the function.
|
||||
// If we find he location there, we won't have to search through its body.
|
||||
DeclLocResolver DLR(Ctx, Loc);
|
||||
DLR.VisitDeclContext(D);
|
||||
if (DLR.FoundIt()) {
|
||||
llvm::tie(Dcl, Stm) = DLR.getResult();
|
||||
return;
|
||||
}
|
||||
|
||||
// We didn't find a declaration that corresponds to the source location.
|
||||
|
||||
// Finally, search through the body of the function.
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
StmtLocResolver SLR(Ctx, Loc);
|
||||
SLR.Visit(D->getBody(Ctx));
|
||||
if (SLR.FoundIt()) {
|
||||
llvm::tie(Dcl, Stm) = SLR.getResult();
|
||||
// If we didn't find a more immediate 'parent' declaration for the
|
||||
// statement, set the function as the parent.
|
||||
if (Dcl == 0)
|
||||
Dcl = D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclLocResolver::VisitVarDecl(VarDecl *D) {
|
||||
CheckRange(D);
|
||||
if (!FoundIt())
|
||||
return;
|
||||
assert(Dcl == D && "Result not updated ?");
|
||||
|
||||
// Check whether the location points to the init expression.
|
||||
if (D->getInit()) {
|
||||
StmtLocResolver SLR(Ctx, Loc);
|
||||
SLR.Visit(D->getInit());
|
||||
Stm = SLR.getStmt();
|
||||
}
|
||||
}
|
||||
|
||||
void DeclLocResolver::VisitDecl(Decl *D) {
|
||||
CheckRange(D);
|
||||
}
|
||||
|
||||
void LocResolverBase::CheckRange(Decl *D) {
|
||||
SourceRange Range = D->getSourceRange();
|
||||
if (!Range.isValid())
|
||||
return;
|
||||
|
||||
FixRange(Range);
|
||||
|
||||
SourceManager &SourceMgr = Ctx.getSourceManager();
|
||||
if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
|
||||
return;
|
||||
|
||||
if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
|
||||
PassedLoc = true;
|
||||
else
|
||||
Dcl = D;
|
||||
}
|
||||
|
||||
void LocResolverBase::CheckRange(Stmt *Node) {
|
||||
SourceRange Range = Node->getSourceRange();
|
||||
if (!Range.isValid())
|
||||
return;
|
||||
|
||||
FixRange(Range);
|
||||
|
||||
SourceManager &SourceMgr = Ctx.getSourceManager();
|
||||
if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
|
||||
return;
|
||||
|
||||
if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
|
||||
PassedLoc = true;
|
||||
else
|
||||
Stm = Node;
|
||||
}
|
||||
|
||||
void LocResolverBase::FixRange(SourceRange &Range) {
|
||||
if (!Range.isValid())
|
||||
return;
|
||||
|
||||
unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
|
||||
Ctx.getSourceManager(),
|
||||
Ctx.getLangOptions());
|
||||
Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
|
||||
}
|
||||
|
||||
void LocResolverBase::print(Decl *D) {
|
||||
llvm::raw_ostream &OS = llvm::outs();
|
||||
OS << "#### DECL ####\n";
|
||||
D->print(OS, Ctx);
|
||||
OS << " <";
|
||||
D->getLocStart().print(OS, Ctx.getSourceManager());
|
||||
OS << " > - <";
|
||||
D->getLocEnd().print(OS, Ctx.getSourceManager());
|
||||
OS << ">\n\n";
|
||||
OS.flush();
|
||||
}
|
||||
|
||||
void LocResolverBase::print(Stmt *Node) {
|
||||
llvm::raw_ostream &OS = llvm::outs();
|
||||
OS << "#### STMT ####\n";
|
||||
Node->printPretty(OS, Ctx);
|
||||
OS << " <";
|
||||
Node->getLocStart().print(OS, Ctx.getSourceManager());
|
||||
OS << " > - <";
|
||||
Node->getLocEnd().print(OS, Ctx.getSourceManager());
|
||||
OS << ">\n\n";
|
||||
OS.flush();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Returns the AST node that a source location points to.
|
||||
///
|
||||
std::pair<Decl *, Stmt *>
|
||||
clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
|
||||
if (Loc.isInvalid())
|
||||
return std::make_pair((Decl*)0, (Stmt*)0);
|
||||
|
||||
DeclLocResolver DLR(Ctx, Loc);
|
||||
DLR.Visit(Ctx.getTranslationUnitDecl());
|
||||
return DLR.getResult();
|
||||
}
|
@ -31,7 +31,7 @@ foreach( f ${files} )
|
||||
COMMENT "Copying clang's ${f}...")
|
||||
endforeach( f )
|
||||
|
||||
add_custom_target(clang_headers ALL
|
||||
add_custom_target(clang-headers ALL
|
||||
DEPENDS ${files})
|
||||
|
||||
install(FILES ${files}
|
||||
|
@ -118,6 +118,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
|
||||
case 13:
|
||||
if (!memcmp(Str, "address_space", 13)) return AT_address_space;
|
||||
if (!memcmp(Str, "always_inline", 13)) return AT_always_inline;
|
||||
if (!memcmp(Str, "vec_type_hint", 13)) return IgnoredAttribute;
|
||||
break;
|
||||
case 14:
|
||||
if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception;
|
||||
@ -136,6 +137,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
|
||||
if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained;
|
||||
if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained;
|
||||
break;
|
||||
case 20:
|
||||
if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size;
|
||||
case 22:
|
||||
if (!memcmp(Str, "no_instrument_function", 22))
|
||||
return AT_no_instrument_function;
|
||||
|
@ -173,6 +173,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
|
||||
case DeclSpec::TST_typename: return "type-name";
|
||||
case DeclSpec::TST_typeofType:
|
||||
case DeclSpec::TST_typeofExpr: return "typeof";
|
||||
case DeclSpec::TST_auto: return "auto";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdentLoc,
|
||||
IdentifierInfo *TargetName,
|
||||
OverloadedOperatorKind Op,
|
||||
AttributeList *AttrList,
|
||||
bool IsTypeName) {
|
||||
|
||||
|
@ -149,13 +149,35 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
|
||||
}
|
||||
}
|
||||
} else { // not an identifier
|
||||
switch (Tok.getKind()) {
|
||||
case tok::r_paren:
|
||||
// parse a possibly empty comma separated list of expressions
|
||||
if (Tok.is(tok::r_paren)) {
|
||||
// __attribute__(( nonnull() ))
|
||||
ConsumeParen(); // ignore the right paren loc for now
|
||||
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
||||
0, SourceLocation(), 0, 0, CurrAttr);
|
||||
} else {
|
||||
break;
|
||||
case tok::kw_char:
|
||||
case tok::kw_wchar_t:
|
||||
case tok::kw_bool:
|
||||
case tok::kw_short:
|
||||
case tok::kw_int:
|
||||
case tok::kw_long:
|
||||
case tok::kw_signed:
|
||||
case tok::kw_unsigned:
|
||||
case tok::kw_float:
|
||||
case tok::kw_double:
|
||||
case tok::kw_void:
|
||||
case tok::kw_typeof:
|
||||
// If it's a builtin type name, eat it and expect a rparen
|
||||
// __attribute__(( vec_type_hint(char) ))
|
||||
ConsumeToken();
|
||||
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
||||
0, SourceLocation(), 0, 0, CurrAttr);
|
||||
if (Tok.is(tok::r_paren))
|
||||
ConsumeParen();
|
||||
break;
|
||||
default:
|
||||
// __attribute__(( aligned(16) ))
|
||||
ExprVector ArgExprs(Actions);
|
||||
bool ArgExprsOk = true;
|
||||
@ -181,6 +203,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
|
||||
SourceLocation(), ArgExprs.take(), ArgExprs.size(),
|
||||
CurrAttr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -371,7 +394,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
|
||||
/// According to the standard grammar, =default and =delete are function
|
||||
/// definitions, but that definitely doesn't fit with the parser here.
|
||||
///
|
||||
Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
|
||||
Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo) {
|
||||
// If a simple-asm-expr is present, parse it.
|
||||
if (Tok.is(tok::kw_asm)) {
|
||||
SourceLocation Loc;
|
||||
@ -393,7 +417,13 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
|
||||
}
|
||||
|
||||
// Inform the current actions module that we just parsed this declarator.
|
||||
DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
|
||||
DeclPtrTy ThisDecl = TemplateInfo.TemplateParams?
|
||||
Actions.ActOnTemplateDeclarator(CurScope,
|
||||
Action::MultiTemplateParamsArg(Actions,
|
||||
TemplateInfo.TemplateParams->data(),
|
||||
TemplateInfo.TemplateParams->size()),
|
||||
D)
|
||||
: Actions.ActOnDeclarator(CurScope, D);
|
||||
|
||||
// Parse declarator '=' initializer.
|
||||
if (Tok.is(tok::equal)) {
|
||||
@ -896,7 +926,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_auto:
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
|
||||
if (getLang().CPlusPlus0x)
|
||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
|
||||
else
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw_register:
|
||||
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
|
||||
@ -1018,6 +1051,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
ParseTypeofSpecifier(DS);
|
||||
continue;
|
||||
|
||||
case tok::kw_decltype:
|
||||
ParseDecltypeSpecifier(DS);
|
||||
continue;
|
||||
|
||||
case tok::less:
|
||||
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
|
||||
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
|
||||
@ -1095,6 +1132,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
/// [GNU] typeof-specifier
|
||||
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
|
||||
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
|
||||
/// [C++0x] 'decltype' ( expression )
|
||||
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
|
||||
const char *&PrevSpec,
|
||||
const ParsedTemplateInfo &TemplateInfo) {
|
||||
@ -1235,6 +1273,18 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
|
||||
ParseTypeofSpecifier(DS);
|
||||
return true;
|
||||
|
||||
// C++0x decltype support.
|
||||
case tok::kw_decltype:
|
||||
ParseDecltypeSpecifier(DS);
|
||||
return true;
|
||||
|
||||
// C++0x auto support.
|
||||
case tok::kw_auto:
|
||||
if (!getLang().CPlusPlus0x)
|
||||
return false;
|
||||
|
||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec);
|
||||
break;
|
||||
case tok::kw___ptr64:
|
||||
case tok::kw___w64:
|
||||
case tok::kw___cdecl:
|
||||
|
@ -11,6 +11,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Parse/ParseDiagnostic.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
@ -274,8 +275,6 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
|
||||
ParseOptionalCXXScopeSpecifier(SS);
|
||||
|
||||
AttributeList *AttrList = 0;
|
||||
IdentifierInfo *TargetName = 0;
|
||||
SourceLocation IdentLoc = SourceLocation();
|
||||
|
||||
// Check nested-name specifier.
|
||||
if (SS.isInvalid()) {
|
||||
@ -287,17 +286,33 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
|
||||
SkipUntil(tok::semi);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
|
||||
IdentifierInfo *TargetName = 0;
|
||||
OverloadedOperatorKind Op = OO_None;
|
||||
SourceLocation IdentLoc;
|
||||
|
||||
if (Tok.is(tok::kw_operator)) {
|
||||
IdentLoc = Tok.getLocation();
|
||||
|
||||
Op = TryParseOperatorFunctionId();
|
||||
if (!Op) {
|
||||
// If there was an invalid operator, skip to end of decl, and eat ';'.
|
||||
SkipUntil(tok::semi);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
} else if (Tok.is(tok::identifier)) {
|
||||
// Parse identifier.
|
||||
TargetName = Tok.getIdentifierInfo();
|
||||
IdentLoc = ConsumeToken();
|
||||
} else {
|
||||
// FIXME: Use a better diagnostic here.
|
||||
Diag(Tok, diag::err_expected_ident_in_using);
|
||||
|
||||
// If there was invalid identifier, skip to end of decl, and eat ';'.
|
||||
SkipUntil(tok::semi);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// Parse identifier.
|
||||
TargetName = Tok.getIdentifierInfo();
|
||||
IdentLoc = ConsumeToken();
|
||||
|
||||
// Parse (optional) attributes (most likely GNU strong-using extension).
|
||||
if (Tok.is(tok::kw___attribute))
|
||||
AttrList = ParseAttributes();
|
||||
@ -308,7 +323,8 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
|
||||
AttrList ? "attributes list" : "namespace name", tok::semi);
|
||||
|
||||
return Actions.ActOnUsingDeclaration(CurScope, UsingLoc, SS,
|
||||
IdentLoc, TargetName, AttrList, IsTypeName);
|
||||
IdentLoc, TargetName, Op,
|
||||
AttrList, IsTypeName);
|
||||
}
|
||||
|
||||
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
|
||||
@ -355,6 +371,51 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
||||
move(AssertMessage));
|
||||
}
|
||||
|
||||
/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
|
||||
///
|
||||
/// 'decltype' ( expression )
|
||||
///
|
||||
void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
||||
assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
|
||||
|
||||
SourceLocation StartLoc = ConsumeToken();
|
||||
SourceLocation LParenLoc = Tok.getLocation();
|
||||
|
||||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
||||
"decltype")) {
|
||||
SkipUntil(tok::r_paren);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the expression
|
||||
|
||||
// C++0x [dcl.type.simple]p4:
|
||||
// The operand of the decltype specifier is an unevaluated operand.
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Action::Unevaluated);
|
||||
OwningExprResult Result = ParseExpression();
|
||||
if (Result.isInvalid()) {
|
||||
SkipUntil(tok::r_paren);
|
||||
return;
|
||||
}
|
||||
|
||||
// Match the ')'
|
||||
SourceLocation RParenLoc;
|
||||
if (Tok.is(tok::r_paren))
|
||||
RParenLoc = ConsumeParen();
|
||||
else
|
||||
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
if (RParenLoc.isInvalid())
|
||||
return;
|
||||
|
||||
const char *PrevSpec = 0;
|
||||
// Check for duplicate type specifiers (e.g. "int decltype(a)").
|
||||
if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
|
||||
Result.release()))
|
||||
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
||||
}
|
||||
|
||||
/// ParseClassName - Parse a C++ class-name, which names a class. Note
|
||||
/// that we only check that the result names a type; semantic analysis
|
||||
/// will need to verify that the type names a class. The result is
|
||||
|
@ -59,81 +59,39 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
||||
|
||||
while (true) {
|
||||
// nested-name-specifier:
|
||||
// type-name '::'
|
||||
// namespace-name '::'
|
||||
// nested-name-specifier identifier '::'
|
||||
if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
|
||||
// We have an identifier followed by a '::'. Lookup this name
|
||||
// as the name in a nested-name-specifier.
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
SourceLocation IdLoc = ConsumeToken();
|
||||
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
|
||||
SourceLocation CCLoc = ConsumeToken();
|
||||
// nested-name-specifier 'template'[opt] simple-template-id '::'
|
||||
|
||||
// Parse the optional 'template' keyword, then make sure we have
|
||||
// 'identifier <' after it.
|
||||
if (Tok.is(tok::kw_template)) {
|
||||
SourceLocation TemplateKWLoc = ConsumeToken();
|
||||
|
||||
if (!HasScopeSpecifier) {
|
||||
SS.setBeginLoc(IdLoc);
|
||||
HasScopeSpecifier = true;
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok.getLocation(),
|
||||
diag::err_id_after_template_in_nested_name_spec)
|
||||
<< SourceRange(TemplateKWLoc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SS.isInvalid())
|
||||
continue;
|
||||
if (NextToken().isNot(tok::less)) {
|
||||
Diag(NextToken().getLocation(),
|
||||
diag::err_less_after_template_name_in_nested_name_spec)
|
||||
<< Tok.getIdentifierInfo()->getName()
|
||||
<< SourceRange(TemplateKWLoc, Tok.getLocation());
|
||||
break;
|
||||
}
|
||||
|
||||
TemplateTy Template
|
||||
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
|
||||
*Tok.getIdentifierInfo(),
|
||||
Tok.getLocation(), SS);
|
||||
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
|
||||
&SS, TemplateKWLoc, false))
|
||||
break;
|
||||
|
||||
SS.setScopeRep(
|
||||
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
|
||||
SS.setEndLoc(CCLoc);
|
||||
continue;
|
||||
}
|
||||
|
||||
// nested-name-specifier:
|
||||
// type-name '::'
|
||||
// nested-name-specifier 'template'[opt] simple-template-id '::'
|
||||
if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
|
||||
Tok.is(tok::kw_template)) {
|
||||
// Parse the optional 'template' keyword, then make sure we have
|
||||
// 'identifier <' after it.
|
||||
if (Tok.is(tok::kw_template)) {
|
||||
SourceLocation TemplateKWLoc = ConsumeToken();
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok.getLocation(),
|
||||
diag::err_id_after_template_in_nested_name_spec)
|
||||
<< SourceRange(TemplateKWLoc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NextToken().isNot(tok::less)) {
|
||||
Diag(NextToken().getLocation(),
|
||||
diag::err_less_after_template_name_in_nested_name_spec)
|
||||
<< Tok.getIdentifierInfo()->getName()
|
||||
<< SourceRange(TemplateKWLoc, Tok.getLocation());
|
||||
break;
|
||||
}
|
||||
|
||||
TemplateTy Template
|
||||
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
|
||||
*Tok.getIdentifierInfo(),
|
||||
Tok.getLocation(),
|
||||
SS);
|
||||
AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
|
||||
&SS, TemplateKWLoc, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
TemplateTy Template;
|
||||
TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
|
||||
CurScope, Template, &SS);
|
||||
if (TNK) {
|
||||
// We have found a template name, so annotate this this token
|
||||
// with a template-id annotation. We do not permit the
|
||||
// template-id to be translated into a type annotation,
|
||||
// because some clients (e.g., the parsing of class template
|
||||
// specializations) still want to see the original template-id
|
||||
// token.
|
||||
AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
|
||||
// We have
|
||||
//
|
||||
@ -172,8 +130,62 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
||||
SS.setScopeRep(0);
|
||||
SS.setEndLoc(CCLoc);
|
||||
continue;
|
||||
} else
|
||||
assert(false && "FIXME: Only type template names supported here");
|
||||
}
|
||||
|
||||
assert(false && "FIXME: Only type template names supported here");
|
||||
}
|
||||
|
||||
|
||||
// The rest of the nested-name-specifier possibilities start with
|
||||
// tok::identifier.
|
||||
if (Tok.isNot(tok::identifier))
|
||||
break;
|
||||
|
||||
IdentifierInfo &II = *Tok.getIdentifierInfo();
|
||||
|
||||
// nested-name-specifier:
|
||||
// type-name '::'
|
||||
// namespace-name '::'
|
||||
// nested-name-specifier identifier '::'
|
||||
Token Next = NextToken();
|
||||
if (Next.is(tok::coloncolon)) {
|
||||
// We have an identifier followed by a '::'. Lookup this name
|
||||
// as the name in a nested-name-specifier.
|
||||
SourceLocation IdLoc = ConsumeToken();
|
||||
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
|
||||
SourceLocation CCLoc = ConsumeToken();
|
||||
|
||||
if (!HasScopeSpecifier) {
|
||||
SS.setBeginLoc(IdLoc);
|
||||
HasScopeSpecifier = true;
|
||||
}
|
||||
|
||||
if (SS.isInvalid())
|
||||
continue;
|
||||
|
||||
SS.setScopeRep(
|
||||
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II));
|
||||
SS.setEndLoc(CCLoc);
|
||||
continue;
|
||||
}
|
||||
|
||||
// nested-name-specifier:
|
||||
// type-name '<'
|
||||
if (Next.is(tok::less)) {
|
||||
TemplateTy Template;
|
||||
if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope,
|
||||
Template, &SS)) {
|
||||
// We have found a template name, so annotate this this token
|
||||
// with a template-id annotation. We do not permit the
|
||||
// template-id to be translated into a type annotation,
|
||||
// because some clients (e.g., the parsing of class template
|
||||
// specializations) still want to see the original template-id
|
||||
// token.
|
||||
if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(),
|
||||
false))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have any tokens that form the beginning of a
|
||||
|
@ -771,10 +771,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
||||
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
|
||||
MethodAttrs = ParseAttributes();
|
||||
|
||||
if (KeyIdents.size() == 0)
|
||||
return DeclPtrTy();
|
||||
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
|
||||
&KeyIdents[0]);
|
||||
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
|
||||
mType, IDecl, DSRet, ReturnType, Sel,
|
||||
mType, IDecl, DSRet, ReturnType, Sel,
|
||||
&ArgInfos[0], CargNames, MethodAttrs,
|
||||
MethodImplKind, isVariadic);
|
||||
}
|
||||
|
@ -170,7 +170,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
||||
// If we have a declaration or declarator list, handle it.
|
||||
if (isDeclarationAfterDeclarator()) {
|
||||
// Parse this declaration.
|
||||
DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
|
||||
DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
|
||||
TemplateInfo);
|
||||
|
||||
if (Tok.is(tok::comma)) {
|
||||
Diag(Tok, diag::err_multiple_template_declarators)
|
||||
@ -200,7 +201,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
||||
}
|
||||
return DeclPtrTy();
|
||||
}
|
||||
return ParseFunctionDefinition(DeclaratorInfo);
|
||||
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo);
|
||||
}
|
||||
|
||||
if (DeclaratorInfo.isFunctionDeclarator())
|
||||
@ -620,7 +621,11 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||
/// replaced with a type annotation token. Otherwise, the
|
||||
/// simple-template-id is always replaced with a template-id
|
||||
/// annotation token.
|
||||
void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
///
|
||||
/// If an unrecoverable parse error occurs and no annotation token can be
|
||||
/// formed, this function returns true.
|
||||
///
|
||||
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
const CXXScopeSpec *SS,
|
||||
SourceLocation TemplateKWLoc,
|
||||
bool AllowTypeAnnotation) {
|
||||
@ -643,14 +648,19 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
TemplateArgIsType,
|
||||
TemplateArgLocations,
|
||||
RAngleLoc);
|
||||
|
||||
if (Invalid) {
|
||||
// If we failed to parse the template ID but skipped ahead to a >, we're not
|
||||
// going to be able to form a token annotation. Eat the '>' if present.
|
||||
if (Tok.is(tok::greater))
|
||||
ConsumeToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
|
||||
TemplateArgIsType.data(),
|
||||
TemplateArgs.size());
|
||||
|
||||
if (Invalid) // FIXME: How to recover from a broken template-id?
|
||||
return;
|
||||
|
||||
// Build the annotation token.
|
||||
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
|
||||
Action::TypeResult Type
|
||||
@ -658,8 +668,13 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
LAngleLoc, TemplateArgsPtr,
|
||||
&TemplateArgLocations[0],
|
||||
RAngleLoc);
|
||||
if (Type.isInvalid()) // FIXME: better recovery?
|
||||
return;
|
||||
if (Type.isInvalid()) {
|
||||
// If we failed to parse the template ID but skipped ahead to a >, we're not
|
||||
// going to be able to form a token annotation. Eat the '>' if present.
|
||||
if (Tok.is(tok::greater))
|
||||
ConsumeToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
Tok.setKind(tok::annot_typename);
|
||||
Tok.setAnnotationValue(Type.get());
|
||||
@ -704,6 +719,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
// In case the tokens were cached, have Preprocessor replace them with the
|
||||
// annotation token.
|
||||
PP.AnnotateCachedTokens(Tok);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Replaces a template-id annotation token with a type
|
||||
|
@ -543,6 +543,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
|
||||
/// [GNU] typeof-specifier
|
||||
/// [GNU] '_Complex'
|
||||
/// [C++0x] 'auto' [TODO]
|
||||
/// [C++0x] 'decltype' ( expression )
|
||||
///
|
||||
/// type-name:
|
||||
/// class-name
|
||||
@ -695,7 +696,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
|
||||
|
||||
return TPResult::True();
|
||||
|
||||
// GNU typeof support.
|
||||
// GNU typeof support.
|
||||
case tok::kw_typeof: {
|
||||
if (NextToken().isNot(tok::l_paren))
|
||||
return TPResult::True();
|
||||
@ -716,6 +717,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
|
||||
return TPResult::True();
|
||||
}
|
||||
|
||||
// C++0x decltype support.
|
||||
case tok::kw_decltype:
|
||||
return TPResult::True();
|
||||
|
||||
default:
|
||||
return TPResult::False();
|
||||
}
|
||||
|
@ -590,7 +590,8 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
|
||||
/// [C++] function-definition: [C++ 8.4]
|
||||
/// decl-specifier-seq[opt] declarator function-try-block
|
||||
///
|
||||
Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
|
||||
Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo) {
|
||||
const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
|
||||
assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
|
||||
"This isn't a function declarator!");
|
||||
@ -632,7 +633,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
|
||||
|
||||
// Tell the actions module that we have entered a function definition with the
|
||||
// specified Declarator for the function.
|
||||
DeclPtrTy Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
|
||||
DeclPtrTy Res = TemplateInfo.TemplateParams?
|
||||
Actions.ActOnStartOfFunctionTemplateDef(CurScope,
|
||||
Action::MultiTemplateParamsArg(Actions,
|
||||
TemplateInfo.TemplateParams->data(),
|
||||
TemplateInfo.TemplateParams->size()),
|
||||
D)
|
||||
: Actions.ActOnStartOfFunctionDef(CurScope, D);
|
||||
|
||||
if (Tok.is(tok::kw_try))
|
||||
return ParseFunctionTryBlock(Res);
|
||||
@ -832,7 +839,8 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
|
||||
/// specifier, and another one to get the actual type inside
|
||||
/// ParseDeclarationSpecifiers).
|
||||
///
|
||||
/// This returns true if the token was annotated.
|
||||
/// This returns true if the token was annotated or an unrecoverable error
|
||||
/// occurs.
|
||||
///
|
||||
/// Note that this routine emits an error if you call it with ::new or ::delete
|
||||
/// as the current tokens, so only call it in contexts where these are invalid.
|
||||
@ -927,7 +935,12 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
||||
if (TemplateNameKind TNK
|
||||
= Actions.isTemplateName(*Tok.getIdentifierInfo(),
|
||||
CurScope, Template, &SS))
|
||||
AnnotateTemplateIdToken(Template, TNK, &SS);
|
||||
if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
|
||||
// If an unrecoverable error occurred, we need to return true here,
|
||||
// because the token stream is in a damaged state. We may not return
|
||||
// a valid identifier.
|
||||
return Tok.isNot(tok::identifier);
|
||||
}
|
||||
}
|
||||
|
||||
// The current token, which is either an identifier or a
|
||||
@ -950,7 +963,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
||||
}
|
||||
|
||||
if (SS.isEmpty())
|
||||
return false;
|
||||
return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon);
|
||||
|
||||
// A C++ scope specifier that isn't followed by a typename.
|
||||
// Push the current token back into the token stream (or revert it if it is
|
||||
@ -971,7 +984,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
||||
|
||||
/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
|
||||
/// annotates C++ scope specifiers and template-ids. This returns
|
||||
/// true if the token was annotated.
|
||||
/// true if the token was annotated or there was an error that could not be
|
||||
/// recovered from.
|
||||
///
|
||||
/// Note that this routine emits an error if you call it with ::new or ::delete
|
||||
/// as the current tokens, so only call it in contexts where these are invalid.
|
||||
|
@ -421,9 +421,12 @@ class Sema : public Action {
|
||||
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
|
||||
|
||||
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
|
||||
return ActOnDeclarator(S, D, false);
|
||||
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
|
||||
}
|
||||
DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition);
|
||||
|
||||
DeclPtrTy HandleDeclarator(Scope *S, Declarator &D,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
bool IsFunctionDefinition);
|
||||
void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
|
||||
Scope *S);
|
||||
void DiagnoseFunctionSpecifiers(Declarator& D);
|
||||
@ -437,6 +440,7 @@ class Sema : public Action {
|
||||
bool &Redeclaration);
|
||||
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
QualType R, NamedDecl* PrevDecl,
|
||||
MultiTemplateParamsArg TemplateParamLists,
|
||||
bool IsFunctionDefinition,
|
||||
bool &Redeclaration);
|
||||
void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
|
||||
@ -693,6 +697,11 @@ class Sema : public Action {
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool ForceRValue = false);
|
||||
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool ForceRValue = false);
|
||||
void AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||
Expr *From, QualType ToType,
|
||||
OverloadCandidateSet& CandidateSet);
|
||||
@ -1137,7 +1146,8 @@ class Sema : public Action {
|
||||
|
||||
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
|
||||
AssociatedNamespaceSet &AssociatedNamespaces,
|
||||
AssociatedClassSet &AssociatedClasses);
|
||||
AssociatedClassSet &AssociatedClasses,
|
||||
bool &GlobalScope);
|
||||
|
||||
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
|
||||
SourceLocation NameLoc,
|
||||
@ -1372,9 +1382,10 @@ class Sema : public Action {
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS,
|
||||
bool isAddressOfOperand);
|
||||
DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
||||
bool TypeDependent, bool ValueDependent,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty,
|
||||
SourceLocation Loc, bool TypeDependent,
|
||||
bool ValueDependent,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
|
||||
llvm::SmallVectorImpl<FieldDecl *> &Path);
|
||||
OwningExprResult
|
||||
@ -1563,6 +1574,7 @@ class Sema : public Action {
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdentLoc,
|
||||
IdentifierInfo *TargetName,
|
||||
OverloadedOperatorKind Op,
|
||||
AttributeList *AttrList,
|
||||
bool IsTypeName);
|
||||
|
||||
@ -1581,17 +1593,36 @@ class Sema : public Action {
|
||||
CXXConstructorDecl *Constructor,
|
||||
QualType DeclInitType,
|
||||
Expr **Exprs, unsigned NumExprs);
|
||||
|
||||
/// MarcDestructorReferenced - Prepare for calling destructor on the
|
||||
/// constructed decl.
|
||||
void MarcDestructorReferenced(SourceLocation Loc, QualType DeclInitType);
|
||||
|
||||
/// DefineImplicitDefaultConstructor - Checks for feasibility of
|
||||
/// defining this constructor as the default constructor.
|
||||
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *Constructor);
|
||||
|
||||
/// DefineImplicitDestructor - Checks for feasibility of
|
||||
/// defining this destructor as the default destructor.
|
||||
void DefineImplicitDestructor(SourceLocation CurrentLocation,
|
||||
CXXDestructorDecl *Destructor);
|
||||
|
||||
/// DefineImplicitCopyConstructor - Checks for feasibility of
|
||||
/// defining this constructor as the copy constructor.
|
||||
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *Constructor,
|
||||
unsigned TypeQuals);
|
||||
|
||||
/// DefineImplicitOverloadedAssign - Checks for feasibility of
|
||||
/// defining implicit this overloaded assignment operator.
|
||||
void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
|
||||
CXXMethodDecl *MethodDecl);
|
||||
|
||||
/// getAssignOperatorMethod - Returns the default copy assignmment operator
|
||||
/// for the class.
|
||||
CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl,
|
||||
CXXRecordDecl *ClassDecl);
|
||||
|
||||
/// MaybeBindToTemporary - If the passed in expression has a record type with
|
||||
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
|
||||
@ -2067,6 +2098,14 @@ class Sema : public Action {
|
||||
AttributeList *Attr,
|
||||
MultiTemplateParamsArg TemplateParameterLists);
|
||||
|
||||
virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D);
|
||||
|
||||
virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D);
|
||||
|
||||
virtual DeclResult
|
||||
ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
unsigned TagSpec,
|
||||
@ -2180,7 +2219,13 @@ class Sema : public Action {
|
||||
/// into a non-deduced context produced a type or value that
|
||||
/// produces a type that does not match the original template
|
||||
/// arguments provided.
|
||||
TDK_NonDeducedMismatch
|
||||
TDK_NonDeducedMismatch,
|
||||
/// \brief When performing template argument deduction for a function
|
||||
/// template, there were too many call arguments.
|
||||
TDK_TooManyArguments,
|
||||
/// \brief When performing template argument deduction for a class
|
||||
/// template, there were too few call arguments.
|
||||
TDK_TooFewArguments
|
||||
};
|
||||
|
||||
/// \brief Provides information about an attempted template argument
|
||||
@ -2260,6 +2305,12 @@ class Sema : public Action {
|
||||
const TemplateArgumentList &TemplateArgs,
|
||||
TemplateDeductionInfo &Info);
|
||||
|
||||
TemplateDeductionResult
|
||||
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
FunctionDecl *&Specialization,
|
||||
TemplateDeductionInfo &Info);
|
||||
|
||||
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
|
||||
llvm::SmallVectorImpl<bool> &Deduced);
|
||||
|
||||
@ -3022,6 +3073,13 @@ class Sema : public Action {
|
||||
// returns true if the cast is invalid
|
||||
bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
|
||||
|
||||
// CheckExtVectorCast - check type constraints for extended vectors.
|
||||
// Since vectors are an extension, there are no C standard reference for this.
|
||||
// We allow casting between vectors and integer datatypes of the same size,
|
||||
// or vectors and the element type of that vector.
|
||||
// returns true if the cast is invalid
|
||||
bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
|
||||
|
||||
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
|
||||
/// \param Method - May be null.
|
||||
/// \param [out] ReturnType - The return type of the send.
|
||||
|
@ -717,6 +717,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
|
||||
if (E->isTypeDependent() || E->isValueDependent())
|
||||
return false;
|
||||
|
||||
E = E->IgnoreParenCasts();
|
||||
|
||||
switch (E->getStmtClass()) {
|
||||
case Stmt::ConditionalOperatorClass: {
|
||||
const ConditionalOperator *C = cast<ConditionalOperator>(E);
|
||||
@ -766,6 +768,25 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
|
||||
return false;
|
||||
}
|
||||
|
||||
case Stmt::CallExprClass: {
|
||||
const CallExpr *CE = cast<CallExpr>(E);
|
||||
if (const ImplicitCastExpr *ICE
|
||||
= dyn_cast<ImplicitCastExpr>(CE->getCallee())) {
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
|
||||
if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>(Context)) {
|
||||
unsigned ArgIndex = FA->getFormatIdx();
|
||||
const Expr *Arg = CE->getArg(ArgIndex - 1);
|
||||
|
||||
return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
|
||||
format_idx, firstDataArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case Stmt::ObjCStringLiteralClass:
|
||||
case Stmt::StringLiteralClass: {
|
||||
const StringLiteral *StrE = NULL;
|
||||
|
@ -319,16 +319,16 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (isa<FunctionDecl>(D) &&
|
||||
AllowOverloadingOfFunction(D, Context)) {
|
||||
// We are pushing the name of a function, which might be an
|
||||
// overloaded name.
|
||||
FunctionDecl *FD = cast<FunctionDecl>(D);
|
||||
} else if ((isa<FunctionDecl>(D) &&
|
||||
AllowOverloadingOfFunction(D, Context)) ||
|
||||
isa<FunctionTemplateDecl>(D)) {
|
||||
// We are pushing the name of a function or function template,
|
||||
// which might be an overloaded name.
|
||||
IdentifierResolver::iterator Redecl
|
||||
= std::find_if(IdResolver.begin(FD->getDeclName()),
|
||||
= std::find_if(IdResolver.begin(D->getDeclName()),
|
||||
IdResolver.end(),
|
||||
std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
|
||||
FD));
|
||||
D));
|
||||
if (Redecl != IdResolver.end() &&
|
||||
S->isDeclScope(DeclPtrTy::make(*Redecl))) {
|
||||
// There is already a declaration of a function on our
|
||||
@ -655,7 +655,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
|
||||
"Cannot merge with an overloaded function declaration");
|
||||
|
||||
// Verify the old decl was also a function.
|
||||
FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
|
||||
FunctionDecl *Old = 0;
|
||||
if (FunctionTemplateDecl *OldFunctionTemplate
|
||||
= dyn_cast<FunctionTemplateDecl>(OldD))
|
||||
Old = OldFunctionTemplate->getTemplatedDecl();
|
||||
else
|
||||
Old = dyn_cast<FunctionDecl>(OldD);
|
||||
if (!Old) {
|
||||
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
||||
<< New->getDeclName();
|
||||
@ -1385,7 +1390,9 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
|
||||
}
|
||||
|
||||
Sema::DeclPtrTy
|
||||
Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) {
|
||||
Sema::HandleDeclarator(Scope *S, Declarator &D,
|
||||
MultiTemplateParamsArg TemplateParamLists,
|
||||
bool IsFunctionDefinition) {
|
||||
DeclarationName Name = GetNameForDeclarator(D);
|
||||
|
||||
// All of these full declarators require an identifier. If it doesn't have
|
||||
@ -1500,9 +1507,15 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) {
|
||||
|
||||
bool Redeclaration = false;
|
||||
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
if (TemplateParamLists.size()) {
|
||||
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
|
||||
} else if (R->isFunctionType()) {
|
||||
New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl,
|
||||
move(TemplateParamLists),
|
||||
IsFunctionDefinition, Redeclaration);
|
||||
} else {
|
||||
New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
|
||||
@ -1799,6 +1812,15 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
} else if (SC == VarDecl::None)
|
||||
SC = VarDecl::Static;
|
||||
}
|
||||
if (SC == VarDecl::Static) {
|
||||
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
|
||||
if (RD->isLocalClass())
|
||||
Diag(D.getIdentifierLoc(),
|
||||
diag::err_static_data_member_not_allowed_in_local_class)
|
||||
<< Name << RD->getDeclName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The variable can not
|
||||
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
@ -1987,6 +2009,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
|
||||
NamedDecl*
|
||||
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
QualType R, NamedDecl* PrevDecl,
|
||||
MultiTemplateParamsArg TemplateParamLists,
|
||||
bool IsFunctionDefinition, bool &Redeclaration) {
|
||||
assert(R.getTypePtr()->isFunctionType());
|
||||
|
||||
@ -2044,6 +2067,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
<< R->getAsFunctionType()->getResultType();
|
||||
D.setInvalidType();
|
||||
}
|
||||
|
||||
// Check that we can declare a template here.
|
||||
if (TemplateParamLists.size() &&
|
||||
CheckTemplateDeclScope(S, TemplateParamLists))
|
||||
return 0;
|
||||
|
||||
bool isVirtualOkay = false;
|
||||
FunctionDecl *NewFD;
|
||||
@ -2143,6 +2171,26 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
// from the semantic context.
|
||||
NewFD->setLexicalDeclContext(CurContext);
|
||||
|
||||
// If there is a template parameter list, then we are dealing with a
|
||||
// template declaration or specialization.
|
||||
FunctionTemplateDecl *FunctionTemplate = 0;
|
||||
if (TemplateParamLists.size()) {
|
||||
// FIXME: member templates!
|
||||
TemplateParameterList *TemplateParams
|
||||
= static_cast<TemplateParameterList *>(*TemplateParamLists.release());
|
||||
|
||||
if (TemplateParams->size() > 0) {
|
||||
// This is a function template
|
||||
FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
|
||||
NewFD->getLocation(),
|
||||
Name, TemplateParams,
|
||||
NewFD);
|
||||
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
|
||||
} else {
|
||||
// FIXME: Handle function template specializations
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [dcl.fct.spec]p5:
|
||||
// The virtual specifier shall only be used in declarations of
|
||||
// nonstatic class member functions that appear within a
|
||||
@ -2261,8 +2309,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
}
|
||||
// Finally, we know we have the right number of parameters, install them.
|
||||
NewFD->setParams(Context, Params.data(), Params.size());
|
||||
|
||||
|
||||
|
||||
// If name lookup finds a previous declaration that is not in the
|
||||
// same scope as the new declaration, this may still be an
|
||||
@ -2342,6 +2388,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
&& !NewFD->isInvalidDecl())
|
||||
RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
|
||||
|
||||
// Set this FunctionDecl's range up to the right paren.
|
||||
NewFD->setLocEnd(D.getSourceRange().getEnd());
|
||||
|
||||
if (FunctionTemplate && NewFD->isInvalidDecl())
|
||||
FunctionTemplate->setInvalidDecl();
|
||||
|
||||
if (FunctionTemplate)
|
||||
return FunctionTemplate;
|
||||
|
||||
return NewFD;
|
||||
}
|
||||
|
||||
@ -2470,7 +2525,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
|
||||
if (MergeFunctionDecl(NewFD, OldDecl))
|
||||
return NewFD->setInvalidDecl();
|
||||
|
||||
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
||||
if (FunctionTemplateDecl *OldTemplateDecl
|
||||
= dyn_cast<FunctionTemplateDecl>(OldDecl))
|
||||
NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
|
||||
else
|
||||
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2733,9 +2792,13 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
|
||||
IK_Default);
|
||||
if (!Constructor)
|
||||
Var->setInvalidDecl();
|
||||
else
|
||||
else {
|
||||
if (!RD->hasTrivialConstructor())
|
||||
InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
|
||||
// FIXME. Must do all that is needed to destroy the object
|
||||
// on scope exit. For now, just mark the destructor as used.
|
||||
MarcDestructorReferenced(Var->getLocation(), InitType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2987,11 +3050,15 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
|
||||
|
||||
Scope *ParentScope = FnBodyScope->getParent();
|
||||
|
||||
DeclPtrTy DP = ActOnDeclarator(ParentScope, D, /*IsFunctionDefinition=*/true);
|
||||
DeclPtrTy DP = HandleDeclarator(ParentScope, D,
|
||||
MultiTemplateParamsArg(*this),
|
||||
/*IsFunctionDefinition=*/true);
|
||||
return ActOnStartOfFunctionDef(FnBodyScope, DP);
|
||||
}
|
||||
|
||||
Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
|
||||
if (!D)
|
||||
return D;
|
||||
FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>());
|
||||
|
||||
CurFunctionNeedsScopeChecking = false;
|
||||
@ -3219,7 +3286,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
||||
CurContext = Context.getTranslationUnitDecl();
|
||||
|
||||
FunctionDecl *FD =
|
||||
dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D, DeclPtrTy()).getAs<Decl>());
|
||||
dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D).getAs<Decl>());
|
||||
FD->setImplicit();
|
||||
|
||||
CurContext = PrevDC;
|
||||
|
@ -915,6 +915,30 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||
D->addAttr(S.Context, ::new (S.Context) DLLExportAttr());
|
||||
}
|
||||
|
||||
static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
|
||||
Sema &S) {
|
||||
// Attribute has 3 arguments.
|
||||
if (Attr.getNumArgs() != 3) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned WGSize[3];
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
Expr *E = static_cast<Expr *>(Attr.getArg(i));
|
||||
llvm::APSInt ArgNum(32);
|
||||
if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
||||
<< "reqd_work_group_size" << E->getSourceRange();
|
||||
return;
|
||||
}
|
||||
WGSize[i] = (unsigned) ArgNum.getZExtValue();
|
||||
}
|
||||
D->addAttr(S.Context,
|
||||
::new (S.Context) ReqdWorkGroupSizeAttr(WGSize[0], WGSize[1],
|
||||
WGSize[2]));
|
||||
}
|
||||
|
||||
static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||
// Attribute has no arguments.
|
||||
if (Attr.getNumArgs() != 1) {
|
||||
@ -1736,6 +1760,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Att
|
||||
case AttributeList::AT_cf_returns_retained:
|
||||
HandleNSReturnsRetainedAttr(D, Attr, S); break;
|
||||
|
||||
case AttributeList::AT_reqd_wg_size:
|
||||
HandleReqdWorkGroupSize(D, Attr, S); break;
|
||||
|
||||
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
|
||||
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
|
||||
case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
|
||||
|
@ -1625,7 +1625,8 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
|
||||
Conv = Conversions->function_begin(),
|
||||
ConvEnd = Conversions->function_end();
|
||||
Conv != ConvEnd; ++Conv) {
|
||||
if (*Conv == Conversion->getPreviousDeclaration()) {
|
||||
if (*Conv
|
||||
== cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
|
||||
*Conv = Conversion;
|
||||
return DeclPtrTy::make(Conversion);
|
||||
}
|
||||
@ -1784,18 +1785,24 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdentLoc,
|
||||
IdentifierInfo *TargetName,
|
||||
OverloadedOperatorKind Op,
|
||||
AttributeList *AttrList,
|
||||
bool IsTypeName) {
|
||||
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
|
||||
assert(TargetName && "Invalid TargetName.");
|
||||
assert((TargetName || Op) && "Invalid TargetName.");
|
||||
assert(IdentLoc.isValid() && "Invalid TargetName location.");
|
||||
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
|
||||
|
||||
UsingDecl *UsingAlias = 0;
|
||||
|
||||
DeclarationName Name;
|
||||
if (TargetName)
|
||||
Name = TargetName;
|
||||
else
|
||||
Name = Context.DeclarationNames.getCXXOperatorName(Op);
|
||||
|
||||
// Lookup target name.
|
||||
LookupResult R = LookupParsedName(S, &SS, TargetName,
|
||||
LookupOrdinaryName, false);
|
||||
LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false);
|
||||
|
||||
if (NamedDecl *NS = R) {
|
||||
if (IsTypeName && !isa<TypeDecl>(NS)) {
|
||||
@ -1890,10 +1897,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
|
||||
if (!BaseClassDecl->hasTrivialConstructor()) {
|
||||
if (CXXConstructorDecl *BaseCtor =
|
||||
BaseClassDecl->getDefaultConstructor(Context)) {
|
||||
if (BaseCtor->isImplicit() && !BaseCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
|
||||
}
|
||||
BaseClassDecl->getDefaultConstructor(Context))
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1
|
||||
@ -1913,12 +1918,10 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
if (!FieldClassDecl->hasTrivialConstructor())
|
||||
if (!FieldClassDecl->hasTrivialConstructor()) {
|
||||
if (CXXConstructorDecl *FieldCtor =
|
||||
FieldClassDecl->getDefaultConstructor(Context)) {
|
||||
if (FieldCtor->isImplicit() && !FieldCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
|
||||
}
|
||||
FieldClassDecl->getDefaultConstructor(Context))
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 <<
|
||||
@ -1928,6 +1931,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (FieldType->isReferenceType()) {
|
||||
Diag(CurrentLocation, diag::err_unintialized_member)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
|
||||
@ -1942,7 +1946,147 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
Constructor->setUsed();
|
||||
Constructor->setUsed();
|
||||
else
|
||||
Constructor->setInvalidDecl();
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
|
||||
CXXDestructorDecl *Destructor) {
|
||||
assert((Destructor->isImplicit() && !Destructor->isUsed()) &&
|
||||
"DefineImplicitDestructor - call it for implicit default dtor");
|
||||
|
||||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(Destructor->getDeclContext());
|
||||
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
|
||||
// C++ [class.dtor] p5
|
||||
// Before the implicitly-declared default destructor for a class is
|
||||
// implicitly defined, all the implicitly-declared default destructors
|
||||
// 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 (!BaseClassDecl->hasTrivialDestructor()) {
|
||||
if (CXXDestructorDecl *BaseDtor =
|
||||
const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context)))
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseDtor);
|
||||
else
|
||||
assert(false &&
|
||||
"DefineImplicitDestructor - missing dtor in a base class");
|
||||
}
|
||||
}
|
||||
|
||||
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 (!FieldClassDecl->hasTrivialDestructor()) {
|
||||
if (CXXDestructorDecl *FieldDtor =
|
||||
const_cast<CXXDestructorDecl*>(
|
||||
FieldClassDecl->getDestructor(Context)))
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldDtor);
|
||||
else
|
||||
assert(false &&
|
||||
"DefineImplicitDestructor - missing dtor in class of a data member");
|
||||
}
|
||||
}
|
||||
}
|
||||
Destructor->setUsed();
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
|
||||
CXXMethodDecl *MethodDecl) {
|
||||
assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
|
||||
MethodDecl->getOverloadedOperator() == OO_Equal &&
|
||||
!MethodDecl->isUsed()) &&
|
||||
"DefineImplicitOverloadedAssign - call it for implicit assignment op");
|
||||
|
||||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
|
||||
assert(ClassDecl && "DefineImplicitOverloadedAssign - invalid constructor");
|
||||
|
||||
// C++[class.copy] p12
|
||||
// Before the implicitly-declared copy assignment operator for a class is
|
||||
// implicitly defined, all implicitly-declared copy assignment operators
|
||||
// for its direct base classes and its nonstatic data members shall have
|
||||
// been implicitly defined.
|
||||
bool err = false;
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
|
||||
Base != ClassDecl->bases_end(); ++Base) {
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
|
||||
if (CXXMethodDecl *BaseAssignOpMethod =
|
||||
getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl))
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
|
||||
}
|
||||
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 (CXXMethodDecl *FieldAssignOpMethod =
|
||||
getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl))
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
|
||||
}
|
||||
else if (FieldType->isReferenceType()) {
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getNameAsCString();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_first_required_here);
|
||||
err = true;
|
||||
}
|
||||
else if (FieldType.isConstQualified()) {
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getNameAsCString();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_first_required_here);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
MethodDecl->setUsed();
|
||||
}
|
||||
|
||||
CXXMethodDecl *
|
||||
Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl,
|
||||
CXXRecordDecl *ClassDecl) {
|
||||
QualType LHSType = Context.getTypeDeclType(ClassDecl);
|
||||
QualType RHSType(LHSType);
|
||||
// If class's assignment operator argument is const/volatile qualified,
|
||||
// look for operator = (const/volatile B&). Otherwise, look for
|
||||
// operator = (B&).
|
||||
if (ParmDecl->getType().isConstQualified())
|
||||
RHSType.addConst();
|
||||
if (ParmDecl->getType().isVolatileQualified())
|
||||
RHSType.addVolatile();
|
||||
ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
|
||||
LHSType,
|
||||
SourceLocation()));
|
||||
ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
|
||||
RHSType,
|
||||
SourceLocation()));
|
||||
Expr *Args[2] = { &*LHS, &*RHS };
|
||||
OverloadCandidateSet CandidateSet;
|
||||
AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
|
||||
CandidateSet);
|
||||
OverloadCandidateSet::iterator Best;
|
||||
if (BestViableFunction(CandidateSet,
|
||||
ClassDecl->getLocation(), Best) == OR_Success)
|
||||
return cast<CXXMethodDecl>(Best->Function);
|
||||
assert(false &&
|
||||
"getAssignOperatorMethod - copy assignment operator method not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
@ -1956,6 +2100,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
|
||||
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
|
||||
// C++ [class.copy] p209
|
||||
// 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
|
||||
@ -1966,8 +2111,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
|
||||
if (CXXConstructorDecl *BaseCopyCtor =
|
||||
BaseClassDecl->getCopyConstructor(Context, TypeQuals))
|
||||
if (BaseCopyCtor->isImplicit() && !BaseCopyCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
|
||||
}
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
|
||||
Field != ClassDecl->field_end(Context);
|
||||
@ -1980,8 +2124,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
if (CXXConstructorDecl *FieldCopyCtor =
|
||||
FieldClassDecl->getCopyConstructor(Context, TypeQuals))
|
||||
if (FieldCopyCtor->isImplicit() && !FieldCopyCtor->isUsed())
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
|
||||
}
|
||||
}
|
||||
CopyConstructor->setUsed();
|
||||
@ -1997,6 +2140,16 @@ void Sema::InitializeVarWithConstructor(VarDecl *VD,
|
||||
VD->setInit(Context, Temp);
|
||||
}
|
||||
|
||||
void Sema::MarcDestructorReferenced(SourceLocation Loc, QualType DeclInitType)
|
||||
{
|
||||
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
|
||||
DeclInitType->getAsRecordType()->getDecl());
|
||||
if (!ClassDecl->hasTrivialDestructor())
|
||||
if (CXXDestructorDecl *Destructor =
|
||||
const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
|
||||
MarkDeclarationReferenced(Loc, Destructor);
|
||||
}
|
||||
|
||||
/// AddCXXDirectInitializerToDecl - This action is called immediately after
|
||||
/// ActOnDeclarator, when a C++ direct initializer is present.
|
||||
/// e.g: "int x(1);"
|
||||
@ -2063,6 +2216,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
|
||||
VDecl->setCXXDirectInitializer(true);
|
||||
InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
|
||||
(Expr**)Exprs.release(), NumExprs);
|
||||
// FIXME. Must do all that is needed to destroy the object
|
||||
// on scope exit. For now, just mark the destructor as used.
|
||||
MarcDestructorReferenced(VDecl->getLocation(), DeclInitType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -2590,7 +2746,8 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
|
||||
ParamEnd = FnDecl->param_end();
|
||||
Param != ParamEnd; ++Param) {
|
||||
QualType ParamType = (*Param)->getType().getNonReferenceType();
|
||||
if (ParamType->isRecordType() || ParamType->isEnumeralType()) {
|
||||
if (ParamType->isDependentType() || ParamType->isRecordType() ||
|
||||
ParamType->isEnumeralType()) {
|
||||
ClassOrEnumParam = true;
|
||||
break;
|
||||
}
|
||||
|
@ -623,17 +623,42 @@ Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
/// BuildDeclRefExpr - Build either a DeclRefExpr or a
|
||||
/// QualifiedDeclRefExpr based on whether or not SS is a
|
||||
/// nested-name-specifier.
|
||||
DeclRefExpr *
|
||||
Sema::OwningExprResult
|
||||
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
||||
bool TypeDependent, bool ValueDependent,
|
||||
const CXXScopeSpec *SS) {
|
||||
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
|
||||
Diag(Loc,
|
||||
diag::err_auto_variable_cannot_appear_in_own_initializer)
|
||||
<< D->getDeclName();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
||||
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
|
||||
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
|
||||
Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
|
||||
<< D->getIdentifier() << FD->getDeclName();
|
||||
Diag(D->getLocation(), diag::note_local_variable_declared_here)
|
||||
<< D->getIdentifier();
|
||||
return ExprError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarkDeclarationReferenced(Loc, D);
|
||||
|
||||
Expr *E;
|
||||
if (SS && !SS->isEmpty()) {
|
||||
return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
|
||||
ValueDependent, SS->getRange(),
|
||||
E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
|
||||
ValueDependent, SS->getRange(),
|
||||
static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
|
||||
} else
|
||||
return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
|
||||
E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
|
||||
|
||||
return Owned(E);
|
||||
}
|
||||
|
||||
/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
|
||||
@ -968,7 +993,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
// The pointer is type- and value-dependent if it points into something
|
||||
// dependent.
|
||||
bool Dependent = DC->isDependentContext();
|
||||
return Owned(BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS));
|
||||
return BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1061,11 +1086,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
|
||||
// Make the DeclRefExpr or BlockDeclRefExpr for the decl.
|
||||
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
|
||||
return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
|
||||
false, false, SS));
|
||||
return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
|
||||
false, false, SS);
|
||||
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
|
||||
return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
|
||||
false, false, SS));
|
||||
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
|
||||
false, false, SS);
|
||||
ValueDecl *VD = cast<ValueDecl>(D);
|
||||
|
||||
// Check whether this declaration can be used. Note that we suppress
|
||||
@ -1113,7 +1138,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
QualType NoProtoType = T;
|
||||
if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
|
||||
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
|
||||
return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
|
||||
return BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1194,8 +1219,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
}
|
||||
}
|
||||
|
||||
return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
|
||||
TypeDependent, ValueDependent, SS));
|
||||
return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
|
||||
TypeDependent, ValueDependent, SS);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
|
||||
@ -1886,7 +1911,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
|
||||
|
||||
// This flag determines whether or not CompName has an 's' char prefix,
|
||||
// indicating that it is a string of hex values to be used as vector indices.
|
||||
bool HexSwizzle = *compStr == 's';
|
||||
bool HexSwizzle = *compStr == 's' || *compStr == 'S';
|
||||
|
||||
// Check that we've found one of the special components, or that the component
|
||||
// names must come from the same set.
|
||||
@ -2586,11 +2611,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
|
||||
CommaLocs, RParenLoc));
|
||||
|
||||
// Determine whether this is a call to a member function.
|
||||
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
|
||||
if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
|
||||
isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
|
||||
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) {
|
||||
NamedDecl *MemDecl = MemExpr->getMemberDecl();
|
||||
if (isa<OverloadedFunctionDecl>(MemDecl) ||
|
||||
isa<CXXMethodDecl>(MemDecl) ||
|
||||
(isa<FunctionTemplateDecl>(MemDecl) &&
|
||||
isa<CXXMethodDecl>(
|
||||
cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
|
||||
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
|
||||
CommaLocs, RParenLoc));
|
||||
}
|
||||
}
|
||||
|
||||
// If we're directly calling a function, get the appropriate declaration.
|
||||
@ -2626,13 +2656,19 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
|
||||
}
|
||||
|
||||
OverloadedFunctionDecl *Ovl = 0;
|
||||
FunctionTemplateDecl *FunctionTemplate = 0;
|
||||
if (DRExpr) {
|
||||
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
|
||||
if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DRExpr->getDecl())))
|
||||
FDecl = FunctionTemplate->getTemplatedDecl();
|
||||
else
|
||||
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
|
||||
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
|
||||
NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
|
||||
}
|
||||
|
||||
if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
|
||||
if (Ovl || FunctionTemplate ||
|
||||
(getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
|
||||
// We don't perform ADL for implicit declarations of builtins.
|
||||
if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
|
||||
ADL = false;
|
||||
@ -2641,7 +2677,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
|
||||
if (!getLangOptions().CPlusPlus)
|
||||
ADL = false;
|
||||
|
||||
if (Ovl || ADL) {
|
||||
if (Ovl || FunctionTemplate || ADL) {
|
||||
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
|
||||
UnqualifiedName, LParenLoc, Args,
|
||||
NumArgs, CommaLocs, RParenLoc, ADL);
|
||||
@ -2846,12 +2882,15 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
|
||||
return Diag(castExpr->getLocStart(),
|
||||
diag::err_typecheck_expect_scalar_operand)
|
||||
<< castExpr->getType() << castExpr->getSourceRange();
|
||||
} else if (castExpr->getType()->isVectorType()) {
|
||||
if (CheckVectorCast(TyR, castExpr->getType(), castType))
|
||||
} else if (castType->isExtVectorType()) {
|
||||
if (CheckExtVectorCast(TyR, castType, castExpr->getType()))
|
||||
return true;
|
||||
} else if (castType->isVectorType()) {
|
||||
if (CheckVectorCast(TyR, castType, castExpr->getType()))
|
||||
return true;
|
||||
} else if (castExpr->getType()->isVectorType()) {
|
||||
if (CheckVectorCast(TyR, castExpr->getType(), castType))
|
||||
return true;
|
||||
} else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) {
|
||||
return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
|
||||
} else if (!castType->isArithmeticType()) {
|
||||
@ -2889,6 +2928,35 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
|
||||
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
|
||||
|
||||
// If SrcTy is also an ExtVectorType, the types must be identical unless
|
||||
// lax vector conversions is enabled.
|
||||
if (SrcTy->isExtVectorType()) {
|
||||
if (getLangOptions().LaxVectorConversions &&
|
||||
Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy))
|
||||
return false;
|
||||
if (DestTy != SrcTy)
|
||||
return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
|
||||
<< DestTy << SrcTy << R;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If SrcTy is a VectorType, then only the total size must match.
|
||||
if (SrcTy->isVectorType()) {
|
||||
if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy))
|
||||
return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
|
||||
<< DestTy << SrcTy << R;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All scalar -> ext vector "c-style" casts are legal; the appropriate
|
||||
// conversion will take place first from scalar to elt type, and then
|
||||
// splat from elt type to vector.
|
||||
return false;
|
||||
}
|
||||
|
||||
Action::OwningExprResult
|
||||
Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
||||
SourceLocation RParenLoc, ExprArg Op) {
|
||||
@ -5525,18 +5593,27 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
||||
if (!Constructor->isUsed())
|
||||
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
|
||||
}
|
||||
// FIXME: more checking for other implicits go here.
|
||||
else
|
||||
Constructor->setUsed(true);
|
||||
}
|
||||
|
||||
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
|
||||
if (Destructor->isImplicit() && !Destructor->isUsed())
|
||||
DefineImplicitDestructor(Loc, Destructor);
|
||||
|
||||
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
|
||||
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
|
||||
MethodDecl->getOverloadedOperator() == OO_Equal) {
|
||||
if (!MethodDecl->isUsed())
|
||||
DefineImplicitOverloadedAssign(Loc, MethodDecl);
|
||||
}
|
||||
}
|
||||
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
||||
// Implicit instantiation of function templates
|
||||
// Implicit instantiation of function templates and member functions of
|
||||
// class templates.
|
||||
if (!Function->getBody(Context)) {
|
||||
if (Function->getInstantiatedFromMemberFunction())
|
||||
// FIXME: distinguish between implicit instantiations of function
|
||||
// templates and explicit specializations (the latter don't get
|
||||
// instantiated, naturally).
|
||||
if (Function->getInstantiatedFromMemberFunction() ||
|
||||
Function->getPrimaryTemplate())
|
||||
PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
|
||||
|
||||
// FIXME: check for function template specializations.
|
||||
}
|
||||
|
||||
|
||||
|
@ -771,7 +771,7 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
|
||||
Diag(ED->getLocation(), diag::err_type_defined_in_condition);
|
||||
}
|
||||
|
||||
DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy());
|
||||
DeclPtrTy Dcl = ActOnDeclarator(S, D);
|
||||
if (!Dcl)
|
||||
return ExprError();
|
||||
AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false);
|
||||
@ -1567,7 +1567,7 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
|
||||
CXXTemporary *Temp = CXXTemporary::Create(Context,
|
||||
RD->getDestructor(Context));
|
||||
ExprTemporaries.push_back(Temp);
|
||||
|
||||
MarcDestructorReferenced(E->getExprLoc(), E->getType());
|
||||
// FIXME: Add the temporary to the temporaries vector.
|
||||
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
|
||||
}
|
||||
|
@ -200,10 +200,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
|
||||
|
||||
if (InitEntity)
|
||||
return Diag(InitLoc, diag::err_cannot_initialize_decl)
|
||||
<< InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
|
||||
<< Init->getType() << Init->getSourceRange();
|
||||
else
|
||||
return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
|
||||
<< InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
|
||||
<< Init->getType() << Init->getSourceRange();
|
||||
return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
|
||||
<< DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
|
||||
<< Init->getType() << Init->getSourceRange();
|
||||
}
|
||||
@ -211,7 +210,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
|
||||
// C99 6.7.8p16.
|
||||
if (DeclType->isArrayType())
|
||||
return Diag(Init->getLocStart(), diag::err_array_init_list_required)
|
||||
<< Init->getSourceRange();
|
||||
<< Init->getSourceRange();
|
||||
|
||||
return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
|
||||
}
|
||||
|
@ -125,21 +125,32 @@ MaybeConstructOverloadSet(ASTContext &Context,
|
||||
assert(!isa<OverloadedFunctionDecl>(*I) &&
|
||||
"Cannot have an overloaded function");
|
||||
|
||||
if (isa<FunctionDecl>(*I)) {
|
||||
if ((*I)->isFunctionOrFunctionTemplate()) {
|
||||
// If we found a function, there might be more functions. If
|
||||
// so, collect them into an overload set.
|
||||
DeclIterator Last = I;
|
||||
OverloadedFunctionDecl *Ovl = 0;
|
||||
for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
|
||||
for (++Last;
|
||||
Last != IEnd && (*Last)->isFunctionOrFunctionTemplate();
|
||||
++Last) {
|
||||
if (!Ovl) {
|
||||
// FIXME: We leak this overload set. Eventually, we want to stop
|
||||
// building the declarations for these overload sets, so there will be
|
||||
// nothing to leak.
|
||||
Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(),
|
||||
(*I)->getDeclName());
|
||||
Ovl->addOverload(cast<FunctionDecl>(*I));
|
||||
NamedDecl *ND = (*I)->getUnderlyingDecl();
|
||||
if (isa<FunctionDecl>(ND))
|
||||
Ovl->addOverload(cast<FunctionDecl>(ND));
|
||||
else
|
||||
Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
|
||||
}
|
||||
Ovl->addOverload(cast<FunctionDecl>(*Last));
|
||||
|
||||
NamedDecl *ND = (*Last)->getUnderlyingDecl();
|
||||
if (isa<FunctionDecl>(ND))
|
||||
Ovl->addOverload(cast<FunctionDecl>(ND));
|
||||
else
|
||||
Ovl->addOverload(cast<FunctionTemplateDecl>(ND));
|
||||
}
|
||||
|
||||
// If we had more than one function, we built an overload
|
||||
@ -202,11 +213,12 @@ MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) {
|
||||
break;
|
||||
|
||||
case LResult::Found: {
|
||||
NamedDecl *ND = I->getAsDecl();
|
||||
NamedDecl *ND = I->getAsDecl()->getUnderlyingDecl();
|
||||
|
||||
if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
|
||||
TagFound = Context.getCanonicalDecl(TD);
|
||||
TagNames += FoundDecls.insert(TagFound)? 1 : 0;
|
||||
} else if (isa<FunctionDecl>(ND))
|
||||
} else if (ND->isFunctionOrFunctionTemplate())
|
||||
Functions += FoundDecls.insert(ND)? 1 : 0;
|
||||
else
|
||||
FoundDecls.insert(ND);
|
||||
@ -313,10 +325,9 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
|
||||
|
||||
Sema::LookupResult
|
||||
Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) {
|
||||
if (ObjCCompatibleAliasDecl *Alias
|
||||
= dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
|
||||
D = Alias->getClassInterface();
|
||||
|
||||
if (D)
|
||||
D = D->getUnderlyingDecl();
|
||||
|
||||
LookupResult Result;
|
||||
Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
|
||||
OverloadedDeclSingleDecl : SingleDecl;
|
||||
@ -334,10 +345,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
|
||||
LookupResult Result;
|
||||
Result.Context = &Context;
|
||||
|
||||
if (F != L && isa<FunctionDecl>(*F)) {
|
||||
if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
|
||||
IdentifierResolver::iterator Next = F;
|
||||
++Next;
|
||||
if (Next != L && isa<FunctionDecl>(*Next)) {
|
||||
if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
|
||||
Result.StoredKind = OverloadedDeclFromIdResolver;
|
||||
Result.First = F.getAsOpaqueValue();
|
||||
Result.Last = L.getAsOpaqueValue();
|
||||
@ -345,11 +356,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
|
||||
}
|
||||
}
|
||||
|
||||
Decl *D = *F;
|
||||
if (ObjCCompatibleAliasDecl *Alias
|
||||
= dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
|
||||
D = Alias->getClassInterface();
|
||||
|
||||
NamedDecl *D = *F;
|
||||
if (D)
|
||||
D = D->getUnderlyingDecl();
|
||||
|
||||
Result.StoredKind = SingleDecl;
|
||||
Result.First = reinterpret_cast<uintptr_t>(D);
|
||||
Result.Last = 0;
|
||||
@ -363,10 +373,10 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
|
||||
LookupResult Result;
|
||||
Result.Context = &Context;
|
||||
|
||||
if (F != L && isa<FunctionDecl>(*F)) {
|
||||
if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
|
||||
DeclContext::lookup_iterator Next = F;
|
||||
++Next;
|
||||
if (Next != L && isa<FunctionDecl>(*Next)) {
|
||||
if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
|
||||
Result.StoredKind = OverloadedDeclFromDeclContext;
|
||||
Result.First = reinterpret_cast<uintptr_t>(F);
|
||||
Result.Last = reinterpret_cast<uintptr_t>(L);
|
||||
@ -374,10 +384,9 @@ Sema::LookupResult::CreateLookupResult(ASTContext &Context,
|
||||
}
|
||||
}
|
||||
|
||||
Decl *D = *F;
|
||||
if (ObjCCompatibleAliasDecl *Alias
|
||||
= dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
|
||||
D = Alias->getClassInterface();
|
||||
NamedDecl *D = *F;
|
||||
if (D)
|
||||
D = D->getUnderlyingDecl();
|
||||
|
||||
Result.StoredKind = SingleDecl;
|
||||
Result.First = reinterpret_cast<uintptr_t>(D);
|
||||
@ -1083,7 +1092,7 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
|
||||
// Lookup in a base class succeeded; return these results.
|
||||
|
||||
// If we found a function declaration, return an overload set.
|
||||
if (isa<FunctionDecl>(*Paths.front().Decls.first))
|
||||
if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate())
|
||||
return LookupResult::CreateLookupResult(Context,
|
||||
Paths.front().Decls.first, Paths.front().Decls.second);
|
||||
|
||||
@ -1239,7 +1248,8 @@ static void
|
||||
addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
|
||||
ASTContext &Context,
|
||||
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
|
||||
Sema::AssociatedClassSet &AssociatedClasses) {
|
||||
Sema::AssociatedClassSet &AssociatedClasses,
|
||||
bool &GlobalScope) {
|
||||
// C++ [basic.lookup.koenig]p2:
|
||||
// [...]
|
||||
// -- If T is a class type (including unions), its associated
|
||||
@ -1252,13 +1262,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
|
||||
DeclContext *Ctx = Class->getDeclContext();
|
||||
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
|
||||
AssociatedClasses.insert(EnclosingClass);
|
||||
|
||||
// Add the associated namespace for this class.
|
||||
while (Ctx->isRecord())
|
||||
Ctx = Ctx->getParent();
|
||||
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
|
||||
AssociatedNamespaces.insert(EnclosingNamespace);
|
||||
|
||||
else if (Ctx->isTranslationUnit())
|
||||
GlobalScope = true;
|
||||
|
||||
// Add the class itself. If we've already seen this class, we don't
|
||||
// need to visit base classes.
|
||||
if (!AssociatedClasses.insert(Class))
|
||||
@ -1288,6 +1299,8 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
|
||||
BaseCtx = BaseCtx->getParent();
|
||||
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
|
||||
AssociatedNamespaces.insert(EnclosingNamespace);
|
||||
else if (BaseCtx->isTranslationUnit())
|
||||
GlobalScope = true;
|
||||
|
||||
// Make sure we visit the bases of this base class.
|
||||
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
|
||||
@ -1304,7 +1317,8 @@ static void
|
||||
addAssociatedClassesAndNamespaces(QualType T,
|
||||
ASTContext &Context,
|
||||
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
|
||||
Sema::AssociatedClassSet &AssociatedClasses) {
|
||||
Sema::AssociatedClassSet &AssociatedClasses,
|
||||
bool &GlobalScope) {
|
||||
// C++ [basic.lookup.koenig]p2:
|
||||
//
|
||||
// For each argument type T in the function call, there is a set
|
||||
@ -1346,7 +1360,8 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
= dyn_cast<CXXRecordDecl>(ClassType->getDecl())) {
|
||||
addAssociatedClassesAndNamespaces(ClassDecl, Context,
|
||||
AssociatedNamespaces,
|
||||
AssociatedClasses);
|
||||
AssociatedClasses,
|
||||
GlobalScope);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1366,6 +1381,8 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
Ctx = Ctx->getParent();
|
||||
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
|
||||
AssociatedNamespaces.insert(EnclosingNamespace);
|
||||
else if (Ctx->isTranslationUnit())
|
||||
GlobalScope = true;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1377,7 +1394,8 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
// Return type
|
||||
addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
|
||||
Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
|
||||
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType);
|
||||
if (!Proto)
|
||||
@ -1388,7 +1406,8 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
ArgEnd = Proto->arg_type_end();
|
||||
Arg != ArgEnd; ++Arg)
|
||||
addAssociatedClassesAndNamespaces(*Arg, Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1406,13 +1425,15 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
// Handle the type that the pointer to member points to.
|
||||
addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
|
||||
Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
|
||||
// Handle the class type into which this points.
|
||||
if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
|
||||
addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
|
||||
Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1431,7 +1452,8 @@ addAssociatedClassesAndNamespaces(QualType T,
|
||||
void
|
||||
Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
|
||||
AssociatedNamespaceSet &AssociatedNamespaces,
|
||||
AssociatedClassSet &AssociatedClasses) {
|
||||
AssociatedClassSet &AssociatedClasses,
|
||||
bool &GlobalScope) {
|
||||
AssociatedNamespaces.clear();
|
||||
AssociatedClasses.clear();
|
||||
|
||||
@ -1447,7 +1469,8 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
|
||||
|
||||
if (Arg->getType() != Context.OverloadTy) {
|
||||
addAssociatedClassesAndNamespaces(Arg->getType(), Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1475,7 +1498,9 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
|
||||
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
FunctionDecl *FDecl = cast<FunctionDecl>(*Func);
|
||||
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*Func);
|
||||
if (!FDecl)
|
||||
FDecl = cast<FunctionTemplateDecl>(*Func)->getTemplatedDecl();
|
||||
|
||||
// Add the namespace in which this function was defined. Note
|
||||
// that, if this is a member function, we do *not* consider the
|
||||
@ -1483,11 +1508,14 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
|
||||
DeclContext *Ctx = FDecl->getDeclContext();
|
||||
if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
|
||||
AssociatedNamespaces.insert(EnclosingNamespace);
|
||||
else if (Ctx->isTranslationUnit())
|
||||
GlobalScope = true;
|
||||
|
||||
// Add the classes and namespaces associated with the parameter
|
||||
// types and return type of this function.
|
||||
addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1589,8 +1617,10 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
|
||||
// arguments we have.
|
||||
AssociatedNamespaceSet AssociatedNamespaces;
|
||||
AssociatedClassSet AssociatedClasses;
|
||||
bool GlobalScope = false;
|
||||
FindAssociatedClassesAndNamespaces(Args, NumArgs,
|
||||
AssociatedNamespaces, AssociatedClasses);
|
||||
AssociatedNamespaces, AssociatedClasses,
|
||||
GlobalScope);
|
||||
|
||||
// C++ [basic.lookup.argdep]p3:
|
||||
// Let X be the lookup set produced by unqualified lookup (3.4.1)
|
||||
@ -1626,4 +1656,17 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
|
||||
Functions.insert(Func);
|
||||
}
|
||||
}
|
||||
|
||||
if (GlobalScope) {
|
||||
DeclContext::lookup_iterator I, E;
|
||||
for (llvm::tie(I, E)
|
||||
= Context.getTranslationUnitDecl()->lookup(Context, Name);
|
||||
I != E; ++I) {
|
||||
FunctionDecl *Func = dyn_cast<FunctionDecl>(*I);
|
||||
if (!Func)
|
||||
break;
|
||||
|
||||
Functions.insert(Func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +300,18 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
|
||||
|
||||
// This function overloads every function in the overload set.
|
||||
return true;
|
||||
} else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
|
||||
} else if (FunctionTemplateDecl *Old = dyn_cast<FunctionTemplateDecl>(OldD))
|
||||
return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl);
|
||||
else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
|
||||
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
|
||||
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
|
||||
|
||||
// C++ [temp.fct]p2:
|
||||
// A function template can be overloaded with other function templates
|
||||
// and with normal (non-template) functions.
|
||||
if ((OldTemplate == 0) != (NewTemplate == 0))
|
||||
return true;
|
||||
|
||||
// Is the function New an overload of the function Old?
|
||||
QualType OldQType = Context.getCanonicalType(Old->getType());
|
||||
QualType NewQType = Context.getCanonicalType(New->getType());
|
||||
@ -315,8 +326,8 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
|
||||
isa<FunctionNoProtoType>(NewQType.getTypePtr()))
|
||||
return false;
|
||||
|
||||
FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType.getTypePtr());
|
||||
FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType.getTypePtr());
|
||||
FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
|
||||
FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
|
||||
|
||||
// The signature of a function includes the types of its
|
||||
// parameters (C++ 1.3.10), which includes the presence or absence
|
||||
@ -328,6 +339,22 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
|
||||
NewType->arg_type_begin())))
|
||||
return true;
|
||||
|
||||
// C++ [temp.over.link]p4:
|
||||
// The signature of a function template consists of its function
|
||||
// signature, its return type and its template parameter list. The names
|
||||
// of the template parameters are significant only for establishing the
|
||||
// relationship between the template parameters and the rest of the
|
||||
// signature.
|
||||
//
|
||||
// We check the return type and template parameter lists for function
|
||||
// templates first; the remaining checks follow.
|
||||
if (NewTemplate &&
|
||||
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
|
||||
OldTemplate->getTemplateParameters(),
|
||||
false, false, SourceLocation()) ||
|
||||
OldType->getResultType() != NewType->getResultType()))
|
||||
return true;
|
||||
|
||||
// If the function is a class member, its signature includes the
|
||||
// cv-qualifiers (if any) on the function itself.
|
||||
//
|
||||
@ -2048,7 +2075,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||
assert(Proto && "Functions without a prototype cannot be overloaded");
|
||||
assert(!isa<CXXConversionDecl>(Function) &&
|
||||
"Use AddConversionCandidate for conversion functions");
|
||||
|
||||
assert(!Function->getDescribedFunctionTemplate() &&
|
||||
"Use AddTemplateOverloadCandidate for function templates");
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
|
||||
if (!isa<CXXConstructorDecl>(Method)) {
|
||||
// If we get here, it's because we're calling a member function
|
||||
@ -2233,6 +2262,42 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Add a C++ function template as a candidate in the candidate set,
|
||||
/// using template argument deduction to produce an appropriate function
|
||||
/// template specialization.
|
||||
void
|
||||
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions,
|
||||
bool ForceRValue) {
|
||||
// C++ [over.match.funcs]p7:
|
||||
// In each case where a candidate is a function template, candidate
|
||||
// function template specializations are generated using template argument
|
||||
// deduction (14.8.3, 14.8.2). Those candidates are then handled as
|
||||
// candidate functions in the usual way.113) A given name can refer to one
|
||||
// or more function templates and also to a set of overloaded non-template
|
||||
// functions. In such a case, the candidate functions generated from each
|
||||
// function template are combined with the set of non-template candidate
|
||||
// functions.
|
||||
TemplateDeductionInfo Info(Context);
|
||||
FunctionDecl *Specialization = 0;
|
||||
if (TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(FunctionTemplate, Args, NumArgs,
|
||||
Specialization, Info)) {
|
||||
// FIXME: Record what happened with template argument deduction, so
|
||||
// that we can give the user a beautiful diagnostic.
|
||||
(void)Result;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the function template specialization produced by template argument
|
||||
// deduction as a candidate.
|
||||
assert(Specialization && "Missing function template specialization?");
|
||||
AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
|
||||
SuppressUserConversions, ForceRValue);
|
||||
}
|
||||
|
||||
/// AddConversionCandidate - Add a C++ conversion function as a
|
||||
/// candidate in the candidate set (C++ [over.match.conv],
|
||||
/// C++ [over.match.copy]). From is the expression we're converting from,
|
||||
@ -3653,8 +3718,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
||||
} else if (IsMember)
|
||||
continue;
|
||||
|
||||
if (FunctionType == Context.getCanonicalType((*Fun)->getType()))
|
||||
return *Fun;
|
||||
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
|
||||
if (FunctionType == Context.getCanonicalType(FunDecl->getType()))
|
||||
return FunDecl;
|
||||
} else {
|
||||
unsigned DiagID
|
||||
= PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning,
|
||||
"Clang does not yet support templated conversion functions");
|
||||
Diag(From->getLocStart(), DiagID);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -3699,10 +3771,18 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
|
||||
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
|
||||
FuncEnd = Ovl->function_end();
|
||||
Func != FuncEnd; ++Func) {
|
||||
AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
|
||||
DeclContext *Ctx = 0;
|
||||
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
|
||||
AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
|
||||
Ctx = FunDecl->getDeclContext();
|
||||
} else {
|
||||
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
|
||||
AddTemplateOverloadCandidate(FunTmpl, Args, NumArgs, CandidateSet);
|
||||
Ctx = FunTmpl->getDeclContext();
|
||||
}
|
||||
|
||||
if ((*Func)->getDeclContext()->isRecord() ||
|
||||
(*Func)->getDeclContext()->isFunctionOrMethod())
|
||||
|
||||
if (Ctx->isRecord() || Ctx->isFunctionOrMethod())
|
||||
ArgumentDependentLookup = false;
|
||||
}
|
||||
} else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
|
||||
@ -3711,7 +3791,13 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
|
||||
if (Func->getDeclContext()->isRecord() ||
|
||||
Func->getDeclContext()->isFunctionOrMethod())
|
||||
ArgumentDependentLookup = false;
|
||||
}
|
||||
} else if (FunctionTemplateDecl *FuncTemplate
|
||||
= dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
|
||||
AddTemplateOverloadCandidate(FuncTemplate, Args, NumArgs, CandidateSet);
|
||||
|
||||
if (FuncTemplate->getDeclContext()->isRecord())
|
||||
ArgumentDependentLookup = false;
|
||||
}
|
||||
|
||||
if (Callee)
|
||||
UnqualifiedName = Callee->getDeclName();
|
||||
|
@ -67,9 +67,10 @@ TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: What follows is a gross hack.
|
||||
// FIXME: What follows is a slightly less gross hack than what used to
|
||||
// follow.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
|
||||
if (FD->getType()->isDependentType()) {
|
||||
if (FD->getDescribedFunctionTemplate()) {
|
||||
TemplateResult = TemplateTy::make(FD);
|
||||
return TNK_Function_template;
|
||||
}
|
||||
@ -78,7 +79,7 @@ TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
|
||||
FEnd = Ovl->function_end();
|
||||
F != FEnd; ++F) {
|
||||
if ((*F)->getType()->isDependentType()) {
|
||||
if (isa<FunctionTemplateDecl>(*F)) {
|
||||
TemplateResult = TemplateTy::make(Ovl);
|
||||
return TNK_Function_template;
|
||||
}
|
||||
@ -1808,8 +1809,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||
!isa<TemplateTemplateParmDecl>(Template)) {
|
||||
assert(isa<FunctionTemplateDecl>(Template) &&
|
||||
"Only function templates are possible here");
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::note_template_arg_refers_here_func)
|
||||
Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
|
||||
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
|
||||
<< Template;
|
||||
}
|
||||
|
||||
@ -1873,15 +1874,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
|
||||
OldParmEnd = Old->end(), NewParm = New->begin();
|
||||
OldParm != OldParmEnd; ++OldParm, ++NewParm) {
|
||||
if ((*OldParm)->getKind() != (*NewParm)->getKind()) {
|
||||
unsigned NextDiag = diag::err_template_param_different_kind;
|
||||
if (TemplateArgLoc.isValid()) {
|
||||
Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
|
||||
NextDiag = diag::note_template_param_different_kind;
|
||||
if (Complain) {
|
||||
unsigned NextDiag = diag::err_template_param_different_kind;
|
||||
if (TemplateArgLoc.isValid()) {
|
||||
Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
|
||||
NextDiag = diag::note_template_param_different_kind;
|
||||
}
|
||||
Diag((*NewParm)->getLocation(), NextDiag)
|
||||
<< IsTemplateTemplateParm;
|
||||
Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
|
||||
<< IsTemplateTemplateParm;
|
||||
}
|
||||
Diag((*NewParm)->getLocation(), NextDiag)
|
||||
<< IsTemplateTemplateParm;
|
||||
Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
|
||||
<< IsTemplateTemplateParm;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2499,6 +2502,40 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
return DeclPtrTy::make(Specialization);
|
||||
}
|
||||
|
||||
Sema::DeclPtrTy
|
||||
Sema::ActOnTemplateDeclarator(Scope *S,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D) {
|
||||
return HandleDeclarator(S, D, move(TemplateParameterLists), false);
|
||||
}
|
||||
|
||||
Sema::DeclPtrTy
|
||||
Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D) {
|
||||
assert(getCurFunctionDecl() == 0 && "Function parsing confused");
|
||||
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
||||
"Not a function declarator!");
|
||||
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
||||
|
||||
if (FTI.hasPrototype) {
|
||||
// FIXME: Diagnose arguments without names in C.
|
||||
}
|
||||
|
||||
Scope *ParentScope = FnBodyScope->getParent();
|
||||
|
||||
DeclPtrTy DP = HandleDeclarator(ParentScope, D,
|
||||
move(TemplateParameterLists),
|
||||
/*IsFunctionDefinition=*/true);
|
||||
FunctionTemplateDecl *FunctionTemplate
|
||||
= cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>());
|
||||
if (FunctionTemplate)
|
||||
return ActOnStartOfFunctionDef(FnBodyScope,
|
||||
DeclPtrTy::make(FunctionTemplate->getTemplatedDecl()));
|
||||
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// Explicit instantiation of a class template specialization
|
||||
Sema::DeclResult
|
||||
Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user