Import Clang r74383.

This commit is contained in:
Ed Schouten 2009-06-27 10:45:02 +00:00
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
182 changed files with 7760 additions and 1761 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 *);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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) {}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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) {

View 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

View File

@ -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 {

View File

@ -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

View File

@ -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));

View File

@ -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">;

View File

@ -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<

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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.
///

View File

@ -97,6 +97,7 @@ class AttributeList {
AT_warn_unused_result,
AT_weak,
AT_weak_import,
AT_reqd_wg_size,
IgnoredAttribute,
UnknownAttribute
};

View File

@ -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
};

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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,

View File

@ -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");

View File

@ -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

View File

@ -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;

View File

@ -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())

View File

@ -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.

View File

@ -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);

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
// PathDiagnostics for analyses based on GRSimpleVals.
// PathDiagnostics.
//
//===----------------------------------------------------------------------===//

View File

@ -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);

View File

@ -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

View File

@ -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 "

View File

@ -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 << ":";

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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());
}
//===----------------------------------------------------------------------===//

View File

@ -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)));
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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()) {

View 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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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.
///

View File

@ -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-"

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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());

View File

@ -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() &&

View File

@ -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 {

View File

@ -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().

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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();

View File

@ -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)

View File

@ -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])));

View File

@ -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);

View File

@ -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());

View 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();
}

View File

@ -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}

View File

@ -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;

View File

@ -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";
}
}

View File

@ -48,6 +48,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *TargetName,
OverloadedOperatorKind Op,
AttributeList *AttrList,
bool IsTypeName) {

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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.
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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();

View File

@ -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