diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
commit | 4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch) | |
tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /include/clang | |
parent | 5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff) | |
download | src-4c8b24812ddcd1dedaca343a6d4e76f91f398981.tar.gz src-4c8b24812ddcd1dedaca343a6d4e76f91f398981.zip |
Update clang to r84119.vendor/clang/clang-r84119
Notes
Notes:
svn path=/vendor/clang/dist/; revision=198092
svn path=/vendor/clang/clang-84119/; revision=198093; tag=vendor/clang/clang-r84119
Diffstat (limited to 'include/clang')
192 files changed, 17361 insertions, 7950 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index 5d5abfe011d4..94d258d9e4e6 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -37,16 +37,16 @@ public: }; private: ValueKind Kind; - - struct ComplexAPSInt { - APSInt Real, Imag; + + struct ComplexAPSInt { + APSInt Real, Imag; ComplexAPSInt() : Real(1), Imag(1) {} }; struct ComplexAPFloat { APFloat Real, Imag; ComplexAPFloat() : Real(0.0), Imag(0.0) {} }; - + struct LV { Expr* Base; uint64_t Offset; @@ -57,16 +57,17 @@ private: Vec() : Elts(0), NumElts(0) {} ~Vec() { delete[] Elts; } }; - + enum { - MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ? + MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ? sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat)) }; - - /// Data - space for the largest member in units of void*. This is an effort - /// to ensure that the APSInt/APFloat values have proper alignment. - void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)]; - + + union { + void *Aligner; + char Data[MaxSize]; + }; + public: APValue() : Kind(Uninitialized) {} explicit APValue(const APSInt &I) : Kind(Uninitialized) { @@ -93,7 +94,7 @@ public: ~APValue() { MakeUninit(); } - + ValueKind getKind() const { return Kind; } bool isUninit() const { return Kind == Uninitialized; } bool isInt() const { return Kind == Int; } @@ -102,54 +103,54 @@ public: bool isComplexFloat() const { return Kind == ComplexFloat; } bool isLValue() const { return Kind == LValue; } bool isVector() const { return Kind == Vector; } - + void print(llvm::raw_ostream &OS) const; void dump() const; - + APSInt &getInt() { assert(isInt() && "Invalid accessor"); - return *(APSInt*)(void*)Data; + return *(APSInt*)(char*)Data; } const APSInt &getInt() const { return const_cast<APValue*>(this)->getInt(); } - + APFloat &getFloat() { assert(isFloat() && "Invalid accessor"); - return *(APFloat*)(void*)Data; + return *(APFloat*)(char*)Data; } const APFloat &getFloat() const { return const_cast<APValue*>(this)->getFloat(); } - + APValue &getVectorElt(unsigned i) const { assert(isVector() && "Invalid accessor"); - return ((Vec*)(void*)Data)->Elts[i]; + return ((Vec*)(char*)Data)->Elts[i]; } unsigned getVectorLength() const { assert(isVector() && "Invalid accessor"); return ((Vec*)(void *)Data)->NumElts; } - + APSInt &getComplexIntReal() { assert(isComplexInt() && "Invalid accessor"); - return ((ComplexAPSInt*)(void*)Data)->Real; + return ((ComplexAPSInt*)(char*)Data)->Real; } const APSInt &getComplexIntReal() const { return const_cast<APValue*>(this)->getComplexIntReal(); } - + APSInt &getComplexIntImag() { assert(isComplexInt() && "Invalid accessor"); - return ((ComplexAPSInt*)(void*)Data)->Imag; + return ((ComplexAPSInt*)(char*)Data)->Imag; } const APSInt &getComplexIntImag() const { return const_cast<APValue*>(this)->getComplexIntImag(); } - + APFloat &getComplexFloatReal() { assert(isComplexFloat() && "Invalid accessor"); - return ((ComplexAPFloat*)(void*)Data)->Real; + return ((ComplexAPFloat*)(char*)Data)->Real; } const APFloat &getComplexFloatReal() const { return const_cast<APValue*>(this)->getComplexFloatReal(); @@ -157,7 +158,7 @@ public: APFloat &getComplexFloatImag() { assert(isComplexFloat() && "Invalid accessor"); - return ((ComplexAPFloat*)(void*)Data)->Imag; + return ((ComplexAPFloat*)(char*)Data)->Imag; } const APFloat &getComplexFloatImag() const { return const_cast<APValue*>(this)->getComplexFloatImag(); @@ -171,44 +172,44 @@ public: assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data)->Offset; } - + void setInt(const APSInt &I) { assert(isInt() && "Invalid accessor"); - *(APSInt*)(void*)Data = I; + *(APSInt*)(char*)Data = I; } void setFloat(const APFloat &F) { assert(isFloat() && "Invalid accessor"); - *(APFloat*)(void*)Data = F; + *(APFloat*)(char*)Data = F; } void setVector(const APValue *E, unsigned N) { assert(isVector() && "Invalid accessor"); - ((Vec*)(void*)Data)->Elts = new APValue[N]; - ((Vec*)(void*)Data)->NumElts = N; + ((Vec*)(char*)Data)->Elts = new APValue[N]; + ((Vec*)(char*)Data)->NumElts = N; for (unsigned i = 0; i != N; ++i) - ((Vec*)(void*)Data)->Elts[i] = E[i]; + ((Vec*)(char*)Data)->Elts[i] = E[i]; } void setComplexInt(const APSInt &R, const APSInt &I) { - assert(R.getBitWidth() == I.getBitWidth() && + assert(R.getBitWidth() == I.getBitWidth() && "Invalid complex int (type mismatch)."); assert(isComplexInt() && "Invalid accessor"); - ((ComplexAPSInt*)(void*)Data)->Real = R; - ((ComplexAPSInt*)(void*)Data)->Imag = I; + ((ComplexAPSInt*)(char*)Data)->Real = R; + ((ComplexAPSInt*)(char*)Data)->Imag = I; } void setComplexFloat(const APFloat &R, const APFloat &I) { - assert(&R.getSemantics() == &I.getSemantics() && + assert(&R.getSemantics() == &I.getSemantics() && "Invalid complex float (type mismatch)."); assert(isComplexFloat() && "Invalid accessor"); - ((ComplexAPFloat*)(void*)Data)->Real = R; - ((ComplexAPFloat*)(void*)Data)->Imag = I; + ((ComplexAPFloat*)(char*)Data)->Real = R; + ((ComplexAPFloat*)(char*)Data)->Imag = I; } void setLValue(Expr *B, uint64_t O) { assert(isLValue() && "Invalid accessor"); - ((LV*)(void*)Data)->Base = B; - ((LV*)(void*)Data)->Offset = O; + ((LV*)(char*)Data)->Base = B; + ((LV*)(char*)Data)->Offset = O; } - + const APValue &operator=(const APValue &RHS); - + private: void MakeUninit(); void MakeInt() { @@ -218,27 +219,27 @@ private: } void MakeFloat() { assert(isUninit() && "Bad state change"); - new ((APFloat*)(void*)Data) APFloat(0.0); + new ((void*)(char*)Data) APFloat(0.0); Kind = Float; } void MakeVector() { assert(isUninit() && "Bad state change"); - new ((Vec*)(void*)Data) Vec(); + new ((void*)(char*)Data) Vec(); Kind = Vector; } void MakeComplexInt() { assert(isUninit() && "Bad state change"); - new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt(); + new ((void*)(char*)Data) ComplexAPSInt(); Kind = ComplexInt; } void MakeComplexFloat() { assert(isUninit() && "Bad state change"); - new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat(); + new ((void*)(char*)Data) ComplexAPFloat(); Kind = ComplexFloat; } void MakeLValue() { assert(isUninit() && "Bad state change"); - new ((LV*)(void*)Data) LV(); + new ((void*)(char*)Data) LV(); Kind = LValue; } }; @@ -247,7 +248,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) { V.print(OS); return OS; } - + } // end namespace clang. #endif diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index 6dc7e13d8f70..af6bf30b6882 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -36,27 +36,27 @@ public: ASTConsumer() : SemaConsumer(false) { } virtual ~ASTConsumer() {} - + /// Initialize - This is called to initialize the consumer, providing the /// ASTContext and the Action. virtual void Initialize(ASTContext &Context) {} - + /// HandleTopLevelDecl - Handle the specified top-level declaration. This is /// called by the parser to process every top-level Decl*. Note that D can /// be the head of a chain of Decls (e.g. for `int a, b` the chain will have /// two elements). Use Decl::getNextDeclarator() to walk the chain. virtual void HandleTopLevelDecl(DeclGroupRef D); - + /// HandleTranslationUnit - This method is called when the ASTs for entire /// translation unit have been parsed. - virtual void HandleTranslationUnit(ASTContext &Ctx) {} - + virtual void HandleTranslationUnit(ASTContext &Ctx) {} + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl /// (e.g. struct, union, enum, class) is completed. This allows the client to /// hack on the type, which can occur at any point in the file (because these /// can be defined in declspecs). virtual void HandleTagDeclDefinition(TagDecl *D) {} - + /// \brief Callback invoked at the end of a translation unit to /// notify the consumer that the given tentative definition should /// be completed. diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 041a0f33ad4d..63f909146e92 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -22,6 +22,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/OwningPtr.h" @@ -43,24 +44,26 @@ namespace clang { class TargetInfo; // Decls class Decl; + class FieldDecl; + class ObjCIvarDecl; + class ObjCIvarRefExpr; class ObjCPropertyDecl; class RecordDecl; class TagDecl; + class TemplateTypeParmDecl; class TranslationUnitDecl; class TypeDecl; class TypedefDecl; - class TemplateTypeParmDecl; - class FieldDecl; - class ObjCIvarRefExpr; - class ObjCIvarDecl; - + class UnresolvedUsingDecl; + class UsingDecl; + namespace Builtin { class Context; } - + /// ASTContext - This class holds long-lived AST nodes (such as types and /// decls) that can be referred to throughout the semantic analysis of a file. -class ASTContext { +class ASTContext { std::vector<Type*> Types; - llvm::FoldingSet<ExtQualType> ExtQualTypes; + llvm::FoldingSet<ExtQuals> ExtQualNodes; llvm::FoldingSet<ComplexType> ComplexTypes; llvm::FoldingSet<PointerType> PointerTypes; llvm::FoldingSet<BlockPointerType> BlockPointerTypes; @@ -70,17 +73,21 @@ class ASTContext { llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; std::vector<VariableArrayType*> VariableArrayTypes; - std::vector<DependentSizedArrayType*> DependentSizedArrayTypes; - std::vector<DependentSizedExtVectorType*> DependentSizedExtVectorTypes; + llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; + llvm::FoldingSet<DependentSizedExtVectorType> DependentSizedExtVectorTypes; llvm::FoldingSet<VectorType> VectorTypes; llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes; + llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; + llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; llvm::FoldingSet<TypenameType> TypenameTypes; - llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes; + llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes; llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; + llvm::FoldingSet<ObjCProtocolListType> ObjCProtocolListTypes; + llvm::FoldingSet<ElaboratedType> ElaboratedTypes; llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; @@ -97,46 +104,109 @@ class ASTContext { llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts; llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts; + /// \brief Mapping from ObjCContainers to their ObjCImplementations. + llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; + llvm::DenseMap<unsigned, FixedWidthIntType*> SignedFixedWidthIntTypes; llvm::DenseMap<unsigned, FixedWidthIntType*> UnsignedFixedWidthIntTypes; - + /// BuiltinVaListType - built-in va list type. /// This is initially null and set by Sema::LazilyCreateBuiltin when /// a builtin that takes a valist is encountered. QualType BuiltinVaListType; /// ObjCIdType - a pseudo built-in typedef type (set by Sema). - QualType ObjCIdType; - const RecordType *IdStructType; - + QualType ObjCIdTypedefType; + /// ObjCSelType - another pseudo built-in typedef type (set by Sema). QualType ObjCSelType; const RecordType *SelStructType; - + /// ObjCProtoType - another pseudo built-in typedef type (set by Sema). QualType ObjCProtoType; const RecordType *ProtoStructType; /// ObjCClassType - another pseudo built-in typedef type (set by Sema). - QualType ObjCClassType; - const RecordType *ClassStructType; - + QualType ObjCClassTypedefType; + QualType ObjCConstantStringType; RecordDecl *CFConstantStringTypeDecl; RecordDecl *ObjCFastEnumerationStateTypeDecl; - - /// \brief Keeps track of all declaration attributes. + + /// \brief The type for the C FILE type. + TypeDecl *FILEDecl; + + /// \brief The type for the C jmp_buf type. + TypeDecl *jmp_bufDecl; + + /// \brief The type for the C sigjmp_buf type. + TypeDecl *sigjmp_bufDecl; + + /// \brief Keeps track of all declaration attributes. /// /// Since so few decls have attrs, we keep them in a hash map instead of /// wasting space in the Decl class. llvm::DenseMap<const Decl*, Attr*> DeclAttrs; - + + /// \brief Keeps track of the static data member templates from which + /// static data members of class template specializations were instantiated. + /// + /// This data structure stores the mapping from instantiations of static + /// data members to the static data member representations within the + /// class template from which they were instantiated along with the kind + /// of instantiation or specialization (a TemplateSpecializationKind - 1). + /// + /// Given the following example: + /// + /// \code + /// template<typename T> + /// struct X { + /// static T value; + /// }; + /// + /// template<typename T> + /// T X<T>::value = T(17); + /// + /// int *x = &X<int>::value; + /// \endcode + /// + /// This mapping will contain an entry that maps from the VarDecl for + /// X<int>::value to the corresponding VarDecl for X<T>::value (within the + /// class template X) and will be marked TSK_ImplicitInstantiation. + llvm::DenseMap<VarDecl *, MemberSpecializationInfo *> + InstantiatedFromStaticDataMember; + + /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls + /// where created during instantiation. + /// + /// For example: + /// \code + /// template<typename T> + /// struct A { + /// void f(); + /// }; + /// + /// template<typename T> + /// struct B : A<T> { + /// using A<T>::f; + /// }; + /// + /// template struct B<int>; + /// \endcode + /// + /// This mapping will contain an entry that maps from the UsingDecl in + /// B<int> to the UnresolvedUsingDecl in B<T>. + llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *> + InstantiatedFromUnresolvedUsingDecl; + + llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl; + TranslationUnitDecl *TUDecl; /// SourceMgr - The associated SourceManager object. SourceManager &SourceMgr; - + /// LangOpts - The language options used to create the AST associated with /// this ASTContext object. LangOptions LangOpts; @@ -144,17 +214,17 @@ class ASTContext { /// \brief Whether we have already loaded comment source ranges from an /// external source. bool LoadedExternalComments; - + /// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects. bool FreeMemory; llvm::MallocAllocator MallocAlloc; llvm::BumpPtrAllocator BumpAlloc; - + /// \brief Mapping from declarations to their comments, once we have /// already looked up the comment associated with a given declaration. llvm::DenseMap<const Decl *, std::string> DeclComments; - -public: + +public: TargetInfo &Target; IdentifierTable &Idents; SelectorTable &Selectors; @@ -163,41 +233,73 @@ public: llvm::OwningPtr<ExternalASTSource> ExternalSource; clang::PrintingPolicy PrintingPolicy; + // Typedefs which may be provided defining the structure of Objective-C + // pseudo-builtins + QualType ObjCIdRedefinitionType; + QualType ObjCClassRedefinitionType; + /// \brief Source ranges for all of the comments in the source file, /// sorted in order of appearance in the translation unit. std::vector<SourceRange> Comments; - + SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } void *Allocate(unsigned Size, unsigned Align = 8) { return FreeMemory ? MallocAlloc.Allocate(Size, Align) : BumpAlloc.Allocate(Size, Align); } - void Deallocate(void *Ptr) { + void Deallocate(void *Ptr) { if (FreeMemory) - MallocAlloc.Deallocate(Ptr); + MallocAlloc.Deallocate(Ptr); } const LangOptions& getLangOptions() const { return LangOpts; } - - FullSourceLoc getFullLoc(SourceLocation Loc) const { + + FullSourceLoc getFullLoc(SourceLocation Loc) const { return FullSourceLoc(Loc,SourceMgr); } /// \brief Retrieve the attributes for the given declaration. Attr*& getDeclAttrs(const Decl *D) { return DeclAttrs[D]; } - + /// \brief Erase the attributes corresponding to the given declaration. void eraseDeclAttrs(const Decl *D) { DeclAttrs.erase(D); } - + + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + MemberSpecializationInfo *getInstantiatedFromStaticDataMember(VarDecl *Var); + + /// \brief Note that the static data member \p Inst is an instantiation of + /// the static data member template \p Tmpl of a class template. + void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK); + + /// \brief If this using decl is instantiated from an unresolved using decl, + /// return it. + UnresolvedUsingDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD); + + /// \brief Note that the using decl \p Inst is an instantiation of + /// the unresolved using decl \p Tmpl of a class template. + void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst, + UnresolvedUsingDecl *Tmpl); + + + FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); + + void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } + const char *getCommentForDecl(const Decl *D); - + // Builtin Types. QualType VoidTy; QualType BoolTy; QualType CharTy; - QualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + QualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + QualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. + QualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; QualType UnsignedLongLongTy, UnsignedInt128Ty; @@ -207,6 +309,7 @@ public: QualType OverloadTy; QualType DependentTy; QualType UndeducedAutoTy; + QualType ObjCBuiltinIdTy, ObjCBuiltinClassTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, @@ -232,23 +335,52 @@ public: //===--------------------------------------------------------------------===// // Type Constructors //===--------------------------------------------------------------------===// - - /// getAddSpaceQualType - Return the uniqued reference to the type for an - /// address space qualified type with the specified type and address space. - /// The resulting type has a union of the qualifiers from T and the address - /// space. If T already has an address space specifier, it is silently + +private: + /// getExtQualType - Return a type with extended qualifiers. + QualType getExtQualType(const Type *Base, Qualifiers Quals); + +public: + /// getAddSpaceQualType - Return the uniqued reference to the type for an + /// address space qualified type with the specified type and address space. + /// The resulting type has a union of the qualifiers from T and the address + /// space. If T already has an address space specifier, it is silently /// replaced. QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace); - + /// getObjCGCQualType - Returns the uniqued reference to the type for an /// objc gc qualified type. The retulting type has a union of the qualifiers /// from T and the gc attribute. - QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr); - + QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr); + + /// getRestrictType - Returns the uniqued reference to the type for a + /// 'restrict' qualified type. The resulting type has a union of the + /// qualifiers from T and 'restrict'. + QualType getRestrictType(QualType T) { + return T.withFastQualifiers(Qualifiers::Restrict); + } + + /// getVolatileType - Returns the uniqued reference to the type for a + /// 'volatile' qualified type. The resulting type has a union of the + /// qualifiers from T and 'volatile'. + QualType getVolatileType(QualType T); + + /// getConstType - Returns the uniqued reference to the type for a + /// 'const' qualified type. The resulting type has a union of the + /// qualifiers from T and 'const'. + /// + /// It can be reasonably expected that this will always be + /// equivalent to calling T.withConst(). + QualType getConstType(QualType T) { return T.withConst(); } + + /// getNoReturnType - Add the noreturn attribute to the given type which must + /// be a FunctionType or a pointer to an allowable type or a BlockPointer. + QualType getNoReturnType(QualType T); + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); - + /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. QualType getPointerType(QualType T); @@ -274,15 +406,17 @@ public: /// variable array of the specified element type. QualType getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals); - + unsigned EltTypeQuals, + SourceRange Brackets); + /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element /// type. FIXME: We will need these to be uniqued, or at least /// comparable, at some point. QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals); + unsigned EltTypeQuals, + SourceRange Brackets); /// getIncompleteArrayType - Returns a unique reference to the type for a /// incomplete array of the specified element type. @@ -295,7 +429,23 @@ public: QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals); - + + /// getConstantArrayWithExprType - Return a reference to the type for a + /// constant array of the specified element type. + QualType getConstantArrayWithExprType(QualType EltTy, + const llvm::APInt &ArySize, + Expr *ArySizeExpr, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals, + SourceRange Brackets); + + /// getConstantArrayWithoutExprType - Return a reference to the type + /// for a constant array of the specified element type. + QualType getConstantArrayWithoutExprType(QualType EltTy, + const llvm::APInt &ArySize, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals); + /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. QualType getVectorType(QualType VectorType, unsigned NumElts); @@ -309,13 +459,13 @@ public: /// the type for a dependently-sized vector of the specified element /// type. FIXME: We will need these to be uniqued, or at least /// comparable, at some point. - QualType getDependentSizedExtVectorType(QualType VectorType, + QualType getDependentSizedExtVectorType(QualType VectorType, Expr *SizeExpr, SourceLocation AttrLoc); /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// - QualType getFunctionNoProtoType(QualType ResultTy); + QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false); /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. @@ -323,7 +473,8 @@ public: unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec = false, bool hasAnyExceptionSpec = false, - unsigned NumExs = 0, const QualType *ExArray = 0); + unsigned NumExs = 0, const QualType *ExArray = 0, + bool NoReturn = false); /// getTypeDeclType - Return the unique reference to the type for /// the specified type declaration. @@ -332,9 +483,8 @@ public: /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); - QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl); - QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, + QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, IdentifierInfo *Name = 0); @@ -345,37 +495,40 @@ public: QualType getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType); - QualType getTypenameType(NestedNameSpecifier *NNS, + QualType getTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType Canon = QualType()); - QualType getTypenameType(NestedNameSpecifier *NNS, + QualType getTypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *TemplateId, QualType Canon = QualType()); + QualType getElaboratedType(QualType UnderlyingType, + ElaboratedType::TagKind Tag); + + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **Protocols = 0, + unsigned NumProtocols = 0); /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the /// given interface decl and the conforming protocol list. - QualType getObjCObjectPointerType(ObjCInterfaceDecl *Decl, + QualType getObjCObjectPointerType(QualType OIT, ObjCProtocolDecl **ProtocolList = 0, unsigned NumProtocols = 0); - - /// getObjCQualifiedInterfaceType - Return a - /// ObjCQualifiedInterfaceType type for the given interface decl and - /// the conforming protocol list. - QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **ProtocolList, - unsigned NumProtocols); - + + QualType getObjCProtocolListType(QualType T, + ObjCProtocolDecl **Protocols, + unsigned NumProtocols); + /// getTypeOfType - GCC extension. 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); - + QualType getTagDeclType(const TagDecl *Decl); + /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined /// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4). QualType getSizeType() const; @@ -392,15 +545,15 @@ public: /// getUnsignedWCharType - Return the type of "unsigned wchar_t". /// Used when in C++, as a GCC extension. QualType getUnsignedWCharType() const; - + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; - + // getCFConstantStringType - Return the C structure type used to represent // constant CFStrings. - QualType getCFConstantStringType(); - + QualType getCFConstantStringType(); + /// Get the structure type used to representation CFStrings, or NULL /// if it hasn't yet been built. QualType getRawCFConstantStringType() { @@ -412,13 +565,13 @@ public: // This setter/getter represents the ObjC type for an NSConstantString. void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl); - QualType getObjCConstantStringInterface() const { - return ObjCConstantStringType; + QualType getObjCConstantStringInterface() const { + return ObjCConstantStringType; } //// This gets the struct used to keep track of fast enumerations. QualType getObjCFastEnumerationStateType(); - + /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet /// been built. QualType getRawObjCFastEnumerationStateType() { @@ -429,109 +582,166 @@ public: void setObjCFastEnumerationStateType(QualType T); + /// \brief Set the type for the C FILE type. + void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; } + + /// \brief Retrieve the C FILE type. + QualType getFILEType() { + if (FILEDecl) + return getTypeDeclType(FILEDecl); + return QualType(); + } + + /// \brief Set the type for the C jmp_buf type. + void setjmp_bufDecl(TypeDecl *jmp_bufDecl) { + this->jmp_bufDecl = jmp_bufDecl; + } + + /// \brief Retrieve the C jmp_buf type. + QualType getjmp_bufType() { + if (jmp_bufDecl) + return getTypeDeclType(jmp_bufDecl); + return QualType(); + } + + /// \brief Set the type for the C sigjmp_buf type. + void setsigjmp_bufDecl(TypeDecl *sigjmp_bufDecl) { + this->sigjmp_bufDecl = sigjmp_bufDecl; + } + + /// \brief Retrieve the C sigjmp_buf type. + QualType getsigjmp_bufType() { + if (sigjmp_bufDecl) + return getTypeDeclType(sigjmp_bufDecl); + return QualType(); + } + /// getObjCEncodingForType - Emit the ObjC type encoding for the /// given type into \arg S. If \arg NameFields is specified then /// record field names are also encoded. - void getObjCEncodingForType(QualType t, std::string &S, + void getObjCEncodingForType(QualType t, std::string &S, const FieldDecl *Field=0); void getLegacyIntegralTypeEncoding(QualType &t) const; - + // Put the string version of type qualifiers into S. - void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, std::string &S) const; - + /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S); - + /// getObjCEncodingForPropertyDecl - Return the encoded type for /// this method declaration. If non-NULL, Container must be either /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should /// only be NULL when getting encodings for protocol properties. - void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, + void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, const Decl *Container, std::string &S); - + + bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto); + /// getObjCEncodingTypeSize returns size of type for objective-c encoding /// purpose. int getObjCEncodingTypeSize(QualType t); /// This setter/getter represents the ObjC 'id' type. It is setup lazily, by /// Sema. id is always a (typedef for a) pointer type, a pointer to a struct. - QualType getObjCIdType() const { return ObjCIdType; } + QualType getObjCIdType() const { return ObjCIdTypedefType; } void setObjCIdType(QualType T); - + void setObjCSelType(QualType T); QualType getObjCSelType() const { return ObjCSelType; } - + void setObjCProtoType(QualType QT); QualType getObjCProtoType() const { return ObjCProtoType; } - + /// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by /// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a /// struct. - QualType getObjCClassType() const { return ObjCClassType; } + QualType getObjCClassType() const { return ObjCClassTypedefType; } void setObjCClassType(QualType T); - + void setBuiltinVaListType(QualType T); QualType getBuiltinVaListType() const { return BuiltinVaListType; } QualType getFixedWidthIntType(unsigned Width, bool Signed); - TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + /// getCVRQualifiedType - Returns a type with additional const, + /// volatile, or restrict qualifiers. + QualType getCVRQualifiedType(QualType T, unsigned CVR) { + return getQualifiedType(T, Qualifiers::fromCVRMask(CVR)); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(QualType T, Qualifiers Qs) { + if (!Qs.hasNonFastQualifiers()) + return T.withFastQualifiers(Qs.getFastQualifiers()); + QualifierCollector Qc(Qs); + const Type *Ptr = Qc.strip(T); + return getExtQualType(Ptr, Qc); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(const Type *T, Qualifiers Qs) { + if (!Qs.hasNonFastQualifiers()) + return QualType(T, Qs.getFastQualifiers()); + return getExtQualType(T, Qs); + } + + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template); + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + OverloadedFunctionDecl *Template); - TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name); enum GetBuiltinTypeError { - GE_None, //< No error - GE_Missing_FILE //< Missing the FILE type from <stdio.h> + GE_None, //< No error + GE_Missing_stdio, //< Missing a type from <stdio.h> + GE_Missing_setjmp //< Missing a type from <setjmp.h> }; - + /// GetBuiltinType - Return the type for the specified builtin. QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error); - + private: QualType getFromTargetType(unsigned Type) const; //===--------------------------------------------------------------------===// // Type Predicates. //===--------------------------------------------------------------------===// - -public: - /// isObjCObjectPointerType - Returns true if type is an Objective-C pointer - /// to an object type. This includes "id" and "Class" (two 'special' pointers - /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified - /// ID type). - bool isObjCObjectPointerType(QualType Ty) const; +public: /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// - QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const; - + Qualifiers::GC getObjCGCAttrKind(const QualType &Ty) const; + /// isObjCNSObjectType - Return true if this is an NSObject object with /// its NSObject attribute set. bool isObjCNSObjectType(QualType Ty) const; - + //===--------------------------------------------------------------------===// // Type Sizing and Analysis //===--------------------------------------------------------------------===// - + /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified /// scalar floating point type. const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; - + /// getTypeInfo - Get the size and alignment of the specified complete type in /// bits. std::pair<uint64_t, unsigned> getTypeInfo(const Type *T); std::pair<uint64_t, unsigned> getTypeInfo(QualType T) { return getTypeInfo(T.getTypePtr()); } - + /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. uint64_t getTypeSize(QualType T) { @@ -540,7 +750,7 @@ public: uint64_t getTypeSize(const Type *T) { return getTypeInfo(T).first; } - + /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. /// This method does not work on incomplete types. unsigned getTypeAlign(QualType T) { @@ -549,23 +759,23 @@ public: unsigned getTypeAlign(const Type *T) { return getTypeInfo(T).second; } - + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign /// a data type. unsigned getPreferredTypeAlign(const Type *T); - + /// getDeclAlignInBytes - Return the alignment of the specified decl /// that should be returned by __alignof(). Note that bitfields do /// not have a valid alignment, so this method will assert on them. unsigned getDeclAlignInBytes(const Decl *D); - + /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D); - + /// getASTObjCInterfaceLayout - Get or compute information about the /// layout of the specified Objective-C interface. const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D); @@ -592,14 +802,14 @@ public: //===--------------------------------------------------------------------===// // Type Operators //===--------------------------------------------------------------------===// - + /// getCanonicalType - Return the canonical (structural) type corresponding to /// the specified potentially non-canonical type. The non-canonical version /// of a type may have many "decorated" versions of types. Decorators can /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed /// to be free of any of these, allowing two canonical types to be compared /// for exact equality with a simple pointer comparison. - QualType getCanonicalType(QualType T); + CanQualType getCanonicalType(QualType T); const Type *getCanonicalType(const Type *T) { return T->getCanonicalTypeInternal().getTypePtr(); } @@ -608,7 +818,7 @@ public: bool hasSameType(QualType T1, QualType T2) { return getCanonicalType(T1) == getCanonicalType(T2); } - + /// \brief Determine whether the given types are equivalent after /// cvr-qualifiers have been removed. bool hasSameUnqualifiedType(QualType T1, QualType T2) { @@ -617,20 +827,7 @@ public: return T1.getUnqualifiedType() == T2.getUnqualifiedType(); } - /// \brief Retrieves the "canonical" declaration of the given declaration. - Decl *getCanonicalDecl(Decl *D); - - /// \brief Retrieves the "canonical" declaration of the given tag - /// declaration. - /// - /// The canonical declaration for the given tag declaration is - /// either the definition of the tag (if it is a complete type) or - /// the first declaration of that tag. - TagDecl *getCanonicalDecl(TagDecl *Tag) { - return cast<TagDecl>(getCanonicalDecl((Decl *)Tag)); - } - - /// \brief Retrieves the "canonical" declaration of + /// \brief Retrieves the "canonical" declaration of /// \brief Retrieves the "canonical" nested name specifier for a /// given nested name specifier. @@ -678,6 +875,13 @@ public: /// types, values, and templates. TemplateName getCanonicalTemplateName(TemplateName Name); + /// \brief Retrieve the "canonical" template argument. + /// + /// The canonical template argument is the simplest template argument + /// (which may be a type, value, expression, or declaration) that + /// expresses the value of the argument. + TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg); + /// Type Query functions. If the type is an instance of the specified class, /// return the Type pointer for the underlying maximally pretty type. This /// is a member of ASTContext because this may need to do some amount of @@ -693,10 +897,17 @@ public: return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T)); } - /// getBaseElementType - Returns the innermost element type of a variable - /// length array type. For example, will return "int" for int[m][n] - QualType getBaseElementType(const VariableArrayType *VAT); - + /// getBaseElementType - Returns the innermost element type of an array type. + /// For example, will return "int" for int[m][n] + QualType getBaseElementType(const ArrayType *VAT); + + /// getBaseElementType - Returns the innermost element type of a type + /// (which needn't actually be an array type). + QualType getBaseElementType(QualType QT); + + /// getConstantArrayElementCount - Returns number of constant array elements. + uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; + /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when /// handling typedefs etc. The canonical type of "T" must be an array type, @@ -704,23 +915,35 @@ public: /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. QualType getArrayDecayedType(QualType T); - - /// getIntegerTypeOrder - Returns the highest ranked integer type: + + /// getPromotedIntegerType - Returns the type that Promotable will + /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable + /// integer type. + QualType getPromotedIntegerType(QualType PromotableType); + + /// \brief Whether this is a promotable bitfield reference according + /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). + /// + /// \returns the type this bit-field will promote to, or NULL if no + /// promotion occurs. + QualType isPromotableBitField(Expr *E); + + /// getIntegerTypeOrder - Returns the highest ranked integer type: /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If - /// LHS < RHS, return -1. + /// LHS < RHS, return -1. int getIntegerTypeOrder(QualType LHS, QualType RHS); - + /// getFloatingTypeOrder - Compare the rank of the two specified floating /// point types, ignoring the domain of the type (i.e. 'double' == /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If - /// LHS < RHS, return -1. + /// LHS < RHS, return -1. int getFloatingTypeOrder(QualType LHS, QualType RHS); - /// getFloatingTypeOfSizeWithinDomain - Returns a real floating - /// point or a complex type (based on typeDomain/typeSize). + /// getFloatingTypeOfSizeWithinDomain - Returns a real floating + /// point or a complex type (based on typeDomain/typeSize). /// 'typeDomain' is a real floating point or complex type. /// 'typeSize' is a real floating point or complex type. - QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, + QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, QualType typeDomain) const; private: @@ -732,33 +955,28 @@ public: //===--------------------------------------------------------------------===// // Type Compatibility Predicates //===--------------------------------------------------------------------===// - + /// Compatibility predicates used to check assignment expressions. bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1 - + bool isObjCIdType(QualType T) const { - return T == ObjCIdType; - } - bool isObjCIdStructType(QualType T) const { - if (!IdStructType) // ObjC isn't enabled - return false; - return T->getAsStructureType() == IdStructType; + return T == ObjCIdTypedefType; } bool isObjCClassType(QualType T) const { - return T == ObjCClassType; - } - bool isObjCClassStructType(QualType T) const { - if (!ClassStructType) // ObjC isn't enabled - return false; - return T->getAsStructureType() == ClassStructType; + return T == ObjCClassTypedefType; } bool isObjCSelType(QualType T) const { assert(SelStructType && "isObjCSelType used before 'SEL' type is built"); return T->getAsStructureType() == SelStructType; } + bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); + bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, + bool ForCompare); // Check the safety of assignment from LHS to RHS - bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, + bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS); bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); @@ -766,6 +984,11 @@ public: QualType mergeTypes(QualType, QualType); QualType mergeFunctionTypes(QualType, QualType); + /// UsualArithmeticConversionsType - handles the various conversions + /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) + /// and returns the result type of that conversion. + QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs); + //===--------------------------------------------------------------------===// // Integer Predicates //===--------------------------------------------------------------------===// @@ -782,15 +1005,15 @@ public: //===--------------------------------------------------------------------===// // Type Iterators. //===--------------------------------------------------------------------===// - + typedef std::vector<Type*>::iterator type_iterator; typedef std::vector<Type*>::const_iterator const_type_iterator; - + type_iterator types_begin() { return Types.begin(); } type_iterator types_end() { return Types.end(); } const_type_iterator types_begin() const { return Types.begin(); } - const_type_iterator types_end() const { return Types.end(); } - + const_type_iterator types_end() const { return Types.end(); } + //===--------------------------------------------------------------------===// // Integer Values //===--------------------------------------------------------------------===// @@ -803,15 +1026,37 @@ public: return Res; } + /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. + ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D); + /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. + ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + + /// \brief Set the implementation of ObjCInterfaceDecl. + void setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD); + /// \brief Set the implementation of ObjCCategoryDecl. + void setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD); + + /// \brief Allocate an uninitialized DeclaratorInfo. + /// + /// The caller should initialize the memory held by DeclaratorInfo using + /// the TypeLoc wrappers. + /// + /// \param T the type that will be the basis for type source info. This type + /// should refer to how the declarator was written in source code, not to + /// what type semantic analysis resolved the declarator to. + DeclaratorInfo *CreateDeclaratorInfo(QualType T); + private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT void operator=(const ASTContext&); // DO NOT IMPLEMENT - + void InitBuiltinTypes(); void InitBuiltinType(QualType &R, BuiltinType::Kind K); - + // Return the ObjC type encoding for a given type. - void getObjCEncodingForTypeImpl(QualType t, std::string &S, + void getObjCEncodingForTypeImpl(QualType t, std::string &S, bool ExpandPointedToStructures, bool ExpandStructures, const FieldDecl *Field, @@ -819,7 +1064,7 @@ private: bool EncodingProperty = false); const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl); + const ObjCImplementationDecl *Impl); }; } // end namespace clang diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index e9f150574b05..abd36f7e5f0f 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define ASTSTART diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 7d3009b01129..6a5e3666a92c 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -14,6 +14,9 @@ #ifndef LLVM_CLANG_AST_ATTR_H #define LLVM_CLANG_AST_ATTR_H +#include "llvm/Support/Casting.h" +using llvm::dyn_cast; + #include <cassert> #include <cstring> #include <string> @@ -54,22 +57,24 @@ public: DLLImport, Deprecated, Destructor, - FastCall, + FastCall, Format, FormatArg, GNUInline, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with + Malloc, + NoDebug, + NoInline, + NonNull, NoReturn, NoThrow, - Nodebug, - Noinline, - NonNull, ObjCException, ObjCNSObject, CFReturnsRetained, // Clang/Checker-specific. NSReturnsRetained, // Clang/Checker-specific. Overloadable, // Clang-specific Packed, + PragmaPack, Pure, Regparm, ReqdWorkGroupSize, // OpenCL-specific @@ -78,14 +83,14 @@ public: StdCall, TransparentUnion, Unavailable, - Unused, + Unused, Used, Visibility, WarnUnusedResult, Weak, WeakImport }; - + private: Attr *Next; Kind AttrKind; @@ -99,16 +104,16 @@ protected: void operator delete(void* data) throw() { assert(0 && "Attrs cannot be released with regular 'delete'."); } - + protected: Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {} virtual ~Attr() { assert(Next == 0 && "Destroy didn't work"); } public: - + void Destroy(ASTContext &C); - + /// \brief Whether this attribute should be merged to new /// declarations. virtual bool isMerged() const { return true; } @@ -119,17 +124,24 @@ public: const Attr *getNext() const { return Next; } void setNext(Attr *next) { Next = next; } + template<typename T> const T *getNext() const { + for (const Attr *attr = getNext(); attr; attr = attr->getNext()) + if (const T *V = dyn_cast<T>(attr)) + return V; + return 0; + } + bool isInherited() const { return Inherited; } void setInherited(bool value) { Inherited = value; } void addAttr(Attr *attr) { assert((attr != 0) && "addAttr(): attr is null"); - + // FIXME: This doesn't preserve the order in any way. attr->Next = Next; Next = attr; } - + // Clone this attribute. virtual Attr* clone(ASTContext &C) const = 0; @@ -146,36 +158,39 @@ public: \ static bool classof(const ATTR##Attr *A) { return true; } \ } -class PackedAttr : public Attr { +DEF_SIMPLE_ATTR(Packed); + +class PragmaPackAttr : public Attr { unsigned Alignment; public: - PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {} + PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {} /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } - virtual Attr* clone(ASTContext &C) const { - return ::new (C) PackedAttr(Alignment); + virtual Attr* clone(ASTContext &C) const { + return ::new (C) PragmaPackAttr(Alignment); } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { - return A->getKind() == Packed; + return A->getKind() == PragmaPack; } - static bool classof(const PackedAttr *A) { return true; } + static bool classof(const PragmaPackAttr *A) { return true; } }; - + class AlignedAttr : public Attr { unsigned Alignment; public: AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} + // FIXME: Should use addressable units, not bits, to match llvm /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } - + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Aligned; @@ -187,11 +202,11 @@ class AnnotateAttr : public Attr { std::string Annotation; public: AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {} - + const std::string& getAnnotation() const { return Annotation; } virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); } - + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Annotate; @@ -203,11 +218,11 @@ class AsmLabelAttr : public Attr { std::string Label; public: AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {} - + const std::string& getLabel() const { return Label; } - + virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); } - + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == AsmLabel; @@ -237,28 +252,28 @@ public: ConstructorAttr(int p) : Attr(Constructor), priority(p) {} int getPriority() const { return priority; } - + virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); } // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Constructor; } + static bool classof(const Attr *A) { return A->getKind() == Constructor; } static bool classof(const ConstructorAttr *A) { return true; } -}; - +}; + class DestructorAttr : public Attr { int priority; public: DestructorAttr(int p) : Attr(Destructor), priority(p) {} int getPriority() const { return priority; } - + virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); } // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Destructor; } + static bool classof(const Attr *A) { return A->getKind() == Destructor; } static bool classof(const DestructorAttr *A) { return true; } -}; - +}; + class GNUInlineAttr : public Attr { public: GNUInlineAttr() : Attr(GNUInline) {} @@ -285,15 +300,16 @@ public: static bool classof(const IBOutletAttr *A) { return true; } }; +DEF_SIMPLE_ATTR(Malloc); DEF_SIMPLE_ATTR(NoReturn); -DEF_SIMPLE_ATTR(AnalyzerNoReturn); +DEF_SIMPLE_ATTR(AnalyzerNoReturn); DEF_SIMPLE_ATTR(Deprecated); class SectionAttr : public Attr { std::string Name; public: SectionAttr(const std::string &N) : Attr(Section), Name(N) {} - + const std::string& getName() const { return Name; } virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); } @@ -307,8 +323,8 @@ public: DEF_SIMPLE_ATTR(Unavailable); DEF_SIMPLE_ATTR(Unused); -DEF_SIMPLE_ATTR(Used); -DEF_SIMPLE_ATTR(Weak); +DEF_SIMPLE_ATTR(Used); +DEF_SIMPLE_ATTR(Weak); DEF_SIMPLE_ATTR(WeakImport); DEF_SIMPLE_ATTR(NoThrow); DEF_SIMPLE_ATTR(Const); @@ -320,14 +336,14 @@ class NonNullAttr : public Attr { public: NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull), ArgNums(0), Size(0) { - + if (size == 0) return; assert(arg_nums); ArgNums = new unsigned[size]; Size = size; memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); } - + virtual ~NonNullAttr() { delete [] ArgNums; } @@ -339,7 +355,7 @@ public: bool isNonNull(unsigned arg) const { return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true; - } + } virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); } @@ -359,8 +375,8 @@ public: int getFormatIdx() const { return formatIdx; } int getFirstArg() const { return firstArg; } - virtual Attr *clone(ASTContext &C) const { - return ::new (C) FormatAttr(Type, formatIdx, firstArg); + virtual Attr *clone(ASTContext &C) const { + return ::new (C) FormatAttr(Type, formatIdx, firstArg); } // Implement isa/cast/dyncast/etc. @@ -437,8 +453,8 @@ public: virtual bool isMerged() const { return false; } - virtual Attr *clone(ASTContext &C) const { - return ::new (C) OverloadableAttr; + virtual Attr *clone(ASTContext &C) const { + return ::new (C) OverloadableAttr; } static bool classof(const Attr *A) { return A->getKind() == Overloadable; } @@ -465,15 +481,15 @@ public: }; class FunctionDecl; - + class CleanupAttr : public Attr { FunctionDecl *FD; - + public: CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {} const FunctionDecl *getFunctionDecl() const { return FD; } - + virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); } // Implement isa/cast/dyncast/etc. @@ -481,9 +497,9 @@ public: static bool classof(const CleanupAttr *A) { return true; } }; -DEF_SIMPLE_ATTR(Nodebug); -DEF_SIMPLE_ATTR(WarnUnusedResult); -DEF_SIMPLE_ATTR(Noinline); +DEF_SIMPLE_ATTR(NoDebug); +DEF_SIMPLE_ATTR(WarnUnusedResult); +DEF_SIMPLE_ATTR(NoInline); class RegparmAttr : public Attr { unsigned NumParams; @@ -493,11 +509,11 @@ public: unsigned getNumParams() const { return NumParams; } - virtual Attr *clone(ASTContext &C) const { - return ::new (C) RegparmAttr(NumParams); + virtual Attr *clone(ASTContext &C) const { + return ::new (C) RegparmAttr(NumParams); } - // Implement isa/cast/dyncast/etc. + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Regparm; } static bool classof(const RegparmAttr *A) { return true; } }; @@ -512,23 +528,23 @@ public: unsigned getYDim() const { return Y; } unsigned getZDim() const { return Z; } - virtual Attr *clone(ASTContext &C) const { - return ::new (C) ReqdWorkGroupSizeAttr(X, Y, 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); #undef DEF_SIMPLE_ATTR - + } // end namespace clang #endif diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h new file mode 100644 index 000000000000..a57bcc184a93 --- /dev/null +++ b/include/clang/AST/CXXInheritance.h @@ -0,0 +1,212 @@ +//===------ CXXInheritance.h - C++ Inheritance ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H +#define LLVM_CLANG_AST_CXXINHERITANCE_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/ADT/SmallVector.h" +#include <list> +#include <map> +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class CXXMethodDecl; +class CXXRecordDecl; +class NamedDecl; + +/// \brief Represents an element in a path from a derived class to a +/// base class. +/// +/// Each step in the path references the link from a +/// derived class to one of its direct base classes, along with a +/// base "number" that identifies which base subobject of the +/// original derived class we are referencing. +struct CXXBasePathElement { + /// \brief The base specifier that states the link from a derived + /// class to a base class, which will be followed by this base + /// path element. + const CXXBaseSpecifier *Base; + + /// \brief The record decl of the class that the base is a base of. + const CXXRecordDecl *Class; + + /// \brief Identifies which base class subobject (of type + /// \c Base->getType()) this base path element refers to. + /// + /// This value is only valid if \c !Base->isVirtual(), because there + /// is no base numbering for the zero or one virtual bases of a + /// given type. + int SubobjectNumber; +}; + +/// \brief Represents a path from a specific derived class +/// (which is not represented as part of the path) to a particular +/// (direct or indirect) base class subobject. +/// +/// Individual elements in the path are described by the \c CXXBasePathElement +/// structure, which captures both the link from a derived class to one of its +/// direct bases and identification describing which base class +/// subobject is being used. +struct CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> { + /// \brief The set of declarations found inside this base class + /// subobject. + DeclContext::lookup_result Decls; +}; + +/// BasePaths - Represents the set of paths from a derived class to +/// one of its (direct or indirect) bases. For example, given the +/// following class hierachy: +/// +/// @code +/// class A { }; +/// class B : public A { }; +/// class C : public A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// There are two potential BasePaths to represent paths from D to a +/// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0) +/// and another is (D,0)->(C,0)->(A,1). These two paths actually +/// refer to two different base class subobjects of the same type, +/// so the BasePaths object refers to an ambiguous path. On the +/// other hand, consider the following class hierarchy: +/// +/// @code +/// class A { }; +/// class B : public virtual A { }; +/// class C : public virtual A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// Here, there are two potential BasePaths again, (D, 0) -> (B, 0) +/// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them +/// refer to the same base class subobject of type A (the virtual +/// one), there is no ambiguity. +class CXXBasePaths { + /// \brief The type from which this search originated. + CXXRecordDecl *Origin; + + /// Paths - The actual set of paths that can be taken from the + /// derived class to the same base class. + std::list<CXXBasePath> Paths; + + /// ClassSubobjects - Records the class subobjects for each class + /// type that we've seen. The first element in the pair says + /// whether we found a path to a virtual base for that class type, + /// while the element contains the number of non-virtual base + /// class subobjects for that class type. The key of the map is + /// the cv-unqualified canonical type of the base class subobject. + std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering> + ClassSubobjects; + + /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find + /// ambiguous paths while it is looking for a path from a derived + /// type to a base type. + bool FindAmbiguities; + + /// RecordPaths - Whether Sema::IsDerivedFrom should record paths + /// while it is determining whether there are paths from a derived + /// type to a base type. + bool RecordPaths; + + /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search + /// if it finds a path that goes across a virtual base. The virtual class + /// is also recorded. + bool DetectVirtual; + + /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom + /// to help build the set of paths. + CXXBasePath ScratchPath; + + /// DetectedVirtual - The base class that is virtual. + const RecordType *DetectedVirtual; + + /// \brief Array of the declarations that have been found. This + /// array is constructed only if needed, e.g., to iterate over the + /// results within LookupResult. + NamedDecl **DeclsFound; + unsigned NumDeclsFound; + + friend class CXXRecordDecl; + + void ComputeDeclsFound(); + +public: + typedef std::list<CXXBasePath>::const_iterator paths_iterator; + typedef NamedDecl **decl_iterator; + + /// BasePaths - Construct a new BasePaths structure to record the + /// paths for a derived-to-base search. + explicit CXXBasePaths(bool FindAmbiguities = true, + bool RecordPaths = true, + bool DetectVirtual = true) + : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0), + NumDeclsFound(0) { } + + ~CXXBasePaths() { delete [] DeclsFound; } + + paths_iterator begin() const { return Paths.begin(); } + paths_iterator end() const { return Paths.end(); } + + CXXBasePath& front() { return Paths.front(); } + const CXXBasePath& front() const { return Paths.front(); } + + decl_iterator found_decls_begin(); + decl_iterator found_decls_end(); + + /// \brief Determine whether the path from the most-derived type to the + /// given base type is ambiguous (i.e., it refers to multiple subobjects of + /// the same base type). + bool isAmbiguous(QualType BaseType); + + /// \brief Whether we are finding multiple paths to detect ambiguities. + bool isFindingAmbiguities() const { return FindAmbiguities; } + + /// \brief Whether we are recording paths. + bool isRecordingPaths() const { return RecordPaths; } + + /// \brief Specify whether we should be recording paths or not. + void setRecordingPaths(bool RP) { RecordPaths = RP; } + + /// \brief Whether we are detecting virtual bases. + bool isDetectingVirtual() const { return DetectVirtual; } + + /// \brief The virtual base discovered on the path (if we are merely + /// detecting virtuals). + const RecordType* getDetectedVirtual() const { + return DetectedVirtual; + } + + /// \brief Retrieve the type from which this base-paths search + /// began + CXXRecordDecl *getOrigin() const { return Origin; } + void setOrigin(CXXRecordDecl *Rec) { Origin = Rec; } + + /// \brief Clear the base-paths results. + void clear(); + + /// \brief Swap this data structure's contents with another CXXBasePaths + /// object. + void swap(CXXBasePaths &Other); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h new file mode 100644 index 000000000000..d7ac76dd32e4 --- /dev/null +++ b/include/clang/AST/CanonicalType.h @@ -0,0 +1,721 @@ +//===-- CanonicalType.h - C Language Family Type Representation -*- 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 the CanQual class template, which provides access to +// canonical types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H +#define LLVM_CLANG_AST_CANONICAL_TYPE_H + +#include "clang/AST/Type.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/type_traits.h" +#include <iterator> + +namespace clang { + +template<typename T> class CanProxy; +template<typename T> struct CanProxyAdaptor; + +//----------------------------------------------------------------------------// +// Canonical, qualified type template +//----------------------------------------------------------------------------// + +/// \brief Represents a canonical, potentially-qualified type. +/// +/// The CanQual template is a lightweight smart pointer that provides access +/// to the canonical representation of a type, where all typedefs and other +/// syntactic sugar has been eliminated. A CanQualType may also have various +/// qualifiers (const, volatile, restrict) attached to it. +/// +/// The template type parameter @p T is one of the Type classes (PointerType, +/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that +/// type (or some subclass of that type). The typedef @c CanQualType is just +/// a shorthand for @c CanQual<Type>. +/// +/// An instance of @c CanQual<T> can be implicitly converted to a +/// @c CanQual<U> when T is derived from U, which essentially provides an +/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be +/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can +/// be implicitly converted to a QualType, but the reverse operation requires +/// a call to ASTContext::getCanonicalType(). +/// +/// +template<typename T = Type> +class CanQual { + /// \brief The actual, canonical type. + QualType Stored; + +public: + /// \brief Constructs a NULL canonical type. + CanQual() : Stored() { } + + /// \brief Converting constructor that permits implicit upcasting of + /// canonical type pointers. + template<typename U> + CanQual(const CanQual<U>& Other, + typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0); + + /// \brief Implicit conversion to the underlying pointer. + /// + /// Also provides the ability to use canonical types in a boolean context, + /// e.g., + /// @code + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } + /// @endcode + operator const T*() const { return getTypePtr(); } + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type. + T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); } + + /// \brief Implicit conversion to a qualified type. + operator QualType() const { return Stored; } + + /// \brief Retrieve a canonical type pointer with a different static type, + /// upcasting or downcasting as needed. + /// + /// The getAs() function is typically used to try to downcast to a + /// more specific (canonical) type in the type system. For example: + /// + /// @code + /// void f(CanQual<Type> T) { + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { + /// // look at Ptr's pointee type + /// } + /// } + /// @endcode + /// + /// \returns A proxy pointer to the same type, but with the specified + /// static type (@p U). If the dynamic type is not the specified static type + /// or a derived class thereof, a NULL canonical type. + template<typename U> CanProxy<U> getAs() const; + + /// \brief Overloaded arrow operator that produces a canonical type + /// proxy. + CanProxy<T> operator->() const; + + /// \brief Retrieve all qualifiers. + Qualifiers getQualifiers() const { return Stored.getQualifiers(); } + + /// \brief Retrieve the const/volatile/restrict qualifiers. + unsigned getCVRQualifiers() const { return Stored.getCVRQualifiers(); } + + /// \brief Determines whether this type has any qualifiers + bool hasQualifiers() const { return Stored.hasQualifiers(); } + + bool isConstQualified() const { + return Stored.isConstQualified(); + } + bool isVolatileQualified() const { + return Stored.isVolatileQualified(); + } + bool isRestrictQualified() const { + return Stored.isRestrictQualified(); + } + + /// \brief Retrieve the unqualified form of this type. + CanQual<T> getUnqualifiedType() const; + + CanQual<T> getQualifiedType(unsigned TQs) const { + return CanQual<T>::CreateUnsafe(QualType(getTypePtr(), TQs)); + } + + /// \brief Determines whether this canonical type is more qualified than + /// the @p Other canonical type. + bool isMoreQualifiedThan(CanQual<T> Other) const { + return Stored.isMoreQualifiedThan(Other.Stored); + } + + /// \brief Determines whether this canonical type is at least as qualified as + /// the @p Other canonical type. + bool isAtLeastAsQualifiedAs(CanQual<T> Other) const { + return Stored.isAtLeastAsQualifiedAs(Other.Stored); + } + + /// \brief If the canonical type is a reference type, returns the type that + /// it refers to; otherwise, returns the type itself. + CanQual<Type> getNonReferenceType() const; + + /// \brief Retrieve the internal representation of this canonical type. + void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); } + + /// \brief Construct a canonical type from its internal representation. + static CanQual<T> getFromOpaquePtr(void *Ptr); + + /// \brief Builds a canonical type from a QualType. + /// + /// This routine is inherently unsafe, because it requires the user to + /// ensure that the given type is a canonical type with the correct + // (dynamic) type. + static CanQual<T> CreateUnsafe(QualType Other); +}; + +template<typename T, typename U> +inline bool operator==(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() == y.getAsOpaquePtr(); +} + +template<typename T, typename U> +inline bool operator!=(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() != y.getAsOpaquePtr(); +} + +/// \brief Represents a canonical, potentially-qualified type. +typedef CanQual<Type> CanQualType; + +//----------------------------------------------------------------------------// +// Internal proxy classes used by canonical types +//----------------------------------------------------------------------------// + +#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \ +CanQualType Accessor() const { \ +return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \ +} + +#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \ +Type Accessor() const { return this->getTypePtr()->Accessor(); } + +/// \brief Base class of all canonical proxy types, which is responsible for +/// storing the underlying canonical type and providing basic conversions. +template<typename T> +class CanProxyBase { +protected: + CanQual<T> Stored; + +public: + /// \brief Retrieve the pointer to the underlying Type + T* getTypePtr() const { return Stored.getTypePtr(); } + + /// \brief Implicit conversion to the underlying pointer. + /// + /// Also provides the ability to use canonical type proxies in a Boolean + // context,e.g., + /// @code + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } + /// @endcode + operator const T*() const { return this->Stored.getTypePtr(); } + + /// \brief Try to convert the given canonical type to a specific structural + /// type. + template<typename U> CanProxy<U> getAs() const { + return this->Stored.template getAs<U>(); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass) + + // Type predicates + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType) + + /// \brief Retrieve the proxy-adaptor type. + /// + /// This arrow operator is used when CanProxyAdaptor has been specialized + /// for the given type T. In that case, we reference members of the + /// CanProxyAdaptor specialization. Otherwise, this operator will be hidden + /// by the arrow operator in the primary CanProxyAdaptor template. + const CanProxyAdaptor<T> *operator->() const { + return static_cast<const CanProxyAdaptor<T> *>(this); + } +}; + +/// \brief Replacable canonical proxy adaptor class that provides the link +/// between a canonical type and the accessors of the type. +/// +/// The CanProxyAdaptor is a replaceable class template that is instantiated +/// as part of each canonical proxy type. The primary template merely provides +/// redirection to the underlying type (T), e.g., @c PointerType. One can +/// provide specializations of this class template for each underlying type +/// that provide accessors returning canonical types (@c CanQualType) rather +/// than the more typical @c QualType, to propagate the notion of "canonical" +/// through the system. +template<typename T> +struct CanProxyAdaptor : CanProxyBase<T> { }; + +/// \brief Canonical proxy type returned when retrieving the members of a +/// canonical type or as the result of the @c CanQual<T>::getAs member +/// function. +/// +/// The CanProxy type mainly exists as a proxy through which operator-> will +/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy +/// type that provides canonical-type access to the fields of the type. +template<typename T> +class CanProxy : public CanProxyAdaptor<T> { +public: + /// \brief Build a NULL proxy. + CanProxy() { } + + /// \brief Build a proxy to the given canonical type. + CanProxy(CanQual<T> Stored) { this->Stored = Stored; } + + /// \brief Implicit conversion to the stored canonical type. + operator CanQual<T>() const { return this->Stored; } +}; + +} // end namespace clang + +namespace llvm { + +/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from +/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc. +/// to return smart pointer (proxies?). +template<typename T> +struct simplify_type<const ::clang::CanQual<T> > { + typedef T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) { + return Val.getTypePtr(); + } +}; +template<typename T> +struct simplify_type< ::clang::CanQual<T> > +: public simplify_type<const ::clang::CanQual<T> > {}; + +// Teach SmallPtrSet that CanQual<T> is "basically a pointer". +template<typename T> +class PointerLikeTypeTraits<clang::CanQual<T> > { +public: + static inline void *getAsVoidPointer(clang::CanQual<T> P) { + return P.getAsOpaquePtr(); + } + static inline clang::CanQual<T> getFromVoidPointer(void *P) { + return clang::CanQual<T>::getFromOpaquePtr(P); + } + // qualifier information is encoded in the low bits. + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +namespace clang { + +//----------------------------------------------------------------------------// +// Canonical proxy adaptors for canonical type nodes. +//----------------------------------------------------------------------------// + +/// \brief Iterator adaptor that turns an iterator over canonical QualTypes +/// into an iterator over CanQualTypes. +template<typename InputIterator> +class CanTypeIterator { + InputIterator Iter; + +public: + typedef CanQualType value_type; + typedef value_type reference; + typedef CanProxy<Type> pointer; + typedef typename std::iterator_traits<InputIterator>::difference_type + difference_type; + typedef typename std::iterator_traits<InputIterator>::iterator_category + iterator_category; + + CanTypeIterator() : Iter() { } + explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { } + + // Input iterator + reference operator*() const { + return CanQualType::CreateUnsafe(*Iter); + } + + pointer operator->() const; + + CanTypeIterator &operator++() { + ++Iter; + return *this; + } + + CanTypeIterator operator++(int) { + CanTypeIterator Tmp(*this); + ++Iter; + return Tmp; + } + + friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) { + return X.Iter == Y.Iter; + } + friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) { + return X.Iter != Y.Iter; + } + + // Bidirectional iterator + CanTypeIterator &operator--() { + --Iter; + return *this; + } + + CanTypeIterator operator--(int) { + CanTypeIterator Tmp(*this); + --Iter; + return Tmp; + } + + // Random access iterator + reference operator[](difference_type n) const { + return CanQualType::CreateUnsafe(Iter[n]); + } + + CanTypeIterator &operator+=(difference_type n) { + Iter += n; + return *this; + } + + CanTypeIterator &operator-=(difference_type n) { + Iter -= n; + return *this; + } + + friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) { + X += n; + return X; + } + + friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) { + X += n; + return X; + } + + friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) { + X -= n; + return X; + } + + friend difference_type operator-(const CanTypeIterator &X, + const CanTypeIterator &Y) { + return X - Y; + } +}; + +template<> +struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) +}; + +template<> +struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<BlockPointerType> + : public CanProxyBase<BlockPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<LValueReferenceType> + : public CanProxyBase<LValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<RValueReferenceType> + : public CanProxyBase<RValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<MemberPointerType> + : public CanProxyBase<MemberPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass) +}; + +template<> +struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor<ConstantArrayType> + : public CanProxyBase<ConstantArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) +}; + +template<> +struct CanProxyAdaptor<ConstantArrayWithExprType> + : public CanProxyBase<ConstantArrayWithExprType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) +}; + +template<> +struct CanProxyAdaptor<ConstantArrayWithoutExprType> + : public CanProxyBase<ConstantArrayWithoutExprType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) +}; + +template<> +struct CanProxyAdaptor<IncompleteArrayType> + : public CanProxyBase<IncompleteArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor<VariableArrayType> + : public CanProxyBase<VariableArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) +}; + +template<> +struct CanProxyAdaptor<DependentSizedArrayType> + : public CanProxyBase<DependentSizedArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) +}; + +template<> +struct CanProxyAdaptor<DependentSizedExtVectorType> + : public CanProxyBase<DependentSizedExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc) +}; + +template<> +struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor<FunctionNoProtoType> + : public CanProxyBase<FunctionNoProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) +}; + +template<> +struct CanProxyAdaptor<FunctionProtoType> + : public CanProxyBase<FunctionProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs); + CanQualType getArgType(unsigned i) const { + return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i)); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals) + + typedef CanTypeIterator<FunctionProtoType::arg_type_iterator> + arg_type_iterator; + + arg_type_iterator arg_type_begin() const { + return arg_type_iterator(this->getTypePtr()->arg_type_begin()); + } + + arg_type_iterator arg_type_end() const { + return arg_type_iterator(this->getTypePtr()->arg_type_end()); + } + + // Note: canonical function types never have exception specifications +}; + +template<> +struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace) +}; + +template<> +struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<TemplateTypeParmType> + : public CanProxyBase<TemplateTypeParmType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName) +}; + +template<> +struct CanProxyAdaptor<ObjCObjectPointerType> + : public CanProxyBase<ObjCObjectPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *, + getInterfaceType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +//----------------------------------------------------------------------------// +// Method and function definitions +//----------------------------------------------------------------------------// +template<typename T> +inline CanQual<T> CanQual<T>::getUnqualifiedType() const { + return CanQual<T>::CreateUnsafe(Stored.getUnqualifiedType()); +} + +template<typename T> +inline CanQual<Type> CanQual<T>::getNonReferenceType() const { + if (CanQual<ReferenceType> RefType = getAs<ReferenceType>()) + return RefType->getPointeeType(); + else + return *this; +} + +template<typename T> +CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) { + CanQual<T> Result; + Result.Stored.setFromOpaqueValue(Ptr); + assert((!Result || Result.Stored.isCanonical()) + && "Type is not canonical!"); + return Result; +} + +template<typename T> +CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) { + assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || isa<T>(Other.getTypePtr())) && + "Dynamic type does not meet the static type's requires"); + CanQual<T> Result; + Result.Stored = Other; + return Result; +} + +template<typename T> +template<typename U> +CanProxy<U> CanQual<T>::getAs() const { + if (Stored.isNull()) + return CanProxy<U>(); + + if (isa<U>(Stored.getTypePtr())) + return CanQual<U>::CreateUnsafe(Stored); + + return CanProxy<U>(); +} + +template<typename T> +CanProxy<T> CanQual<T>::operator->() const { + return CanProxy<T>(*this); +} + +template<typename InputIterator> +typename CanTypeIterator<InputIterator>::pointer +CanTypeIterator<InputIterator>::operator->() const { + return CanProxy<Type>(*this); +} + +} + + +#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 69a52869d818..7c326dee338c 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -16,6 +16,7 @@ #include "clang/AST/APValue.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/Redeclarable.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" @@ -26,23 +27,45 @@ class Stmt; class CompoundStmt; class StringLiteral; class TemplateArgumentList; +class MemberSpecializationInfo; class FunctionTemplateSpecializationInfo; - +class TypeLoc; + +/// \brief A container of type source information. +/// +/// A client can read the relevant info using TypeLoc wrappers, e.g: +/// @code +/// TypeLoc TL = DeclaratorInfo->getTypeLoc(); +/// if (PointerLoc *PL = dyn_cast<PointerLoc>(&TL)) +/// PL->getStarLoc().print(OS, SrcMgr); +/// @endcode +/// +class DeclaratorInfo { + QualType Ty; + // Contains a memory block after the class, used for type source information, + // allocated by ASTContext. + friend class ASTContext; + DeclaratorInfo(QualType ty) : Ty(ty) { } +public: + /// \brief Return the TypeLoc wrapper for the type source info. + TypeLoc getTypeLoc() const; +}; + /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { ASTContext &Ctx; - + explicit TranslationUnitDecl(ASTContext &ctx) : Decl(TranslationUnit, 0, SourceLocation()), DeclContext(TranslationUnit), Ctx(ctx) {} public: ASTContext &getASTContext() const { return Ctx; } - + static TranslationUnitDecl *Create(ASTContext &C); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; } - static bool classof(const TranslationUnitDecl *D) { return true; } + static bool classof(const TranslationUnitDecl *D) { return true; } static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D)); } @@ -91,7 +114,7 @@ public: /// manipulation, so it should be called only when performance doesn't matter. /// For simple declarations, getNameAsCString() should suffice. std::string getNameAsString() const { return Name.getAsString(); } - + /// getQualifiedNameAsString - Returns human-readable qualified name for /// declaration, like A::B::i, for i being member of namespace A::B. /// If declaration is not member of context which can be named (record, @@ -99,6 +122,25 @@ public: /// Creating this name is expensive, so it should be called only when /// performance doesn't matter. std::string getQualifiedNameAsString() const; + std::string getQualifiedNameAsString(const PrintingPolicy &Policy) const; + + /// getNameForDiagnostic - Appends a human-readable name for this + /// declaration into the given string. + /// + /// This is the method invoked by Sema when displaying a NamedDecl + /// in a diagnostic. It does not necessarily produce the same + /// result as getNameAsString(); for example, class template + /// specializations are printed with their template arguments. + /// + /// TODO: use an API that doesn't require so many temporary strings + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + if (Qualified) + S += getQualifiedNameAsString(Policy); + else + S += getNameAsString(); + } /// declarationReplaces - Determine whether this declaration, if /// known to be well-formed within its context, will replace the @@ -118,7 +160,7 @@ public: const NamedDecl *getUnderlyingDecl() const { return const_cast<NamedDecl*>(this)->getUnderlyingDecl(); } - + static bool classof(const Decl *D) { return D->getKind() >= NamedFirst && D->getKind() <= NamedLast; } @@ -128,7 +170,7 @@ public: /// NamespaceDecl - Represent a C++ namespace. class NamespaceDecl : public NamedDecl, public DeclContext { SourceLocation LBracLoc, RBracLoc; - + // For extended namespace definitions: // // namespace A { int x; } @@ -139,7 +181,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext { // OrigNamespace points to the original namespace declaration. // OrigNamespace of the first namespace decl points to itself. NamespaceDecl *OrigNamespace, *NextNamespace; - + NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) { OrigNamespace = this; @@ -148,9 +190,20 @@ class NamespaceDecl : public NamedDecl, public DeclContext { public: static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id); - + virtual void Destroy(ASTContext& C); + // \brief Returns true if this is an anonymous namespace declaration. + // + // For example: + // namespace { + // ... + // }; + // q.v. C++ [namespace.unnamed] + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + NamespaceDecl *getNextNamespace() { return NextNamespace; } const NamespaceDecl *getNextNamespace() const { return NextNamespace; } void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } @@ -159,7 +212,9 @@ public: return OrigNamespace; } void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; } - + + virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; } + virtual SourceRange getSourceRange() const { return SourceRange(getLocation(), RBracLoc); } @@ -168,7 +223,7 @@ public: SourceLocation getRBracLoc() const { return RBracLoc; } void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; } void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; } - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == Namespace; } static bool classof(const NamespaceDecl *D) { return true; } @@ -180,20 +235,20 @@ public: } }; -/// ValueDecl - Represent the declaration of a variable (in which case it is +/// ValueDecl - Represent the declaration of a variable (in which case it is /// an lvalue) a function (in which case it is a function designator) or -/// an enum constant. +/// an enum constant. class ValueDecl : public NamedDecl { QualType DeclType; protected: ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName N, QualType T) + DeclarationName N, QualType T) : NamedDecl(DK, DC, L, N), DeclType(T) {} public: QualType getType() const { return DeclType; } void setType(QualType newType) { DeclType = newType; } - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= ValueFirst && D->getKind() <= ValueLast; @@ -201,6 +256,29 @@ public: static bool classof(const ValueDecl *D) { return true; } }; +/// \brief Represents a ValueDecl that came out of a declarator. +/// Contains type source information through DeclaratorInfo. +class DeclaratorDecl : public ValueDecl { + DeclaratorInfo *DeclInfo; + +protected: + DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, DeclaratorInfo *DInfo) + : ValueDecl(DK, DC, L, N, T), DeclInfo(DInfo) {} + +public: + DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; } + void setDeclaratorInfo(DeclaratorInfo *DInfo) { DeclInfo = DInfo; } + + SourceLocation getTypeSpecStartLoc() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= DeclaratorFirst && D->getKind() <= DeclaratorLast; + } + static bool classof(const DeclaratorDecl *D) { return true; } +}; + /// \brief Structure used to store a statement, the constant value to /// which it was evaluated (if any), and whether or not the statement /// is an integral constant expression (if known). @@ -222,9 +300,32 @@ struct EvaluatedStmt { APValue Evaluated; }; +// \brief Describes the kind of template specialization that a +// particular template specialization declaration represents. +enum TemplateSpecializationKind { + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + TSK_Undeclared = 0, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + TSK_ImplicitInstantiation, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + TSK_ExplicitSpecialization, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation declaration request + /// (C++0x [temp.explicit]). + TSK_ExplicitInstantiationDeclaration, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation definition request + /// (C++ [temp.explicit]). + TSK_ExplicitInstantiationDefinition +}; + /// VarDecl - An instance of this class is created to represent a variable /// declaration or definition. -class VarDecl : public ValueDecl { +class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { public: enum StorageClass { None, Auto, Register, Extern, Static, PrivateExtern @@ -236,81 +337,108 @@ public: /// It is illegal to call this function with SC == None. static const char *getStorageClassSpecifierString(StorageClass SC); +protected: + /// \brief Placeholder type used in Init to denote an unparsed C++ default + /// argument. + struct UnparsedDefaultArgument; + + /// \brief Placeholder type used in Init to denote an uninstantiated C++ + /// default argument. + struct UninstantiatedDefaultArgument; + + typedef llvm::PointerUnion4<Stmt *, EvaluatedStmt *, + UnparsedDefaultArgument *, + UninstantiatedDefaultArgument *> InitType; + + /// \brief The initializer for this variable or, for a ParmVarDecl, the + /// C++ default argument. + mutable InitType Init; + private: - mutable llvm::PointerUnion<Stmt *, EvaluatedStmt *> Init; // FIXME: This can be packed into the bitfields in Decl. unsigned SClass : 3; bool ThreadSpecified : 1; - bool HasCXXDirectInit : 1; + bool HasCXXDirectInit : 1; /// DeclaredInCondition - Whether this variable was declared in a /// condition, e.g., if (int x = foo()) { ... }. bool DeclaredInCondition : 1; - /// \brief The previous declaration of this variable. - VarDecl *PreviousDeclaration; - - // Move to DeclGroup when it is implemented. - SourceLocation TypeSpecStartLoc; friend class StmtIteratorBase; protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, StorageClass SC, SourceLocation TSSL = SourceLocation()) - : ValueDecl(DK, DC, L, Id, T), Init(), + QualType T, DeclaratorInfo *DInfo, StorageClass SC) + : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), - DeclaredInCondition(false), PreviousDeclaration(0), - TypeSpecStartLoc(TSSL) { - SClass = SC; + DeclaredInCondition(false) { + SClass = SC; } + + typedef Redeclarable<VarDecl> redeclarable_base; + virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } + static VarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, StorageClass S, - SourceLocation TypeSpecStartLoc = SourceLocation()); + QualType T, DeclaratorInfo *DInfo, StorageClass S); virtual ~VarDecl(); virtual void Destroy(ASTContext& C); StorageClass getStorageClass() const { return (StorageClass)SClass; } void setStorageClass(StorageClass SC) { SClass = SC; } - - virtual SourceRange getSourceRange() const; - SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; } - void setTypeSpecStartLoc(SourceLocation SL) { - TypeSpecStartLoc = SL; - } + virtual SourceRange getSourceRange() const; - const Expr *getInit() const { + const Expr *getInit() const { if (Init.isNull()) return 0; const Stmt *S = Init.dyn_cast<Stmt *>(); - if (!S) - S = Init.get<EvaluatedStmt *>()->Value; - - return (const Expr*) S; + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + S = ES->Value; + } + return (const Expr*) S; } - Expr *getInit() { + Expr *getInit() { if (Init.isNull()) return 0; Stmt *S = Init.dyn_cast<Stmt *>(); - if (!S) - S = Init.get<EvaluatedStmt *>()->Value; + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + S = ES->Value; + } - return (Expr*) S; + return (Expr*) S; } /// \brief Retrieve the address of the initializer expression. Stmt **getInitAddress() { - if (Init.is<Stmt *>()) - return reinterpret_cast<Stmt **>(&Init); // FIXME: ugly hack - return &Init.get<EvaluatedStmt *>()->Value; + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + return &ES->Value; + + // This union hack tip-toes around strict-aliasing rules. + union { + InitType *InitPtr; + Stmt **StmtPtr; + }; + + InitPtr = &Init; + return StmtPtr; } void setInit(ASTContext &C, Expr *I); - + /// \brief Note that constant evaluation has computed the given /// value for this variable's initializer. void setEvaluatedValue(ASTContext &C, const APValue &Value) const { @@ -325,7 +453,7 @@ public: Eval->WasEvaluated = true; Eval->Evaluated = Value; } - + /// \brief Return the already-evaluated value of this variable's /// initializer, or NULL if the value is not yet known. APValue *getEvaluatedValue() const { @@ -350,7 +478,7 @@ public: /// /// \pre isInitKnownICE() bool isInitICE() const { - assert(isInitKnownICE() && + assert(isInitKnownICE() && "Check whether we already know that the initializer is an ICE"); return Init.get<EvaluatedStmt *>()->IsICE; } @@ -392,7 +520,7 @@ public: bool hasCXXDirectInitializer() const { return HasCXXDirectInit; } - + /// isDeclaredInCondition - Whether this variable was declared as /// part of a condition in an if/switch/while statement, e.g., /// @code @@ -401,27 +529,21 @@ public: bool isDeclaredInCondition() const { return DeclaredInCondition; } - void setDeclaredInCondition(bool InCondition) { - DeclaredInCondition = InCondition; + void setDeclaredInCondition(bool InCondition) { + DeclaredInCondition = InCondition; } - /// getPreviousDeclaration - Return the previous declaration of this - /// variable. - const VarDecl *getPreviousDeclaration() const { return PreviousDeclaration; } - - void setPreviousDeclaration(VarDecl *PrevDecl) { - PreviousDeclaration = PrevDecl; - } + virtual VarDecl *getCanonicalDecl(); /// hasLocalStorage - Returns true if a variable with function scope /// is a non-static local variable. bool hasLocalStorage() const { if (getStorageClass() == None) return !isFileVarDecl(); - + // Return true for: Auto, Register. // Return false for: Extern, Static, PrivateExtern. - + return getStorageClass() <= Register; } @@ -448,7 +570,7 @@ public: return DC->getLookupContext()->isFunctionOrMethod(); return false; } - + /// \brief Determines whether this is a static data member. /// /// This will only be true in C++, and applies to, e.g., the @@ -462,6 +584,24 @@ public: return getDeclContext()->isRecord(); } + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + VarDecl *getInstantiatedFromStaticDataMember(); + + /// \brief If this variable is a static data member, determine what kind of + /// template specialization or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind(); + + /// \brief If this variable is an instantiation of a static data member of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo(); + + /// \brief For a static data member that was instantiated from a static + /// data member of a class template, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + /// isFileVarDecl - Returns true for file scoped variable declaration. bool isFileVarDecl() const { if (getKind() != Decl::Var) @@ -471,16 +611,19 @@ public: if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) ) return true; } + if (isStaticDataMember()) + return true; + return false; } /// \brief Determine whether this is a tentative definition of a /// variable in C. bool isTentativeDefinition(ASTContext &Context) const; - + /// \brief Determines whether this variable is a variable with /// external, C linkage. - bool isExternC(ASTContext &Context) const; + bool isExternC() const; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { @@ -492,12 +635,12 @@ public: class ImplicitParamDecl : public VarDecl { protected: ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType Tw) - : VarDecl(DK, DC, L, Id, Tw, VarDecl::None) {} + IdentifierInfo *Id, QualType Tw) + : VarDecl(DK, DC, L, Id, Tw, /*DInfo=*/0, VarDecl::None) {} public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T); + SourceLocation L, IdentifierInfo *Id, + QualType T); // Implement isa/cast/dyncast/etc. static bool classof(const ImplicitParamDecl *D) { return true; } static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; } @@ -509,44 +652,72 @@ class ParmVarDecl : public VarDecl { /// FIXME: Also can be paced into the bitfields in Decl. /// in, inout, etc. unsigned objcDeclQualifier : 6; - - /// Default argument, if any. [C++ Only] - Expr *DefaultArg; + + /// \brief Retrieves the fake "value" of an unparsed + static Expr *getUnparsedDefaultArgValue() { + uintptr_t Value = (uintptr_t)-1; + // Mask off the low bits + Value &= ~(uintptr_t)0x07; + return reinterpret_cast<Expr*> (Value); + } + protected: ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, StorageClass S, - Expr *DefArg) - : VarDecl(DK, DC, L, Id, T, S), - objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {} + IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + StorageClass S, Expr *DefArg) + : VarDecl(DK, DC, L, Id, T, DInfo, S), objcDeclQualifier(OBJC_TQ_None) { + setDefaultArg(DefArg); + } public: static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,IdentifierInfo *Id, - QualType T, StorageClass S, Expr *DefArg); - + QualType T, DeclaratorInfo *DInfo, + StorageClass S, Expr *DefArg); + ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(objcDeclQualifier); } void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { objcDeclQualifier = QTVal; } - - const Expr *getDefaultArg() const { + + const Expr *getDefaultArg() const { assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); - return DefaultArg; + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + return getInit(); } - Expr *getDefaultArg() { + Expr *getDefaultArg() { assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); - return DefaultArg; + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + return getInit(); + } + void setDefaultArg(Expr *defarg) { + Init = reinterpret_cast<Stmt *>(defarg); + } + + /// \brief Retrieve the source range that covers the entire default + /// argument. + SourceRange getDefaultArgRange() const; + void setUninstantiatedDefaultArg(Expr *arg) { + Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg); + } + Expr *getUninstantiatedDefaultArg() { + return (Expr *)Init.get<UninstantiatedDefaultArgument *>(); + } + const Expr *getUninstantiatedDefaultArg() const { + return (const Expr *)Init.get<UninstantiatedDefaultArgument *>(); } - void setDefaultArg(Expr *defarg) { DefaultArg = defarg; } /// hasDefaultArg - Determines whether this parameter has a default argument, /// either parsed or not. bool hasDefaultArg() const { - return DefaultArg != 0; + return getInit() || hasUnparsedDefaultArg() || + hasUninstantiatedDefaultArg(); } - + /// hasUnparsedDefaultArg - Determines whether this parameter has a /// default argument that has not yet been parsed. This will occur /// during the processing of a C++ class whose member functions have @@ -558,7 +729,11 @@ public: /// }; // x has a regular default argument now /// @endcode bool hasUnparsedDefaultArg() const { - return DefaultArg == reinterpret_cast<Expr *>(-1); + return Init.is<UnparsedDefaultArgument*>(); + } + + bool hasUninstantiatedDefaultArg() const { + return Init.is<UninstantiatedDefaultArgument*>(); } /// setUnparsedDefaultArg - Specify that this parameter has an @@ -566,10 +741,12 @@ public: /// real default argument via setDefaultArg when the class /// definition enclosing the function declaration that owns this /// default argument is completed. - void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); } + void setUnparsedDefaultArg() { + Init = (UnparsedDefaultArgument *)0; + } QualType getOriginalType() const; - + /// setOwningFunction - Sets the function declaration that owns this /// ParmVarDecl. Since ParmVarDecls are often created before the /// FunctionDecls that own them, this routine is required to update @@ -577,9 +754,9 @@ public: void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return (D->getKind() == ParmVar || - D->getKind() == OriginalParmVar); + D->getKind() == OriginalParmVar); } static bool classof(const ParmVarDecl *D) { return true; } }; @@ -594,15 +771,17 @@ protected: QualType OriginalType; private: OriginalParmVarDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, + IdentifierInfo *Id, QualType T, + DeclaratorInfo *DInfo, QualType OT, StorageClass S, Expr *DefArg) - : ParmVarDecl(OriginalParmVar, DC, L, Id, T, S, DefArg), OriginalType(OT) {} + : ParmVarDecl(OriginalParmVar, DC, L, Id, T, DInfo, S, DefArg), + OriginalType(OT) {} public: static OriginalParmVarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,IdentifierInfo *Id, - QualType T, QualType OT, - StorageClass S, Expr *DefArg); + QualType T, DeclaratorInfo *DInfo, + QualType OT, StorageClass S, Expr *DefArg); void setOriginalType(QualType T) { OriginalType = T; } @@ -610,9 +789,9 @@ public: static bool classof(const Decl *D) { return D->getKind() == OriginalParmVar; } static bool classof(const OriginalParmVarDecl *D) { return true; } }; - + /// FunctionDecl - An instance of this class is created to represent a -/// function declaration or definition. +/// function declaration or definition. /// /// Since a given function can be declared several times in a program, /// there may be several FunctionDecls that correspond to that @@ -621,46 +800,35 @@ public: /// FunctionDecl (e.g., the translation unit); this FunctionDecl /// contains all of the information known about the function. Other, /// previous declarations of the function are available via the -/// getPreviousDeclaration() chain. -class FunctionDecl : public ValueDecl, public DeclContext { +/// getPreviousDeclaration() chain. +class FunctionDecl : public DeclaratorDecl, public DeclContext, + public Redeclarable<FunctionDecl> { public: enum StorageClass { None, Extern, Static, PrivateExtern }; - -private: + +private: /// 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. ParmVarDecl **ParamInfo; - + LazyDeclStmtPtr Body; - - /// PreviousDeclaration - A link to the previous declaration of this - /// same function, NULL if this is the first declaration. For - /// example, in the following code, the PreviousDeclaration can be - /// traversed several times to see all three declarations of the - /// function "f", the last of which is also a definition. - /// - /// int f(int x, int y = 1); - /// int f(int x = 0, int y); - /// int f(int x, int y) { return x + y; } - FunctionDecl *PreviousDeclaration; // FIXME: This can be packed into the bitfields in Decl. // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum unsigned SClass : 2; bool IsInline : 1; - bool C99InlineDefinition : 1; bool IsVirtualAsWritten : 1; bool IsPure : 1; bool HasInheritedPrototype : 1; bool HasWrittenPrototype : 1; bool IsDeleted : 1; + bool IsTrivial : 1; // sunk from CXXMethodDecl + bool IsCopyAssignment : 1; // sunk from CXXMethodDecl + bool HasImplicitReturnZero : 1; - // Move to DeclGroup when it is implemented. - SourceLocation TypeSpecStartLoc; - /// \brief End part of this FunctionDecl's source range. /// /// We could compute the full range in getSourceRange(). However, when we're @@ -672,42 +840,59 @@ private: /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. - /// + /// /// For non-templates, this value will be NULL. For function /// declarations that describe a function template, this will be a /// pointer to a FunctionTemplateDecl. For member functions - /// of class template specializations, this will be the - /// FunctionDecl from which the member function was instantiated. - /// For function template specializations, this will be a + /// of class template specializations, this will be a MemberSpecializationInfo + /// pointer containing information about the specialization. + /// For function template specializations, this will be a /// FunctionTemplateSpecializationInfo, which contains information about - /// the template being specialized and the template arguments involved in + /// the template being specialized and the template arguments involved in /// that specialization. - llvm::PointerUnion3<FunctionTemplateDecl*, FunctionDecl*, - FunctionTemplateSpecializationInfo*> + llvm::PointerUnion3<FunctionTemplateDecl *, + MemberSpecializationInfo *, + FunctionTemplateSpecializationInfo *> TemplateOrSpecialization; protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName N, QualType T, - StorageClass S, bool isInline, - SourceLocation TSSL = SourceLocation()) - : ValueDecl(DK, DC, L, N, T), + DeclarationName N, QualType T, DeclaratorInfo *DInfo, + StorageClass S, bool isInline) + : DeclaratorDecl(DK, DC, L, N, T, DInfo), DeclContext(DK), - ParamInfo(0), Body(), PreviousDeclaration(0), - SClass(S), IsInline(isInline), C99InlineDefinition(false), - IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), - HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL), + ParamInfo(0), Body(), + SClass(S), IsInline(isInline), + IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), + HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), + IsCopyAssignment(false), + HasImplicitReturnZero(false), EndRangeLoc(L), TemplateOrSpecialization() {} virtual ~FunctionDecl() {} virtual void Destroy(ASTContext& C); + typedef Redeclarable<FunctionDecl> redeclarable_base; + virtual FunctionDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - DeclarationName N, QualType T, + DeclarationName N, QualType T, + DeclaratorInfo *DInfo, StorageClass S = None, bool isInline = false, - bool hasWrittenPrototype = true, - SourceLocation TSStartLoc = SourceLocation()); + bool hasWrittenPrototype = true); + + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const; virtual SourceRange getSourceRange() const { return SourceRange(getLocation(), EndRangeLoc); @@ -715,9 +900,6 @@ public: void setLocEnd(SourceLocation E) { EndRangeLoc = E; } - - SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; } - void setTypeSpecStartLoc(SourceLocation TS) { TypeSpecStartLoc = TS; } /// getBody - Retrieve the body (definition) of the function. The /// function body might be in any of the (re-)declarations of this @@ -731,10 +913,6 @@ public: return getBody(Definition); } - /// \brief If the function has a body that is immediately available, - /// return it. - Stmt *getBodyIfAvailable() const; - /// isThisDeclarationADefinition - Returns whether this specific /// declaration of the function is also a definition. This does not /// determine whether the function has been defined (e.g., in a @@ -755,14 +933,30 @@ public: bool isPure() const { return IsPure; } void setPure(bool P = true) { IsPure = P; } + /// Whether this function is "trivial" in some specialized C++ senses. + /// Can only be true for default constructors, copy constructors, + /// copy assignment operators, and destructors. Not meaningful until + /// the class has been fully built by Sema. + bool isTrivial() const { return IsTrivial; } + void setTrivial(bool IT) { IsTrivial = IT; } + + bool isCopyAssignment() const { return IsCopyAssignment; } + void setCopyAssignment(bool CA) { IsCopyAssignment = CA; } + + /// Whether falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + bool hasImplicitReturnZero() const { return HasImplicitReturnZero; } + void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } + /// \brief Whether this function has a prototype, either because one /// was explicitly written or because it was "inherited" by merging /// a declaration without a prototype with a declaration that has a /// prototype. - bool hasPrototype() const { - return HasWrittenPrototype || HasInheritedPrototype; + bool hasPrototype() const { + return HasWrittenPrototype || HasInheritedPrototype; } - + bool hasWrittenPrototype() const { return HasWrittenPrototype; } void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; } @@ -798,39 +992,36 @@ public: /// \brief Determines whether this function is a function with /// external, C linkage. - bool isExternC(ASTContext &Context) const; + bool isExternC() const; /// \brief Determines whether this is a global function. bool isGlobal() const; - /// getPreviousDeclaration - Return the previous declaration of this - /// function. - const FunctionDecl *getPreviousDeclaration() const { - return PreviousDeclaration; - } - void setPreviousDeclaration(FunctionDecl * PrevDecl); - unsigned getBuiltinID(ASTContext &Context) const; + virtual const FunctionDecl *getCanonicalDecl() const; + virtual FunctionDecl *getCanonicalDecl(); + + unsigned getBuiltinID() const; unsigned getNumParmVarDeclsFromType() const; - + // Iterator access to formal parameters. unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; typedef ParmVarDecl * const *param_const_iterator; - + param_iterator param_begin() { return ParamInfo; } param_iterator param_end() { return ParamInfo+param_size(); } - + param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_size(); } - + /// getNumParams - Return the number of parameters this function must have /// based on its functiontype. This is the length of the PararmInfo array /// after it has been created. unsigned getNumParams() const; - + const ParmVarDecl *getParamDecl(unsigned i) const { assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; @@ -847,8 +1038,8 @@ public: /// arguments (in C++). unsigned getMinRequiredArguments() const; - QualType getResultType() const { - return getType()->getAsFunctionType()->getResultType(); + QualType getResultType() const { + return getType()->getAs<FunctionType>()->getResultType(); } StorageClass getStorageClass() const { return StorageClass(SClass); } void setStorageClass(StorageClass SC) { SClass = SC; } @@ -856,27 +1047,11 @@ public: bool isInline() const { return IsInline; } void setInline(bool I) { IsInline = I; } - /// \brief Whether this function is an "inline definition" as - /// defined by C99. - bool isC99InlineDefinition() const { return C99InlineDefinition; } - void setC99InlineDefinition(bool I) { C99InlineDefinition = I; } - - /// \brief Determines whether this function has a gnu_inline - /// attribute that affects its semantics. - /// - /// The gnu_inline attribute only introduces GNU inline semantics - /// when all of the inline declarations of the function are marked - /// gnu_inline. - bool hasActiveGNUInlineAttribute(ASTContext &Context) const; - - /// \brief Determines whether this function is a GNU "extern - /// inline", which is roughly the opposite of a C99 "extern inline" - /// function. - bool isExternGNUInline(ASTContext &Context) const; - + bool isInlineDefinitionExternallyVisible() const; + /// isOverloadedOperator - Whether this function declaration /// represents an C++ overloaded operator, e.g., "operator+". - bool isOverloadedOperator() const { + bool isOverloadedOperator() const { return getOverloadedOperator() != OO_None; }; @@ -903,15 +1078,17 @@ public: /// the FunctionDecl X<T>::A. When a complete definition of /// X<int>::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberFunction(). - FunctionDecl *getInstantiatedFromMemberFunction() const { - return TemplateOrSpecialization.dyn_cast<FunctionDecl*>(); - } + FunctionDecl *getInstantiatedFromMemberFunction() const; + /// \brief If this function is an instantiation of a member function of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + /// \brief Specify that this record is an instantiation of the - /// member function RD. - void setInstantiationOfMemberFunction(FunctionDecl *RD) { - TemplateOrSpecialization = RD; - } + /// member function FD. + void setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK); /// \brief Retrieves the function template that is described by this /// function declaration. @@ -933,20 +1110,34 @@ public: TemplateOrSpecialization = Template; } + /// \brief Determine whether this function is a function template + /// specialization. + bool isFunctionTemplateSpecialization() const { + return getPrimaryTemplate() != 0; + } + + /// \brief If this function is actually a function template specialization, + /// retrieve information about this function template specialization. + /// Otherwise, returns NULL. + FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const { + return TemplateOrSpecialization. + dyn_cast<FunctionTemplateSpecializationInfo*>(); + } + /// \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; - + /// \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; - + const TemplateArgumentList *getTemplateSpecializationArgs() const; + /// \brief Specify that this function declaration is actually a function /// template specialization. /// @@ -957,19 +1148,30 @@ public: /// /// \param TemplateArgs the template arguments that produced this /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. void setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, - void *InsertPos); + void *InsertPos, + TemplateSpecializationKind TSK = TSK_ImplicitInstantiation); - /// \brief Determine whether this is an explicit specialization of a - /// function template or a member function of a class template. - bool isExplicitSpecialization() const; + /// \brief Determine what kind of template instantiation this function + /// represents. + TemplateSpecializationKind getTemplateSpecializationKind() const; - /// \brief Note that this is an explicit specialization of a function template - /// or a member function of a class template. - void setExplicitSpecialization(bool ES); - + /// \brief Determine what kind of template instantiation this function + /// represents. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a member function. + bool isOutOfLine() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; @@ -984,22 +1186,23 @@ public: }; -/// FieldDecl - An instance of this class is created by Sema::ActOnField to +/// FieldDecl - An instance of this class is created by Sema::ActOnField to /// represent a member of a struct/union/class. -class FieldDecl : public ValueDecl { +class FieldDecl : public DeclaratorDecl { // FIXME: This can be packed into the bitfields in Decl. bool Mutable : 1; Expr *BitWidth; protected: - FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, Expr *BW, bool Mutable) - : ValueDecl(DK, DC, L, Id, T), Mutable(Mutable), BitWidth(BW) - { } + FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + Expr *BW, bool Mutable) + : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Mutable(Mutable), BitWidth(BW) { + } public: - static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, Expr *BW, - bool Mutable); + static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + DeclaratorInfo *DInfo, Expr *BW, bool Mutable); /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } @@ -1049,7 +1252,7 @@ public: SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E, const llvm::APSInt &V); - + virtual void Destroy(ASTContext& C); const Expr *getInitExpr() const { return (const Expr*) Init; } @@ -1058,11 +1261,11 @@ public: void setInitExpr(Expr *E) { Init = (Stmt*) E; } void setInitVal(const llvm::APSInt &V) { Val = V; } - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == EnumConstant; } static bool classof(const EnumConstantDecl *D) { return true; } - + friend class StmtIteratorBase; }; @@ -1104,16 +1307,16 @@ class TypedefDecl : public TypeDecl { /// UnderlyingType - This is the type the typedef is set to. QualType UnderlyingType; TypedefDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T) + IdentifierInfo *Id, QualType T) : TypeDecl(Typedef, DC, L, Id), UnderlyingType(T) {} virtual ~TypedefDecl() {} public: - + static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,IdentifierInfo *Id, QualType T); - + QualType getUnderlyingType() const { return UnderlyingType; } void setUnderlyingType(QualType newType) { UnderlyingType = newType; } @@ -1123,16 +1326,17 @@ public: }; class TypedefDecl; - + /// TagDecl - Represents the declaration of a struct/union/class/enum. -class TagDecl : public TypeDecl, public DeclContext { +class TagDecl + : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { public: - enum TagKind { - TK_struct, - TK_union, - TK_class, - TK_enum - }; + // This is really ugly. + typedef ElaboratedType::TagKind TagKind; + static const TagKind TK_struct = ElaboratedType::TK_struct; + static const TagKind TK_union = ElaboratedType::TK_union; + static const TagKind TK_class = ElaboratedType::TK_class; + static const TagKind TK_enum = ElaboratedType::TK_enum; private: // FIXME: This can be packed into the bitfields in Decl. @@ -1142,21 +1346,48 @@ private: /// IsDefinition - True if this is a definition ("struct foo {};"), false if /// it is a declaration ("struct foo;"). bool IsDefinition : 1; - + /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef, /// this points to the TypedefDecl. Used for mangling. TypedefDecl *TypedefForAnonDecl; - + + SourceLocation TagKeywordLoc; + SourceLocation RBraceLoc; + protected: TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id) - : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0) { + IdentifierInfo *Id, TagDecl *PrevDecl, + SourceLocation TKL = SourceLocation()) + : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0), + TagKeywordLoc(TKL) { assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum"); TagDeclKind = TK; IsDefinition = false; + setPreviousDeclaration(PrevDecl); } + + typedef Redeclarable<TagDecl> redeclarable_base; + virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + public: - + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } + + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + SourceLocation getTagKeywordLoc() const { return TagKeywordLoc; } + void setTagKeywordLoc(SourceLocation TKL) { TagKeywordLoc = TKL; } + + virtual SourceRange getSourceRange() const; + + virtual TagDecl* getCanonicalDecl(); + /// isDefinition - Return true if this decl has its body specified. bool isDefinition() const { return IsDefinition; @@ -1168,7 +1399,7 @@ public: bool isDependentType() const { return isDependentContext(); } /// @brief Starts the definition of this tag declaration. - /// + /// /// This method should be invoked at the beginning of the definition /// of this tag declaration. It will set the tag type into a state /// where it is in the process of being defined. @@ -1177,7 +1408,7 @@ public: /// @brief Completes the definition of this tag declaration. void completeDefinition(); - /// getDefinition - Returns the TagDecl that actually defines this + /// getDefinition - Returns the TagDecl that actually defines this /// struct/union/class/enum. When determining whether or not a /// struct/union/class/enum is completely defined, one should use this method /// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a @@ -1185,17 +1416,16 @@ public: /// struct/union/class/enum type is defined. This method returns NULL if /// there is no TagDecl that defines the struct/union/class/enum. TagDecl* getDefinition(ASTContext& C) const; - + const char *getKindName() const { - switch (getTagKind()) { - default: assert(0 && "Unknown TagKind!"); - case TK_struct: return "struct"; - case TK_union: return "union"; - case TK_class: return "class"; - case TK_enum: return "enum"; - } + return ElaboratedType::getNameForTagKind(getTagKind()); } + /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into a tag kind. It is an error to provide a type specifier + /// which *isn't* a tag kind here. + static TagKind getTagKindForTypeSpec(unsigned TypeSpec); + TagKind getTagKind() const { return TagKind(TagDeclKind); } @@ -1206,10 +1436,10 @@ public: bool isClass() const { return getTagKind() == TK_class; } bool isUnion() const { return getTagKind() == TK_union; } bool isEnum() const { return getTagKind() == TK_enum; } - + TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; } void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; } - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= TagFirst && D->getKind() <= TagLast; @@ -1240,15 +1470,19 @@ class EnumDecl : public TagDecl { EnumDecl *InstantiatedFrom; EnumDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id) - : TagDecl(Enum, TK_enum, DC, L, Id), InstantiatedFrom(0) { + IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL) + : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) { IntegerType = QualType(); } public: + EnumDecl *getCanonicalDecl() { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + static EnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - EnumDecl *PrevDecl); - + SourceLocation TKL, EnumDecl *PrevDecl); + virtual void Destroy(ASTContext& C); /// completeDefinition - When created, the EnumDecl corresponds to a @@ -1257,16 +1491,16 @@ public: /// added (via DeclContext::addDecl). NewType is the new underlying /// type of the enumeration type. void completeDefinition(ASTContext &C, QualType NewType); - + // enumerator_iterator - Iterates through the enumerators of this // enumeration. typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; - enumerator_iterator enumerator_begin() const { + enumerator_iterator enumerator_begin() const { return enumerator_iterator(this->decls_begin()); } - enumerator_iterator enumerator_end() const { + enumerator_iterator enumerator_end() const { return enumerator_iterator(this->decls_end()); } @@ -1307,18 +1541,24 @@ class RecordDecl : public TagDecl { /// anonymous struct or union. bool AnonymousStructOrUnion : 1; + /// HasObjectMember - This is true if this struct has at least one + /// member containing an object + bool HasObjectMember : 1; + protected: RecordDecl(Kind DK, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id); + SourceLocation L, IdentifierInfo *Id, + RecordDecl *PrevDecl, SourceLocation TKL); virtual ~RecordDecl(); public: static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation TKL = SourceLocation(), RecordDecl* PrevDecl = 0); virtual void Destroy(ASTContext& C); - + bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } @@ -1328,7 +1568,7 @@ public: /// type declared, e.g., /// @code /// union { int i; float f; }; - /// @endcode + /// @endcode /// is an anonymous union but neither of the following are: /// @code /// union X { int i; float f; }; @@ -1339,6 +1579,9 @@ public: AnonymousStructOrUnion = Anon; } + bool hasObjectMember() const { return HasObjectMember; } + void setHasObjectMember (bool val) { HasObjectMember = val; } + /// \brief Determines whether this declaration represents the /// injected class name. /// @@ -1354,7 +1597,7 @@ public: /// \endcode bool isInjectedClassName() const; - /// getDefinition - Returns the RecordDecl that actually defines this + /// getDefinition - Returns the RecordDecl that actually defines this /// struct/union/class. When determining whether or not a struct/union/class /// is completely defined, one should use this method as opposed to /// 'isDefinition'. 'isDefinition' indicates whether or not a specific @@ -1364,7 +1607,7 @@ public: RecordDecl* getDefinition(ASTContext& C) const { return cast_or_null<RecordDecl>(TagDecl::getDefinition(C)); } - + // Iterator access to field members. The field iterator only visits // the non-static data members of this class, ignoring any static // data members, functions, constructors, destructors, etc. @@ -1379,7 +1622,7 @@ public: // field_empty - Whether there are any fields (non-static data // members) in this record. - bool field_empty() const { + bool field_empty() const { return field_begin() == field_end(); } @@ -1408,7 +1651,7 @@ public: static bool classof(const Decl *D) { return D->getKind() == FileScopeAsm; } - static bool classof(const FileScopeAsmDecl *D) { return true; } + static bool classof(const FileScopeAsmDecl *D) { return true; } }; /// BlockDecl - This represents a block literal declaration, which is like an @@ -1423,12 +1666,12 @@ class BlockDecl : public Decl, public DeclContext { /// no formals. ParmVarDecl **ParamInfo; unsigned NumParams; - + Stmt *Body; - + protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) - : Decl(Block, DC, CaretLoc), DeclContext(Block), + : Decl(Block, DC, CaretLoc), DeclContext(Block), isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {} virtual ~BlockDecl(); @@ -1441,7 +1684,7 @@ public: bool IsVariadic() const { return isVariadic; } void setIsVariadic(bool value) { isVariadic = value; } - + CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } Stmt *getBody() const { return (Stmt*) Body; } void setBody(CompoundStmt *B) { Body = (Stmt*) B; } @@ -1450,14 +1693,14 @@ public: unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; typedef ParmVarDecl * const *param_const_iterator; - + bool param_empty() const { return NumParams == 0; } param_iterator param_begin() { return ParamInfo; } param_iterator param_end() { return ParamInfo+param_size(); } - + param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_size(); } - + unsigned getNumParams() const; const ParmVarDecl *getParamDecl(unsigned i) const { assert(i < getNumParams() && "Illegal param #"); @@ -1468,10 +1711,10 @@ public: return ParamInfo[i]; } void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams); - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == Block; } - static bool classof(const BlockDecl *D) { return true; } + static bool classof(const BlockDecl *D) { return true; } static DeclContext *castToDeclContext(const BlockDecl *D) { return static_cast<DeclContext *>(const_cast<BlockDecl*>(D)); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 0bce2f84c7ba..9e88871565f1 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -37,6 +37,7 @@ class ObjCCategoryDecl; class ObjCProtocolDecl; class ObjCImplementationDecl; class ObjCCategoryImplDecl; +class ObjCImplDecl; class LinkageSpecDecl; class BlockDecl; class DeclarationName; @@ -59,8 +60,8 @@ public: namespace clang { -/// Decl - This represents one declaration (or definition), e.g. a variable, -/// typedef, function, struct, etc. +/// Decl - This represents one declaration (or definition), e.g. a variable, +/// typedef, function, struct, etc. /// class Decl { public: @@ -68,7 +69,7 @@ public: enum Kind { #define DECL(Derived, Base) Derived, #define DECL_RANGE(CommonBase, Start, End) \ - CommonBase##First = Start, CommonBase##Last = End, + CommonBase##First = Start, CommonBase##Last = End, #define LAST_DECL_RANGE(CommonBase, Start, End) \ CommonBase##First = Start, CommonBase##Last = End #include "clang/AST/DeclNodes.def" @@ -78,7 +79,9 @@ public: /// namespaces, labels, tags, members and ordinary /// identifiers. These are meant as bitmasks, so that searches in /// C++ can look into the "tag" namespace during ordinary lookup. We - /// use additional namespaces for Objective-C entities. + /// use additional namespaces for Objective-C entities. We also + /// put C++ friend declarations (of previously-undeclared entities) in + /// shadow namespaces. enum IdentifierNamespace { IDNS_Label = 0x1, IDNS_Tag = 0x2, @@ -86,9 +89,11 @@ public: IDNS_Ordinary = 0x8, IDNS_ObjCProtocol = 0x10, IDNS_ObjCImplementation = 0x20, - IDNS_ObjCCategoryImpl = 0x40 + IDNS_ObjCCategoryImpl = 0x40, + IDNS_OrdinaryFriend = 0x80, + IDNS_TagFriend = 0x100 }; - + /// ObjCDeclQualifier - Qualifier used on types in method declarations /// for remote messaging. They are meant for the arguments though and /// applied to the Decls (ObjCMethodDecl and ParmVarDecl). @@ -101,7 +106,7 @@ public: OBJC_TQ_Byref = 0x10, OBJC_TQ_Oneway = 0x20 }; - + private: /// NextDeclInContext - The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is @@ -114,8 +119,8 @@ private: DeclContext *SemanticDC; DeclContext *LexicalDC; }; - - + + /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the Decl was declared. @@ -139,16 +144,16 @@ private: inline DeclContext *getSemanticDC() const { return DeclCtx.get<DeclContext*>(); } - + /// Loc - The location that this decl. SourceLocation Loc; - + /// DeclKind - This indicates which class this is. Kind DeclKind : 8; - + /// InvalidDecl - This indicates a semantic error occurred. unsigned int InvalidDecl : 1; - + /// HasAttrs - This indicates whether the decl has attributes or not. unsigned int HasAttrs : 1; @@ -162,23 +167,23 @@ private: protected: /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. - unsigned IdentifierNamespace : 8; - + unsigned IdentifierNamespace : 16; + private: #ifndef NDEBUG void CheckAccessDeclContext() const; #else void CheckAccessDeclContext() const { } #endif - + protected: /// Access - Used by C++ decls for the access specifier. // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum unsigned Access : 2; friend class CXXClassMemberWrapper; - Decl(Kind DK, DeclContext *DC, SourceLocation L) - : NextDeclInContext(0), DeclCtx(DC), + Decl(Kind DK, DeclContext *DC, SourceLocation L) + : NextDeclInContext(0), DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) { @@ -201,7 +206,7 @@ public: Kind getKind() const { return DeclKind; } const char *getDeclKindName() const; - + Decl *getNextDeclInContext() { return NextDeclInContext; } const Decl *getNextDeclInContext() const { return NextDeclInContext; } @@ -219,16 +224,18 @@ public: return const_cast<Decl*>(this)->getTranslationUnitDecl(); } + bool isInAnonymousNamespace() const; + ASTContext &getASTContext() const; - + void setAccess(AccessSpecifier AS) { - Access = AS; + Access = AS; CheckAccessDeclContext(); } - - AccessSpecifier getAccess() const { + + AccessSpecifier getAccess() const { CheckAccessDeclContext(); - return AccessSpecifier(Access); + return AccessSpecifier(Access); } bool hasAttrs() const { return HasAttrs; } @@ -246,11 +253,11 @@ public: return V; return 0; } - + template<typename T> bool hasAttr() const { return getAttr<T>() != 0; } - + /// setInvalidDecl - Indicates the Decl had a semantic error. This /// allows for graceful error recovery. void setInvalidDecl(bool Invalid = true) { InvalidDecl = Invalid; } @@ -261,12 +268,12 @@ public: /// was written explicitly in the source code. bool isImplicit() const { return Implicit; } void setImplicit(bool I = true) { Implicit = I; } - + /// \brief Whether this declaration was used, meaning that a definition /// is required. bool isUsed() const { return Used; } void setUsed(bool U = true) { Used = U; } - + unsigned getIdentifierNamespace() const { return IdentifierNamespace; } @@ -275,7 +282,7 @@ public: } static unsigned getIdentifierNamespaceForKind(Kind DK); - + /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from /// getDeclContext() (SemanticDC). @@ -298,7 +305,7 @@ public: bool isOutOfLine() const { return getLexicalDeclContext() != getDeclContext(); } - + /// setDeclContext - Set both the semantic and lexical DeclContext /// to DC. void setDeclContext(DeclContext *DC); @@ -311,6 +318,72 @@ public: // be defined inside or outside a function etc). bool isDefinedOutsideFunctionOrMethod() const; + /// \brief Retrieves the "canonical" declaration of the given declaration. + virtual Decl *getCanonicalDecl() { return this; } + const Decl *getCanonicalDecl() const { + return const_cast<Decl*>(this)->getCanonicalDecl(); + } + + /// \brief Whether this particular Decl is a canonical one. + bool isCanonicalDecl() const { return getCanonicalDecl() == this; } + +protected: + /// \brief Returns the next redeclaration or itself if this is the only decl. + /// + /// Decl subclasses that can be redeclared should override this method so that + /// Decl::redecl_iterator can iterate over them. + virtual Decl *getNextRedeclaration() { return this; } + +public: + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + Decl *Current; + Decl *Starter; + + public: + typedef Decl* value_type; + typedef Decl* reference; + typedef Decl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + Decl *Next = Current->getNextRedeclaration(); + assert(Next && "Should return next redeclaration or itself, never null!"); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same decl. + /// It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast<Decl*>(this)); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + /// getBody - If this Decl represents a declaration for a body of code, /// such as a function or method definition, this method returns the /// top-level Stmt* of that body. Otherwise this method returns null. @@ -327,33 +400,71 @@ public: static void addDeclKind(Kind k); static bool CollectingStats(bool Enable = false); static void PrintStats(); - + /// isTemplateParameter - Determines whether this declaration is a /// template parameter. bool isTemplateParameter() const; - + /// isTemplateParameter - Determines whether this declaration is a /// template parameter pack. bool isTemplateParameterPack() const; /// \brief Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const; - + + /// \brief Changes the namespace of this declaration to reflect that it's + /// the object of a friend declaration. + /// + /// These declarations appear in the lexical context of the friending + /// class, but in the semantic context of the actual entity. This property + /// applies only to a specific decl object; other redeclarations of the + /// same entity may not (and probably don't) share this property. + void setObjectOfFriendDecl(bool PreviouslyDeclared) { + unsigned OldNS = IdentifierNamespace; + assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary || + OldNS == (IDNS_Tag | IDNS_Ordinary)) + && "unsupported namespace for undeclared friend"); + if (!PreviouslyDeclared) IdentifierNamespace = 0; + + if (OldNS == IDNS_Tag) + IdentifierNamespace |= IDNS_TagFriend; + else + IdentifierNamespace |= IDNS_OrdinaryFriend; + } + + enum FriendObjectKind { + FOK_None, // not a friend object + FOK_Declared, // a friend of a previously-declared entity + FOK_Undeclared // a friend of a previously-undeclared entity + }; + + /// \brief Determines whether this declaration is the object of a + /// friend declaration and, if so, what kind. + /// + /// There is currently no direct way to find the associated FriendDecl. + FriendObjectKind getFriendObjectKind() const { + unsigned mask + = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); + if (!mask) return FOK_None; + return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? + FOK_Declared : FOK_Undeclared); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *) { return true; } static DeclContext *castToDeclContext(const Decl *); static Decl *castFromDeclContext(const DeclContext *); - + /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - void print(llvm::raw_ostream &Out, unsigned Indentation = 0); + void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const; void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy, - unsigned Indentation = 0); + unsigned Indentation = 0) const; static void printGroup(Decl** Begin, unsigned NumDecls, llvm::raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); - void dump(); + void dump() const; private: const Attr *getAttrsImpl() const; @@ -371,10 +482,10 @@ public: PrettyStackTraceDecl(Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} - + virtual void print(llvm::raw_ostream &OS) const; -}; - +}; + /// DeclContext - This is used only as base class of specific decl types that /// can act as declaration contexts. These decls are (only the top classes @@ -386,8 +497,6 @@ public: /// TagDecl /// ObjCMethodDecl /// ObjCContainerDecl -/// ObjCCategoryImplDecl -/// ObjCImplementationDecl /// LinkageSpecDecl /// BlockDecl /// @@ -421,9 +530,9 @@ class DeclContext { mutable Decl *LastDecl; protected: - DeclContext(Decl::Kind K) + DeclContext(Decl::Kind K) : DeclKind(K), ExternalLexicalStorage(false), - ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0), + ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0), LastDecl(0) { } void DestroyDecls(ASTContext &C); @@ -443,7 +552,7 @@ public: const DeclContext *getParent() const { return const_cast<DeclContext*>(this)->getParent(); } - + /// getLexicalParent - Returns the containing lexical DeclContext. May be /// different from getParent, e.g.: /// @@ -458,8 +567,14 @@ public: } const DeclContext *getLexicalParent() const { return const_cast<DeclContext*>(this)->getLexicalParent(); - } + } + DeclContext *getLookupParent(); + + const DeclContext *getLookupParent() const { + return const_cast<DeclContext*>(this)->getLookupParent(); + } + ASTContext &getParentASTContext() const { return cast<Decl>(this)->getASTContext(); } @@ -499,10 +614,10 @@ public: /// context are semantically declared in the nearest enclosing /// non-transparent (opaque) context but are lexically declared in /// this context. For example, consider the enumerators of an - /// enumeration type: + /// enumeration type: /// @code /// enum E { - /// Val1 + /// Val1 /// }; /// @endcode /// Here, E is a transparent context, so its enumerator (Val1) will @@ -512,13 +627,16 @@ public: /// inline namespaces. bool isTransparentContext() const; - bool Encloses(DeclContext *DC) const { - for (; DC; DC = DC->getParent()) - if (DC == this) - return true; - return false; + /// \brief Determine whether this declaration context is equivalent + /// to the declaration context DC. + bool Equals(DeclContext *DC) { + return this->getPrimaryContext() == DC->getPrimaryContext(); } + /// \brief Determine whether this declaration context encloses the + /// declaration context DC. + bool Encloses(DeclContext *DC); + /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with @@ -535,7 +653,7 @@ public: const DeclContext *getLookupContext() const { return const_cast<DeclContext *>(this)->getLookupContext(); } - + /// \brief Retrieve the nearest enclosing namespace context. DeclContext *getEnclosingNamespaceContext(); const DeclContext *getEnclosingNamespaceContext() const { @@ -591,16 +709,16 @@ public: return tmp; } - friend bool operator==(decl_iterator x, decl_iterator y) { + friend bool operator==(decl_iterator x, decl_iterator y) { return x.Current == y.Current; } - friend bool operator!=(decl_iterator x, decl_iterator y) { + friend bool operator!=(decl_iterator x, decl_iterator y) { return x.Current != y.Current; } }; /// decls_begin/decls_end - Iterate over the declarations stored in - /// this context. + /// this context. decl_iterator decls_begin() const; decl_iterator decls_end() const; bool decls_empty() const; @@ -616,7 +734,7 @@ public: /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; - + /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. @@ -661,13 +779,13 @@ public: ++(*this); return tmp; } - + friend bool operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current == y.Current; } - - friend bool + + friend bool operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current != y.Current; } @@ -688,7 +806,7 @@ public: /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; - + /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. @@ -735,13 +853,13 @@ public: ++(*this); return tmp; } - + friend bool operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current == y.Current; } - - friend bool + + friend bool operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current != y.Current; } @@ -761,6 +879,14 @@ public: /// semantic context via makeDeclVisibleInContext. void addDecl(Decl *D); + /// @brief Add the declaration D to this context without modifying + /// any lookup tables. + /// + /// This is useful for some operations in dependent contexts where + /// the semantic context might not be dependent; this basically + /// only happens with friends. + void addHiddenDecl(Decl *D); + /// lookup_iterator - An iterator that provides access to the results /// of looking up a name within this context. typedef NamedDecl **lookup_iterator; @@ -795,12 +921,16 @@ public: /// visible from this context, as determined by /// NamedDecl::declarationReplaces, the previous declaration will be /// replaced with D. - void makeDeclVisibleInContext(NamedDecl *D); + /// + /// @param Recoverable true if it's okay to not add this decl to + /// the lookup tables because it can be easily recovered by walking + /// the declaration chains. + void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true); /// udir_iterator - Iterates through the using-directives stored /// within this context. typedef UsingDirectiveDecl * const * udir_iterator; - + typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range; udir_iterator_range getUsingDirectives() const; @@ -824,8 +954,8 @@ public: /// \brief State whether this DeclContext has external storage for /// declarations lexically in this context. - void setHasExternalLexicalStorage(bool ES = true) { - ExternalLexicalStorage = ES; + void setHasExternalLexicalStorage(bool ES = true) { + ExternalLexicalStorage = ES; } /// \brief Whether this DeclContext has external storage containing @@ -834,8 +964,8 @@ public: /// \brief State whether this DeclContext has external storage for /// declarations visible in this context. - void setHasExternalVisibleStorage(bool ES = true) { - ExternalVisibleStorage = ES; + void setHasExternalVisibleStorage(bool ES = true) { + ExternalVisibleStorage = ES; } static bool classof(const Decl *D); diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index c523e96e03b0..c858c5c0df78 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -14,46 +14,51 @@ #ifndef LLVM_CLANG_AST_DECLCXX_H #define LLVM_CLANG_AST_DECLCXX_H +#include "clang/AST/Expr.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallPtrSet.h" namespace clang { class ClassTemplateDecl; -class CXXRecordDecl; +class ClassTemplateSpecializationDecl; +class CXXBasePath; +class CXXBasePaths; class CXXConstructorDecl; -class CXXDestructorDecl; class CXXConversionDecl; +class CXXDestructorDecl; class CXXMethodDecl; -class ClassTemplateSpecializationDecl; - -/// \brief Represents any kind of function declaration, whether it is a +class CXXRecordDecl; +class CXXMemberLookupCriteria; + +/// \brief Represents any kind of function declaration, whether it is a /// concrete function or a function template. class AnyFunctionDecl { NamedDecl *Function; - + AnyFunctionDecl(NamedDecl *ND) : Function(ND) { } - + public: AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { } AnyFunctionDecl(FunctionTemplateDecl *FTD); - - /// \brief Implicily converts any function or function template into a + + /// \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; } - - static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) { + + static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) { return AnyFunctionDecl(ND); } }; - + } // end namespace clang namespace llvm { - /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from + /// 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; @@ -63,26 +68,26 @@ namespace llvm { }; template<> struct simplify_type< ::clang::AnyFunctionDecl> : public simplify_type<const ::clang::AnyFunctionDecl> {}; - + // Provide PointerLikeTypeTraits for non-cvr pointers. template<> class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { public: static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) { - return F.get(); + return F.get(); } static inline ::clang::AnyFunctionDecl getFromVoidPointer(void *P) { return ::clang::AnyFunctionDecl::getFromNamedDecl( static_cast< ::clang::NamedDecl*>(P)); } - + enum { NumLowBitsAvailable = 2 }; }; - + } // 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. @@ -127,12 +132,64 @@ public: unsigned size() const { return Functions.size(); } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == OverloadedFunction; + static bool classof(const Decl *D) { + return D->getKind() == OverloadedFunction; } static bool classof(const OverloadedFunctionDecl *D) { return true; } }; +/// \brief Provides uniform iteration syntax for an overload set, function, +/// or function template. +class OverloadIterator { + /// \brief An overloaded function set, function declaration, or + /// function template declaration. + NamedDecl *D; + + /// \brief If the declaration is an overloaded function set, this is the + /// iterator pointing to the current position within that overloaded + /// function set. + OverloadedFunctionDecl::function_iterator Iter; + +public: + typedef AnyFunctionDecl value_type; + typedef value_type reference; + typedef NamedDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + OverloadIterator() : D(0) { } + + OverloadIterator(FunctionDecl *FD) : D(FD) { } + OverloadIterator(FunctionTemplateDecl *FTD) + : D(reinterpret_cast<NamedDecl*>(FTD)) { } + OverloadIterator(OverloadedFunctionDecl *Ovl) + : D(Ovl), Iter(Ovl->function_begin()) { } + + OverloadIterator(NamedDecl *ND); + + reference operator*() const; + + pointer operator->() const { return (**this).get(); } + + OverloadIterator &operator++(); + + OverloadIterator operator++(int) { + OverloadIterator Temp(*this); + ++(*this); + return Temp; + } + + bool Equals(const OverloadIterator &Other) const; +}; + +inline bool operator==(const OverloadIterator &X, const OverloadIterator &Y) { + return X.Equals(Y); +} + +inline bool operator!=(const OverloadIterator &X, const OverloadIterator &Y) { + return !(X == Y); +} + /// CXXBaseSpecifier - A base class of a C++ class. /// /// Each CXXBaseSpecifier represents a single, direct base class (or @@ -162,7 +219,7 @@ class CXXBaseSpecifier { /// struct (false). This determines the mapping from the access /// specifier as written in the source code to the access specifier /// used for semantic analysis. - bool BaseOfClass : 1; + bool BaseOfClass : 1; /// Access - Access specifier as written in the source code (which /// may be AS_none). The actual type of data stored here is an @@ -173,7 +230,7 @@ class CXXBaseSpecifier { /// BaseType - The type of the base class. This will be a class or /// struct (or a typedef of such). QualType BaseType; - + public: CXXBaseSpecifier() { } @@ -183,7 +240,7 @@ public: /// getSourceRange - Retrieves the source range that contains the /// entire base specifier. SourceRange getSourceRange() const { return Range; } - + /// isVirtual - Determines whether the base class is a virtual base /// class (or not). bool isVirtual() const { return Virtual; } @@ -193,11 +250,11 @@ public: /// semantic analysis, so the result can never be AS_none. To /// retrieve the access specifier as written in the source code, use /// getAccessSpecifierAsWritten(). - AccessSpecifier getAccessSpecifier() const { + AccessSpecifier getAccessSpecifier() const { if ((AccessSpecifier)Access == AS_none) return BaseOfClass? AS_private : AS_public; else - return (AccessSpecifier)Access; + return (AccessSpecifier)Access; } /// getAccessSpecifierAsWritten - Retrieves the access specifier as @@ -218,7 +275,7 @@ public: /// to deal with C++-specific things. class CXXRecordDecl : public RecordDecl { /// UserDeclaredConstructor - True when this class has a - /// user-declared constructor. + /// user-declared constructor. bool UserDeclaredConstructor : 1; /// UserDeclaredCopyConstructor - True when this class has a @@ -239,6 +296,12 @@ class CXXRecordDecl : public RecordDecl { /// PlainOldData - True when this class is a POD-type. bool PlainOldData : 1; + /// Empty - true when this class is empty for traits purposes, i.e. has no + /// data members other than 0-width bit-fields, has no virtual function/base, + /// and doesn't inherit from a non-empty class. Doesn't take union-ness into + /// account. + bool Empty : 1; + /// Polymorphic - True when this class is polymorphic, i.e. has at least one /// virtual member or derives from a polymorphic class. bool Polymorphic : 1; @@ -246,12 +309,55 @@ class CXXRecordDecl : public RecordDecl { /// Abstract - True when this class is abstract, i.e. has at least one /// pure virtual function, (that can come from a base class). bool Abstract : 1; - - /// HasTrivialConstructor - True when this class has a trivial constructor + + /// HasTrivialConstructor - True when this class has a trivial constructor. + /// + /// C++ [class.ctor]p5. A constructor is trivial if it is an + /// implicitly-declared default constructor and if: + /// * its class has no virtual functions and no virtual base classes, and + /// * all the direct base classes of its class have trivial constructors, and + /// * for all the nonstatic data members of its class that are of class type + /// (or array thereof), each such class has a trivial constructor. bool HasTrivialConstructor : 1; - - /// HasTrivialDestructor - True when this class has a trivial destructor + + /// HasTrivialCopyConstructor - True when this class has a trivial copy + /// constructor. + /// + /// C++ [class.copy]p6. A copy constructor for class X is trivial + /// if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy constructor, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy constructor; + /// otherwise the copy constructor is non-trivial. + bool HasTrivialCopyConstructor : 1; + + /// HasTrivialCopyAssignment - True when this class has a trivial copy + /// assignment operator. + /// + /// C++ [class.copy]p11. A copy assignment operator for class X is + /// trivial if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy assignment operator, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy assignment + /// operator; + /// otherwise the copy assignment operator is non-trivial. + bool HasTrivialCopyAssignment : 1; + + /// HasTrivialDestructor - True when this class has a trivial destructor. + /// + /// C++ [class.dtor]p3. A destructor is trivial if it is an + /// implicitly-declared destructor and if: + /// * all of the direct base classes of its class have trivial destructors + /// and + /// * for all of the non-static data members of its class that are of class + /// type (or array thereof), each such class has a trivial destructor. bool HasTrivialDestructor : 1; + + /// ComputedVisibleConversions - True when visible conversion functions are + /// already computed and are available. + bool ComputedVisibleConversions : 1; /// Bases - Base classes of this class. /// FIXME: This is wasted space for a union. @@ -260,45 +366,85 @@ class CXXRecordDecl : public RecordDecl { /// NumBases - The number of base class specifiers in Bases. unsigned NumBases; + /// VBases - direct and indirect virtual base classes of this class. + CXXBaseSpecifier *VBases; + + /// NumVBases - The number of virtual base class specifiers in VBases. + unsigned NumVBases; + /// Conversions - Overload set containing the conversion functions /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a - /// CXXConversionDecl. + /// CXXConversionDecl. OverloadedFunctionDecl Conversions; + /// VisibleConversions - Overload set containing the conversion functions + /// of this C++ class and all those inherited conversion functions that + /// are visible in this class. Each of the entries in this overload set is + /// a CXXConversionDecl or a FunctionTemplateDecl. + OverloadedFunctionDecl VisibleConversions; + /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. - /// + /// /// For non-templates, this value will be NULL. For record /// declarations that describe a class template, this will be a /// pointer to a ClassTemplateDecl. For member /// classes of class template specializations, this will be the - /// RecordDecl from which the member class was instantiated. - llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*> + /// MemberSpecializationInfo referring to the member class that was + /// instantiated or specialized. + llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> TemplateOrInstantiation; - + + void getNestedVisibleConversionFunctions(CXXRecordDecl *RD, + const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, + const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes); + void collectConversionFunctions( + llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet); + protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id); + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL = SourceLocation()); ~CXXRecordDecl(); public: /// base_class_iterator - Iterator that traverses the base classes - /// of a clas. + /// of a class. typedef CXXBaseSpecifier* base_class_iterator; /// base_class_const_iterator - Iterator that traverses the base - /// classes of a clas. + /// classes of a class. typedef const CXXBaseSpecifier* base_class_const_iterator; + /// reverse_base_class_iterator = Iterator that traverses the base classes + /// of a class in reverse order. + typedef std::reverse_iterator<base_class_iterator> + reverse_base_class_iterator; + + /// reverse_base_class_iterator = Iterator that traverses the base classes + /// of a class in reverse order. + typedef std::reverse_iterator<base_class_const_iterator> + reverse_base_class_const_iterator; + + virtual CXXRecordDecl *getCanonicalDecl() { + return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); + } + static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation TKL = SourceLocation(), CXXRecordDecl* PrevDecl=0, bool DelayTypeCreation = false); - + virtual void Destroy(ASTContext& C); - + + bool isDynamicClass() const { + return Polymorphic || NumVBases != 0; + } + /// setBases - Sets the base classes of this struct or class. void setBases(ASTContext &C, CXXBaseSpecifier const * const *Bases, unsigned NumBases); @@ -311,18 +457,78 @@ public: base_class_const_iterator bases_begin() const { return Bases; } base_class_iterator bases_end() { return Bases + NumBases; } base_class_const_iterator bases_end() const { return Bases + NumBases; } + reverse_base_class_iterator bases_rbegin() { + return reverse_base_class_iterator(bases_end()); + } + reverse_base_class_const_iterator bases_rbegin() const { + return reverse_base_class_const_iterator(bases_end()); + } + reverse_base_class_iterator bases_rend() { + return reverse_base_class_iterator(bases_begin()); + } + reverse_base_class_const_iterator bases_rend() const { + return reverse_base_class_const_iterator(bases_begin()); + } + + /// getNumVBases - Retrieves the number of virtual base classes of this + /// class. + unsigned getNumVBases() const { return NumVBases; } + + base_class_iterator vbases_begin() { return VBases; } + base_class_const_iterator vbases_begin() const { return VBases; } + base_class_iterator vbases_end() { return VBases + NumVBases; } + base_class_const_iterator vbases_end() const { return VBases + NumVBases; } + reverse_base_class_iterator vbases_rbegin() { + return reverse_base_class_iterator(vbases_end()); + } + reverse_base_class_const_iterator vbases_rbegin() const { + return reverse_base_class_const_iterator(vbases_end()); + } + reverse_base_class_iterator vbases_rend() { + return reverse_base_class_iterator(vbases_begin()); + } + reverse_base_class_const_iterator vbases_rend() const { + return reverse_base_class_const_iterator(vbases_begin()); + } + + /// Iterator access to method members. The method iterator visits + /// all method members of the class, including non-instance methods, + /// special methods, etc. + typedef specific_decl_iterator<CXXMethodDecl> method_iterator; + + /// method_begin - Method begin iterator. Iterates in the order the methods + /// were declared. + method_iterator method_begin() const { + return method_iterator(decls_begin()); + } + /// method_end - Method end iterator. + method_iterator method_end() const { + return method_iterator(decls_end()); + } + + /// Iterator access to constructor members. + typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator; + + ctor_iterator ctor_begin() const { + return ctor_iterator(decls_begin()); + } + ctor_iterator ctor_end() const { + return ctor_iterator(decls_end()); + } /// hasConstCopyConstructor - Determines whether this class has a /// copy constructor that accepts a const-qualified argument. bool hasConstCopyConstructor(ASTContext &Context) const; /// getCopyConstructor - Returns the copy constructor for this class - CXXConstructorDecl *getCopyConstructor(ASTContext &Context, + CXXConstructorDecl *getCopyConstructor(ASTContext &Context, unsigned TypeQuals) const; /// hasConstCopyAssignment - Determines whether this class has a /// copy assignment operator that accepts a const-qualified argument. - bool hasConstCopyAssignment(ASTContext &Context) const; + /// It returns its decl in MD if found. + bool hasConstCopyAssignment(ASTContext &Context, + const CXXMethodDecl *&MD) const; /// addedConstructor - Notify the class that another constructor has /// been added. This routine helps maintain information about the @@ -332,7 +538,12 @@ public: /// hasUserDeclaredConstructor - Whether this class has any /// user-declared constructors. When true, a default constructor /// will not be implicitly declared. - bool hasUserDeclaredConstructor() const { return UserDeclaredConstructor; } + bool hasUserDeclaredConstructor() const { + assert((isDefinition() || + cast<RecordType>(getTypeForDecl())->isBeingDefined()) && + "Incomplete record decl!"); + return UserDeclaredConstructor; + } /// hasUserDeclaredCopyConstructor - Whether this class has a /// user-declared copy constructor. When false, a copy constructor @@ -361,22 +572,43 @@ public: /// setUserDeclaredDestructor - Set whether this class has a /// user-declared destructor. If not set by the time the class is /// fully defined, a destructor will be implicitly declared. - void setUserDeclaredDestructor(bool UCD) { - UserDeclaredDestructor = UCD; + void setUserDeclaredDestructor(bool UCD) { + UserDeclaredDestructor = UCD; } /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. - OverloadedFunctionDecl *getConversionFunctions() { - return &Conversions; + OverloadedFunctionDecl *getConversionFunctions() { + assert((this->isDefinition() || + cast<RecordType>(getTypeForDecl())->isBeingDefined()) && + "getConversionFunctions() called on incomplete type"); + return &Conversions; } - const OverloadedFunctionDecl *getConversionFunctions() const { - return &Conversions; + const OverloadedFunctionDecl *getConversionFunctions() const { + assert((this->isDefinition() || + cast<RecordType>(getTypeForDecl())->isBeingDefined()) && + "getConversionFunctions() called on incomplete type"); + return &Conversions; } + /// getVisibleConversionFunctions - get all conversion functions visible + /// in current class; including conversion function templates. + OverloadedFunctionDecl *getVisibleConversionFunctions(); + /// addVisibleConversionFunction - Add a new conversion function to the + /// list of visible conversion functions. + void addVisibleConversionFunction(CXXConversionDecl *ConvDecl); + + /// \brief Add a new conversion function template to the list of visible + /// conversion functions. + void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl); + /// addConversionFunction - Add a new conversion function to the /// list of conversion functions. - void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl); + void addConversionFunction(CXXConversionDecl *ConvDecl); + + /// \brief Add a new conversion function template to the list of conversion + /// functions. + void addConversionFunction(FunctionTemplateDecl *ConvDecl); /// isAggregate - Whether this class is an aggregate (C++ /// [dcl.init.aggr]), which is a class with no user-declared @@ -397,6 +629,15 @@ public: /// setPOD - Set whether this class is a POD-type (C++ [class]p4). void setPOD(bool POD) { PlainOldData = POD; } + /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which + /// means it has a virtual function, virtual base, data member (other than + /// 0-width bit-field) or inherits from a non-empty class. Does NOT include + /// a check for union-ness. + bool isEmpty() const { return Empty; } + + /// Set whether this class is empty (C++0x [meta.unary.prop]) + void setEmpty(bool Emp) { Empty = Emp; } + /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. bool isPolymorphic() const { return Polymorphic; } @@ -408,26 +649,42 @@ public: /// isAbstract - Whether this class is abstract (C++ [class.abstract]), /// which means that the class contains or inherits a pure virtual function. bool isAbstract() const { return Abstract; } - + /// setAbstract - Set whether this class is abstract (C++ [class.abstract]) void setAbstract(bool Abs) { Abstract = Abs; } - + // hasTrivialConstructor - Whether this class has a trivial constructor // (C++ [class.ctor]p5) bool hasTrivialConstructor() const { return HasTrivialConstructor; } - + // setHasTrivialConstructor - Set whether this class has a trivial constructor // (C++ [class.ctor]p5) void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; } - + + // hasTrivialCopyConstructor - Whether this class has a trivial copy + // constructor (C++ [class.copy]p6) + bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; } + + // setHasTrivialCopyConstructor - Set whether this class has a trivial + // copy constructor (C++ [class.copy]p6) + void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; } + + // hasTrivialCopyAssignment - Whether this class has a trivial copy + // assignment operator (C++ [class.copy]p11) + bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; } + + // setHasTrivialCopyAssignment - Set whether this class has a + // trivial copy assignment operator (C++ [class.copy]p11) + void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; } + // hasTrivialDestructor - Whether this class has a trivial destructor // (C++ [class.dtor]p3) bool hasTrivialDestructor() const { return HasTrivialDestructor; } - + // setHasTrivialDestructor - Set whether this class has a trivial destructor // (C++ [class.dtor]p3) void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; } - + /// \brief If this record is an instantiation of a member class, /// retrieves the member class from which it was instantiated. /// @@ -447,15 +704,17 @@ public: /// the CXXRecordDecl X<T>::A. When a complete definition of /// X<int>::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberClass(). - CXXRecordDecl *getInstantiatedFromMemberClass() const { - return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>(); - } - + CXXRecordDecl *getInstantiatedFromMemberClass() const; + + /// \brief If this class is an instantiation of a member class of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + /// \brief Specify that this record is an instantiation of the /// member class RD. - void setInstantiationOfMemberClass(CXXRecordDecl *RD) { - TemplateOrInstantiation = RD; - } + void setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK); /// \brief Retrieves the class template that is described by this /// class declaration. @@ -476,34 +735,150 @@ public: TemplateOrInstantiation = Template; } + /// \brief Determine whether this particular class is a specialization or + /// instantiation of a class template or member class of a class template, + /// and how it was instantiated or specialized. + TemplateSpecializationKind getTemplateSpecializationKind(); + + /// \brief Set the kind of specialization or template instantiation this is. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + /// getDefaultConstructor - Returns the default constructor for this class CXXConstructorDecl *getDefaultConstructor(ASTContext &Context); - + /// 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()); } + + /// \brief Determine whether this class is derived from the class \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \returns true if this class is derived from Base, false otherwise. + bool isDerivedFrom(CXXRecordDecl *Base); + + /// \brief Determine whether this class is derived from the type \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \param Paths will contain the paths taken from the current class to the + /// given \p Base class. + /// + /// \returns true if this class is derived from Base, false otherwise. + /// + /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than + /// tangling input and output in \p Paths + bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths); + + /// \brief Function type used by lookupInBases() to determine whether a + /// specific base class subobject matches the lookup criteria. + /// + /// \param Specifier the base-class specifier that describes the inheritance + /// from the base class we are trying to match. + /// + /// \param Path the current path, from the most-derived class down to the + /// base named by the \p Specifier. + /// + /// \param UserData a single pointer to user-specified data, provided to + /// lookupInBases(). + /// + /// \returns true if this base matched the search criteria, false otherwise. + typedef bool BaseMatchesCallback(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData); + + /// \brief Look for entities within the base classes of this C++ class, + /// transitively searching all base class subobjects. + /// + /// This routine uses the callback function \p BaseMatches to find base + /// classes meeting some search criteria, walking all base class subobjects + /// and populating the given \p Paths structure with the paths through the + /// inheritance hierarchy that resulted in a match. On a successful search, + /// the \p Paths structure can be queried to retrieve the matching paths and + /// to determine if there were any ambiguities. + /// + /// \param BaseMatches callback function used to determine whether a given + /// base matches the user-defined search criteria. + /// + /// \param UserData user data pointer that will be provided to \p BaseMatches. + /// + /// \param Paths used to record the paths from this class to its base class + /// subobjects that match the search criteria. + /// + /// \returns true if there exists any path from this class to a base class + /// subobject that matches the search criteria. + bool lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, + CXXBasePaths &Paths); + + /// \brief Base-class lookup callback that determines whether the given + /// base class specifier refers to a specific class declaration. + /// + /// This callback can be used with \c lookupInBases() to determine whether + /// a given derived class has is a base class subobject of a particular type. + /// The user data pointer should refer to the canonical CXXRecordDecl of the + /// base class that we are searching for. + static bool FindBaseClass(CXXBaseSpecifier *Specifier, CXXBasePath &Path, + void *BaseRecord); + + /// \brief Base-class lookup callback that determines whether there exists + /// a tag with the given name. + /// + /// This callback can be used with \c lookupInBases() to find tag members + /// of the given name within a C++ class hierarchy. The user data pointer + /// is an opaque \c DeclarationName pointer. + static bool FindTagMember(CXXBaseSpecifier *Specifier, CXXBasePath &Path, + void *Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name. + /// + /// This callback can be used with \c lookupInBases() to find members + /// of the given name within a C++ class hierarchy. The user data pointer + /// is an opaque \c DeclarationName pointer. + static bool FindOrdinaryMember(CXXBaseSpecifier *Specifier, CXXBasePath &Path, + void *Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name that can be used in a nested-name-specifier. + /// + /// This callback can be used with \c lookupInBases() to find membes of + /// the given name within a C++ class hierarchy that can occur within + /// nested-name-specifiers. + static bool FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData); /// viewInheritance - Renders and displays an inheritance diagram /// for this C++ class and all of its base classes (transitively) using /// GraphViz. void viewInheritance(ASTContext& Context) const; - static bool classof(const Decl *D) { - return D->getKind() == CXXRecord || + static bool classof(const Decl *D) { + return D->getKind() == CXXRecord || D->getKind() == ClassTemplateSpecialization || - D->getKind() == ClassTemplatePartialSpecialization; + D->getKind() == ClassTemplatePartialSpecialization; } static bool classof(const CXXRecordDecl *D) { return true; } - static bool classof(const ClassTemplateSpecializationDecl *D) { - return true; + static bool classof(const ClassTemplateSpecializationDecl *D) { + return true; } }; @@ -512,42 +887,60 @@ public: class CXXMethodDecl : public FunctionDecl { protected: CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, + DeclarationName N, QualType T, DeclaratorInfo *DInfo, bool isStatic, bool isInline) - : FunctionDecl(DK, RD, L, N, T, (isStatic ? Static : None), + : FunctionDecl(DK, RD, L, N, T, DInfo, (isStatic ? Static : None), isInline) {} public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isStatic = false, + QualType T, DeclaratorInfo *DInfo, + bool isStatic = false, bool isInline = false); - + bool isStatic() const { return getStorageClass() == Static; } bool isInstance() const { return !isStatic(); } - bool isVirtual() const { - return isVirtualAsWritten() || - (begin_overridden_methods() != end_overridden_methods()); - } + bool isVirtual() const { + CXXMethodDecl *CD = + cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl()); - /// - void addOverriddenMethod(const CXXMethodDecl *MD); + if (CD->isVirtualAsWritten()) + return true; + + return (CD->begin_overridden_methods() != CD->end_overridden_methods()); + } - typedef const CXXMethodDecl ** method_iterator; + /// \brief Determine whether this is a usual deallocation function + /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded + /// delete or delete[] operator with a particular signature. + bool isUsualDeallocationFunction() const; + const CXXMethodDecl *getCanonicalDecl() const { + return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); + } + CXXMethodDecl *getCanonicalDecl() { + return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); + } + + /// + void addOverriddenMethod(const CXXMethodDecl *MD); + + typedef const CXXMethodDecl ** method_iterator; + method_iterator begin_overridden_methods() const; method_iterator end_overridden_methods() const; - + /// getParent - Returns the parent of this method declaration, which /// is the class in which this method is defined. - const CXXRecordDecl *getParent() const { - return cast<CXXRecordDecl>(FunctionDecl::getParent()); + const CXXRecordDecl *getParent() const { + return cast<CXXRecordDecl>(FunctionDecl::getParent()); } - + /// getParent - Returns the parent of this method declaration, which /// is the class in which this method is defined. - CXXRecordDecl *getParent() { + CXXRecordDecl *getParent() { return const_cast<CXXRecordDecl *>( cast<CXXRecordDecl>(FunctionDecl::getParent())); } @@ -557,11 +950,11 @@ public: QualType getThisType(ASTContext &C) const; unsigned getTypeQualifiers() const { - return getType()->getAsFunctionProtoType()->getTypeQuals(); + return getType()->getAs<FunctionProtoType>()->getTypeQuals(); } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion; } static bool classof(const CXXMethodDecl *D) { return true; } @@ -589,38 +982,63 @@ class CXXBaseOrMemberInitializer { uintptr_t BaseOrMember; /// Args - The arguments used to initialize the base or member. - Expr **Args; + Stmt **Args; unsigned NumArgs; - + + /// \brief Stores either the constructor to call to initialize this base or + /// member (a CXXConstructorDecl pointer), or stores the anonymous union of + /// which the initialized value is a member. + /// + /// When the value is a FieldDecl pointer, 'BaseOrMember' is class's + /// anonymous union data member, this field holds the FieldDecl for the + /// member of the anonymous union being initialized. + /// @code + /// struct X { + /// X() : au_i1(123) {} + /// union { + /// int au_i1; + /// float au_f1; + /// }; + /// }; + /// @endcode + /// In above example, BaseOrMember holds the field decl. for anonymous union + /// and AnonUnionMember holds field decl for au_i1. + llvm::PointerUnion<CXXConstructorDecl *, FieldDecl *> CtorOrAnonUnion; + /// IdLoc - Location of the id in ctor-initializer list. SourceLocation IdLoc; + /// RParenLoc - Location of the right paren of the ctor-initializer. + SourceLocation RParenLoc; + public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. - explicit + explicit CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - SourceLocation L); + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R); /// CXXBaseOrMemberInitializer - Creates a new member initializer. - explicit + explicit CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - SourceLocation L); + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R); /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer. ~CXXBaseOrMemberInitializer(); /// arg_iterator - Iterates through the member initialization /// arguments. - typedef Expr **arg_iterator; + typedef ExprIterator arg_iterator; /// arg_const_iterator - Iterates through the member initialization /// arguments. - typedef Expr * const * arg_const_iterator; + typedef ConstExprIterator const_arg_iterator; /// getBaseOrMember - get the generic 'member' representing either the field /// or a base class. void* getBaseOrMember() const { return reinterpret_cast<void*>(BaseOrMember); } - + /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; } @@ -633,8 +1051,8 @@ public: /// type used to specify the initializer. The resulting type will be /// a class type or a typedef of a class type. If this is not a base /// class initializer, returns NULL. - Type *getBaseClass() { - if (isBaseInitializer()) + Type *getBaseClass() { + if (isBaseInitializer()) return reinterpret_cast<Type*>(BaseOrMember & ~0x01); else return 0; @@ -644,8 +1062,8 @@ public: /// type used to specify the initializer. The resulting type will be /// a class type or a typedef of a class type. If this is not a base /// class initializer, returns NULL. - const Type *getBaseClass() const { - if (isBaseInitializer()) + const Type *getBaseClass() const { + if (isBaseInitializer()) return reinterpret_cast<const Type*>(BaseOrMember & ~0x01); else return 0; @@ -654,24 +1072,40 @@ public: /// getMember - If this is a member initializer, returns the /// declaration of the non-static data member being /// initialized. Otherwise, returns NULL. - FieldDecl *getMember() { + FieldDecl *getMember() { if (isMemberInitializer()) - return reinterpret_cast<FieldDecl *>(BaseOrMember); + return reinterpret_cast<FieldDecl *>(BaseOrMember); else return 0; } + void setMember(FieldDecl * anonUnionField) { + BaseOrMember = reinterpret_cast<uintptr_t>(anonUnionField); + } + + FieldDecl *getAnonUnionMember() const { + return CtorOrAnonUnion.dyn_cast<FieldDecl *>(); + } + void setAnonUnionMember(FieldDecl *anonMember) { + CtorOrAnonUnion = anonMember; + } + + const CXXConstructorDecl *getConstructor() const { + return CtorOrAnonUnion.dyn_cast<CXXConstructorDecl *>(); + } + SourceLocation getSourceLocation() const { return IdLoc; } - - /// begin() - Retrieve an iterator to the first initializer argument. - arg_iterator begin() { return Args; } - /// begin() - Retrieve an iterator to the first initializer argument. - arg_const_iterator begin() const { return Args; } + SourceLocation getRParenLoc() const { return RParenLoc; } - /// end() - Retrieve an iterator past the last initializer argument. - arg_iterator end() { return Args + NumArgs; } - /// end() - Retrieve an iterator past the last initializer argument. - arg_const_iterator end() const { return Args + NumArgs; } + /// arg_begin() - Retrieve an iterator to the first initializer argument. + arg_iterator arg_begin() { return Args; } + /// arg_begin() - Retrieve an iterator to the first initializer argument. + const_arg_iterator const_arg_begin() const { return Args; } + + /// arg_end() - Retrieve an iterator past the last initializer argument. + arg_iterator arg_end() { return Args + NumArgs; } + /// arg_end() - Retrieve an iterator past the last initializer argument. + const_arg_iterator const_arg_end() const { return Args + NumArgs; } /// getNumArgs - Determine the number of arguments used to /// initialize the member or base. @@ -680,7 +1114,7 @@ public: /// CXXConstructorDecl - Represents a C++ constructor within a /// class. For example: -/// +/// /// @code /// class X { /// public: @@ -698,82 +1132,86 @@ class CXXConstructorDecl : public CXXMethodDecl { /// explicitly defaulted (i.e., defined with " = default") will have /// @c !Implicit && ImplicitlyDefined. bool ImplicitlyDefined : 1; - + /// Support for base and member initializers. - /// BaseOrMemberInitializers - The arguments used to initialize the base + /// BaseOrMemberInitializers - The arguments used to initialize the base /// or member. CXXBaseOrMemberInitializer **BaseOrMemberInitializers; unsigned NumBaseOrMemberInitializers; - + CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, + DeclarationName N, QualType T, DeclaratorInfo *DInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline), + : CXXMethodDecl(CXXConstructor, RD, L, N, T, DInfo, false, isInline), Explicit(isExplicit), ImplicitlyDefined(false), - BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { + BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { setImplicit(isImplicitlyDeclared); } virtual void Destroy(ASTContext& C); - + public: static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isExplicit, + QualType T, DeclaratorInfo *DInfo, + bool isExplicit, bool isInline, bool isImplicitlyDeclared); - /// isExplicit - Whether this constructor was marked "explicit" or not. + /// isExplicit - Whether this constructor was marked "explicit" or not. bool isExplicit() const { return Explicit; } /// isImplicitlyDefined - Whether this constructor was implicitly /// defined. If false, then this constructor was defined by the /// user. This operation can only be invoked if the constructor has /// already been defined. - bool isImplicitlyDefined(ASTContext &C) const { - assert(isThisDeclarationADefinition() && + bool isImplicitlyDefined(ASTContext &C) const { + assert(isThisDeclarationADefinition() && "Can only get the implicit-definition flag once the " "constructor has been defined"); - return ImplicitlyDefined; + return ImplicitlyDefined; } /// setImplicitlyDefined - Set whether this constructor was /// implicitly defined or not. - void setImplicitlyDefined(bool ID) { - assert(isThisDeclarationADefinition() && + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && "Can only set the implicit-definition flag once the constructor " "has been defined"); - ImplicitlyDefined = ID; + ImplicitlyDefined = ID; } - + /// init_iterator - Iterates through the member/base initializer list. typedef CXXBaseOrMemberInitializer **init_iterator; - + /// init_const_iterator - Iterates through the memberbase initializer list. typedef CXXBaseOrMemberInitializer * const * init_const_iterator; - - /// begin() - Retrieve an iterator to the first initializer. - init_iterator begin() { return BaseOrMemberInitializers; } + + /// init_begin() - Retrieve an iterator to the first initializer. + init_iterator init_begin() { return BaseOrMemberInitializers; } /// begin() - Retrieve an iterator to the first initializer. - init_const_iterator begin() const { return BaseOrMemberInitializers; } - - /// end() - Retrieve an iterator past the last initializer. - init_iterator end() { - return BaseOrMemberInitializers + NumBaseOrMemberInitializers; + init_const_iterator init_begin() const { return BaseOrMemberInitializers; } + + /// init_end() - Retrieve an iterator past the last initializer. + init_iterator init_end() { + return BaseOrMemberInitializers + NumBaseOrMemberInitializers; } /// end() - Retrieve an iterator past the last initializer. - init_const_iterator end() const { - return BaseOrMemberInitializers + NumBaseOrMemberInitializers; + init_const_iterator init_end() const { + return BaseOrMemberInitializers + NumBaseOrMemberInitializers; } - + /// getNumArgs - Determine the number of arguments used to /// initialize the member or base. - unsigned getNumBaseOrMemberInitializers() const { - return NumBaseOrMemberInitializers; + unsigned getNumBaseOrMemberInitializers() const { + return NumBaseOrMemberInitializers; + } + + void setNumBaseOrMemberInitializers(unsigned numBaseOrMemberInitializers) { + NumBaseOrMemberInitializers = numBaseOrMemberInitializers; + } + + void setBaseOrMemberInitializers(CXXBaseOrMemberInitializer ** initializers) { + BaseOrMemberInitializers = initializers; } - - void setBaseOrMemberInitializers(ASTContext &C, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers); - /// isDefaultConstructor - Whether this constructor is a default /// constructor (C++ [class.ctor]p5), which can be used to /// default-initialize a class of this type. @@ -804,10 +1242,10 @@ public: /// isConvertingConstructor - Whether this constructor is a /// converting constructor (C++ [class.conv.ctor]), which can be /// used for user-defined conversions. - bool isConvertingConstructor() const; + bool isConvertingConstructor(bool AllowExplicit) const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() == CXXConstructor; } static bool classof(const CXXConstructorDecl *D) { return true; } @@ -815,7 +1253,7 @@ public: /// CXXDestructorDecl - Represents a C++ destructor within a /// class. For example: -/// +/// /// @code /// class X { /// public: @@ -823,6 +1261,13 @@ public: /// }; /// @endcode class CXXDestructorDecl : public CXXMethodDecl { +public: + enum KindOfObjectToDestroy { + VBASE = 0x1, + DRCTNONVBASE = 0x2, + ANYBASE = 0x3 + }; +private: /// ImplicitlyDefined - Whether this destructor was implicitly /// defined by the compiler. When false, the destructor was defined /// by the user. In C++03, this flag will have the same value as @@ -831,40 +1276,141 @@ class CXXDestructorDecl : public CXXMethodDecl { /// @c !Implicit && ImplicitlyDefined. bool ImplicitlyDefined : 1; + /// Support for base and member destruction. + /// BaseOrMemberDestructions - The arguments used to destruct the base + /// or member. Each uintptr_t value represents one of base classes (either + /// virtual or direct non-virtual base), or non-static data member + /// to be destroyed. The low two bits encode the kind of object + /// being destroyed. + uintptr_t *BaseOrMemberDestructions; + unsigned NumBaseOrMemberDestructions; + CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline), - ImplicitlyDefined(false) { + : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*DInfo=*/0, false, isInline), + ImplicitlyDefined(false), + BaseOrMemberDestructions(0), NumBaseOrMemberDestructions(0) { setImplicit(isImplicitlyDeclared); } + virtual void Destroy(ASTContext& C); public: static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, + QualType T, bool isInline, bool isImplicitlyDeclared); /// isImplicitlyDefined - Whether this destructor was implicitly /// defined. If false, then this destructor was defined by the /// user. This operation can only be invoked if the destructor has /// already been defined. - bool isImplicitlyDefined() const { - assert(isThisDeclarationADefinition() && + bool isImplicitlyDefined() const { + assert(isThisDeclarationADefinition() && "Can only get the implicit-definition flag once the destructor has been defined"); - return ImplicitlyDefined; + return ImplicitlyDefined; } /// setImplicitlyDefined - Set whether this destructor was /// implicitly defined or not. - void setImplicitlyDefined(bool ID) { - assert(isThisDeclarationADefinition() && + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && "Can only set the implicit-definition flag once the destructor has been defined"); - ImplicitlyDefined = ID; + ImplicitlyDefined = ID; + } + + /// destr_iterator - Iterates through the member/base destruction list. + + /// destr_const_iterator - Iterates through the member/base destruction list. + typedef uintptr_t const destr_const_iterator; + + /// destr_begin() - Retrieve an iterator to the first destructed member/base. + uintptr_t* destr_begin() { + return BaseOrMemberDestructions; + } + /// destr_begin() - Retrieve an iterator to the first destructed member/base. + uintptr_t* destr_begin() const { + return BaseOrMemberDestructions; + } + + /// destr_end() - Retrieve an iterator past the last destructed member/base. + uintptr_t* destr_end() { + return BaseOrMemberDestructions + NumBaseOrMemberDestructions; + } + /// destr_end() - Retrieve an iterator past the last destructed member/base. + uintptr_t* destr_end() const { + return BaseOrMemberDestructions + NumBaseOrMemberDestructions; + } + + /// getNumBaseOrMemberDestructions - Number of base and non-static members + /// to destroy. + unsigned getNumBaseOrMemberDestructions() const { + return NumBaseOrMemberDestructions; + } + + /// setNumBaseOrMemberDestructions - Set number of base and non-static members + /// to destroy. + void setNumBaseOrMemberDestructions(unsigned numBaseOrMemberDestructions) { + NumBaseOrMemberDestructions = numBaseOrMemberDestructions; + } + + /// getBaseOrMemberToDestroy - get the generic 'member' representing either + /// the field or a base class. + uintptr_t* getBaseOrMemberToDestroy() const { + return BaseOrMemberDestructions; + } + + /// setBaseOrMemberToDestroy - set the generic 'member' representing either + /// the field or a base class. + void setBaseOrMemberDestructions(uintptr_t* baseOrMemberDestructions) { + BaseOrMemberDestructions = baseOrMemberDestructions; + } + + /// isVbaseToDestroy - returns true, if object is virtual base. + bool isVbaseToDestroy(uintptr_t Vbase) const { + return (Vbase & VBASE) != 0; + } + /// isDirectNonVBaseToDestroy - returns true, if object is direct non-virtual + /// base. + bool isDirectNonVBaseToDestroy(uintptr_t DrctNonVbase) const { + return (DrctNonVbase & DRCTNONVBASE) != 0; + } + /// isAnyBaseToDestroy - returns true, if object is any base (virtual or + /// direct non-virtual) + bool isAnyBaseToDestroy(uintptr_t AnyBase) const { + return (AnyBase & ANYBASE) != 0; + } + /// isMemberToDestroy - returns true if object is a non-static data member. + bool isMemberToDestroy(uintptr_t Member) const { + return (Member & ANYBASE) == 0; + } + /// getAnyBaseClassToDestroy - Get the type for the given base class object. + Type *getAnyBaseClassToDestroy(uintptr_t Base) const { + if (isAnyBaseToDestroy(Base)) + return reinterpret_cast<Type*>(Base & ~0x03); + return 0; + } + /// getMemberToDestroy - Get the member for the given object. + FieldDecl *getMemberToDestroy(uintptr_t Member) const { + if (isMemberToDestroy(Member)) + return reinterpret_cast<FieldDecl *>(Member); + return 0; + } + /// getVbaseClassToDestroy - Get the virtual base. + Type *getVbaseClassToDestroy(uintptr_t Vbase) const { + if (isVbaseToDestroy(Vbase)) + return reinterpret_cast<Type*>(Vbase & ~0x01); + return 0; + } + /// getDirectNonVBaseClassToDestroy - Get the virtual base. + Type *getDirectNonVBaseClassToDestroy(uintptr_t Base) const { + if (isDirectNonVBaseToDestroy(Base)) + return reinterpret_cast<Type*>(Base & ~0x02); + return 0; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() == CXXDestructor; } static bool classof(const CXXDestructorDecl *D) { return true; } @@ -872,7 +1418,7 @@ public: /// CXXConversionDecl - Represents a C++ conversion function within a /// class. For example: -/// +/// /// @code /// class X { /// public: @@ -886,16 +1432,16 @@ class CXXConversionDecl : public CXXMethodDecl { bool Explicit : 1; CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, + DeclarationName N, QualType T, DeclaratorInfo *DInfo, bool isInline, bool isExplicit) - : CXXMethodDecl(CXXConversion, RD, L, N, T, false, isInline), + : CXXMethodDecl(CXXConversion, RD, L, N, T, DInfo, false, isInline), Explicit(isExplicit) { } public: static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, - bool isExplicit); + QualType T, DeclaratorInfo *DInfo, + bool isInline, bool isExplicit); /// isExplicit - Whether this is an explicit conversion operator /// (C++0x only). Explicit conversion operators are only considered @@ -904,17 +1450,81 @@ public: /// getConversionType - Returns the type that this conversion /// function is converting to. - QualType getConversionType() const { - return getType()->getAsFunctionType()->getResultType(); + QualType getConversionType() const { + return getType()->getAs<FunctionType>()->getResultType(); } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() == CXXConversion; } static bool classof(const CXXConversionDecl *D) { return true; } }; +/// FriendDecl - Represents the declaration of a friend entity, +/// which can be a function, a type, or a templated function or type. +// For example: +/// +/// @code +/// template <typename T> class A { +/// friend int foo(T); +/// friend class B; +/// friend T; // only in C++0x +/// template <typename U> friend class C; +/// template <typename U> friend A& operator+=(A&, const U&) { ... } +/// }; +/// @endcode +/// +/// The semantic context of a friend decl is its declaring class. +class FriendDecl : public Decl { +public: + typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion; + +private: + // The declaration that's a friend of this class. + FriendUnion Friend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, + SourceLocation FriendL) + : Decl(Decl::Friend, DC, L), + Friend(Friend), + FriendLoc(FriendL) { + } + +public: + static FriendDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, FriendUnion Friend_, + SourceLocation FriendL); + + /// If this friend declaration names an (untemplated but + /// possibly dependent) type, return the type; otherwise + /// return null. This is used only for C++0x's unelaborated + /// friend type declarations. + Type *getFriendType() const { + return Friend.dyn_cast<Type*>(); + } + + /// If this friend declaration doesn't name an unelaborated + /// type, return the inner declaration. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == Decl::Friend; + } + static bool classof(const FriendDecl *D) { return true; } +}; + /// LinkageSpecDecl - This represents a linkage specification. For example: /// extern "C" void foo(); /// @@ -934,14 +1544,14 @@ private: /// HadBraces - Whether this linkage specification had curly braces or not. bool HadBraces : 1; - LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang, + LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang, bool Braces) - : Decl(LinkageSpec, DC, L), + : Decl(LinkageSpec, DC, L), DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { } public: - static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, LanguageIDs Lang, + static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, LanguageIDs Lang, bool Braces); LanguageIDs getLanguage() const { return Language; } @@ -1008,8 +1618,8 @@ class UsingDirectiveDecl : public NamedDecl { NamespaceDecl *Nominated, DeclContext *CommonAncestor) : NamedDecl(Decl::UsingDirective, DC, L, getName()), - NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange), - Qualifier(Qualifier), IdentLoc(IdentLoc), + NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange), + Qualifier(Qualifier), IdentLoc(IdentLoc), NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0), CommonAncestor(CommonAncestor) { } @@ -1074,20 +1684,20 @@ class NamespaceAliasDecl : public NamedDecl { /// \brief The nested-name-specifier that precedes the namespace /// name, if any. NestedNameSpecifier *Qualifier; - + /// IdentLoc - Location of namespace identifier. SourceLocation IdentLoc; - - /// Namespace - The Decl that this alias points to. Can either be a + + /// Namespace - The Decl that this alias points to. Can either be a /// NamespaceDecl or a NamespaceAliasDecl. NamedDecl *Namespace; - - NamespaceAliasDecl(DeclContext *DC, SourceLocation L, - SourceLocation AliasLoc, IdentifierInfo *Alias, + + NamespaceAliasDecl(DeclContext *DC, SourceLocation L, + SourceLocation AliasLoc, IdentifierInfo *Alias, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, NamedDecl *Namespace) - : NamedDecl(Decl::NamespaceAlias, DC, L, Alias), AliasLoc(AliasLoc), + : NamedDecl(Decl::NamespaceAlias, DC, L, Alias), AliasLoc(AliasLoc), QualifierRange(QualifierRange), Qualifier(Qualifier), IdentLoc(IdentLoc), Namespace(Namespace) { } @@ -1106,7 +1716,7 @@ public: return cast<NamespaceDecl>(Namespace); } - + const NamespaceDecl *getNamespace() const { return const_cast<NamespaceAliasDecl*>(this)->getNamespace(); } @@ -1115,14 +1725,14 @@ public: /// may either be a NamespaceDecl or a NamespaceAliasDecl. NamedDecl *getAliasedNamespace() const { return Namespace; } - static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, SourceLocation AliasLoc, - IdentifierInfo *Alias, + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, SourceLocation AliasLoc, + IdentifierInfo *Alias, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, - SourceLocation IdentLoc, + SourceLocation IdentLoc, NamedDecl *Namespace); - + static bool classof(const Decl *D) { return D->getKind() == Decl::NamespaceAlias; } @@ -1132,20 +1742,23 @@ public: /// UsingDecl - Represents a C++ using-declaration. For example: /// using someNameSpace::someIdentifier; class UsingDecl : public NamedDecl { - /// \brief The source range that covers the nested-name-specifier /// preceding the declaration name. SourceRange NestedNameRange; + /// \brief The source location of the target declaration name. SourceLocation TargetNameLocation; + /// \brief The source location of the "using" location itself. SourceLocation UsingLocation; + /// \brief Target declaration. NamedDecl* TargetDecl; - /// \brief Target declaration. + + /// \brief Target nested name specifier. NestedNameSpecifier* TargetNestedNameDecl; - // Had 'typename' keyword. + // \brief Has 'typename' keyword. bool IsTypeName; UsingDecl(DeclContext *DC, SourceLocation L, SourceRange NNR, @@ -1154,7 +1767,7 @@ class UsingDecl : public NamedDecl { : NamedDecl(Decl::Using, DC, L, Target->getDeclName()), NestedNameRange(NNR), TargetNameLocation(TargetNL), UsingLocation(UL), TargetDecl(Target), - TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) { + TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) { this->IdentifierNamespace = TargetDecl->getIdentifierNamespace(); } @@ -1162,23 +1775,23 @@ public: /// \brief Returns the source range that covers the nested-name-specifier /// preceding the namespace name. SourceRange getNestedNameRange() { return NestedNameRange; } - + /// \brief Returns the source location of the target declaration name. SourceLocation getTargetNameLocation() { return TargetNameLocation; } - + /// \brief Returns the source location of the "using" location itself. SourceLocation getUsingLocation() { return UsingLocation; } - + /// \brief getTargetDecl - Returns target specified by using-decl. 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'. + + /// isTypeName - Return true if using decl has 'typename'. bool isTypeName() const { return IsTypeName; } static UsingDecl *Create(ASTContext &C, DeclContext *DC, @@ -1191,27 +1804,85 @@ public: } static bool classof(const UsingDecl *D) { return true; } }; - + +/// UnresolvedUsingDecl - Represents a using declaration whose name can not +/// yet be resolved. +class UnresolvedUsingDecl : public NamedDecl { + /// \brief The source range that covers the nested-name-specifier + /// preceding the declaration name. + SourceRange TargetNestedNameRange; + + /// \brief The source location of the target declaration name. + SourceLocation TargetNameLocation; + + NestedNameSpecifier *TargetNestedNameSpecifier; + + DeclarationName TargetName; + + // \brief Has 'typename' keyword. + bool IsTypeName; + + UnresolvedUsingDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, DeclarationName TargetName, + bool IsTypeNameArg) + : NamedDecl(Decl::UnresolvedUsing, DC, UsingLoc, TargetName), + TargetNestedNameRange(TargetNNR), TargetNameLocation(TargetNameLoc), + TargetNestedNameSpecifier(TargetNNS), TargetName(TargetName), + IsTypeName(IsTypeNameArg) { } + +public: + /// \brief Returns the source range that covers the nested-name-specifier + /// preceding the namespace name. + SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; } + + /// \brief Get target nested name declaration. + NestedNameSpecifier* getTargetNestedNameSpecifier() { + return TargetNestedNameSpecifier; + } + + /// \brief Returns the source location of the target declaration name. + SourceLocation getTargetNameLocation() const { return TargetNameLocation; } + + /// \brief Returns the source location of the target declaration name. + DeclarationName getTargetName() const { return TargetName; } + + bool isTypeName() const { return IsTypeName; } + + static UnresolvedUsingDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName, + bool IsTypeNameArg); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::UnresolvedUsing; + } + static bool classof(const UnresolvedUsingDecl *D) { return true; } +}; + /// StaticAssertDecl - Represents a C++0x static_assert declaration. class StaticAssertDecl : public Decl { Expr *AssertExpr; StringLiteral *Message; - StaticAssertDecl(DeclContext *DC, SourceLocation L, + StaticAssertDecl(DeclContext *DC, SourceLocation L, Expr *assertexpr, StringLiteral *message) : Decl(StaticAssert, DC, L), AssertExpr(assertexpr), Message(message) { } - + public: static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, Expr *AssertExpr, StringLiteral *Message); - + Expr *getAssertExpr() { return AssertExpr; } const Expr *getAssertExpr() const { return AssertExpr; } - + StringLiteral *getMessage() { return Message; } const StringLiteral *getMessage() const { return Message; } - + virtual ~StaticAssertDecl(); virtual void Destroy(ASTContext& C); @@ -1225,7 +1896,7 @@ public: /// into a diagnostic with <<. const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, AccessSpecifier AS); - + } // end namespace clang #endif diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index 6c1231c0a73d..d9e40d478907 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -57,13 +57,13 @@ public: Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03); } } - + ~StoredDeclsList() { // If this is a vector-form, free the vector. if (VectorTy *Vector = getAsVector()) delete Vector; } - + StoredDeclsList &operator=(const StoredDeclsList &RHS) { if (VectorTy *Vector = getAsVector()) delete Vector; @@ -74,9 +74,9 @@ public: } return *this; } - + bool isNull() const { return (Data & ~0x03) == 0; } - + NamedDecl *getAsDecl() const { if ((Data & 0x03) != DK_Decl) return 0; @@ -135,27 +135,27 @@ public: DeclContext::lookup_result getLookupResult(ASTContext &Context) { if (isNull()) return DeclContext::lookup_result(0, 0); - + if (hasDeclarationIDs()) materializeDecls(Context); // If we have a single NamedDecl, return it. if (getAsDecl()) { assert(!isNull() && "Empty list isn't allowed"); - + // Data is a raw pointer to a NamedDecl*, return it. void *Ptr = &Data; return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1); } - + assert(getAsVector() && "Must have a vector at this point"); VectorTy &Vector = *getAsVector(); - + // Otherwise, we have a range result. - return DeclContext::lookup_result((NamedDecl **)&Vector[0], + return DeclContext::lookup_result((NamedDecl **)&Vector[0], (NamedDecl **)&Vector[0]+Vector.size()); } - + /// HandleRedeclaration - If this is a redeclaration of an existing decl, /// replace the old one with D and return true. Otherwise return false. bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) { @@ -169,7 +169,7 @@ public: setOnlyValue(D); return true; } - + // Determine if this declaration is actually a redeclaration. VectorTy &Vec = *getAsVector(); for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); @@ -183,10 +183,10 @@ public: return false; } - + /// AddSubsequentDecl - This is called on the second and later decl when it is /// not a redeclaration to merge it into the appropriate place in our list. - /// + /// void AddSubsequentDecl(NamedDecl *D) { assert(!hasDeclarationIDs() && "Must materialize before adding decls"); @@ -197,7 +197,7 @@ public: VT->push_back(reinterpret_cast<uintptr_t>(OldD)); Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector; } - + VectorTy &Vec = *getAsVector(); if (isa<UsingDirectiveDecl>(D) || D->getIdentifierNamespace() == Decl::IDNS_Tag) @@ -217,4 +217,4 @@ typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap; } // end namespace clang -#endif +#endif diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 15a8adef8e57..790ea3ca0662 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -18,7 +18,7 @@ #include <cassert> namespace clang { - + class ASTContext; class Decl; class DeclGroup; @@ -27,7 +27,7 @@ class DeclGroupIterator; class DeclGroup { // FIXME: Include a TypeSpecifier object. unsigned NumDecls; - + private: DeclGroup() : NumDecls(0) {} DeclGroup(unsigned numdecls, Decl** decls); @@ -38,34 +38,34 @@ public: unsigned size() const { return NumDecls; } - Decl*& operator[](unsigned i) { + Decl*& operator[](unsigned i) { assert (i < NumDecls && "Out-of-bounds access."); return *((Decl**) (this+1)); } - - Decl* const& operator[](unsigned i) const { + + Decl* const& operator[](unsigned i) const { assert (i < NumDecls && "Out-of-bounds access."); return *((Decl* const*) (this+1)); } }; - + class DeclGroupRef { // Note this is not a PointerIntPair because we need the address of the // non-group case to be valid as a Decl** for iteration. - enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; + enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; Decl* D; Kind getKind() const { return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask); - } - -public: + } + +public: DeclGroupRef() : D(0) {} - + explicit DeclGroupRef(Decl* d) : D(d) {} explicit DeclGroupRef(DeclGroup* dg) : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {} - + static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { if (NumDecls == 0) return DeclGroupRef(); @@ -73,10 +73,10 @@ public: return DeclGroupRef(Decls[0]); return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls)); } - + typedef Decl** iterator; typedef Decl* const * const_iterator; - + bool isNull() const { return D == 0; } bool isSingleDecl() const { return getKind() == SingleDeclKind; } bool isDeclGroup() const { return getKind() == DeclGroupKind; } @@ -88,7 +88,7 @@ public: const Decl *getSingleDecl() const { return const_cast<DeclGroupRef*>(this)->getSingleDecl(); } - + DeclGroup &getDeclGroup() { assert(isDeclGroup() && "Isn't a declgroup"); return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask)); @@ -96,7 +96,7 @@ public: const DeclGroup &getDeclGroup() const { return const_cast<DeclGroupRef*>(this)->getDeclGroup(); } - + iterator begin() { if (isSingleDecl()) return D ? &D : 0; @@ -109,13 +109,13 @@ public: DeclGroup &G = getDeclGroup(); return &G[0] + G.size(); } - + const_iterator begin() const { if (isSingleDecl()) return D ? &D : 0; return &getDeclGroup()[0]; } - + const_iterator end() const { if (isSingleDecl()) return D ? &D+1 : 0; @@ -130,7 +130,7 @@ public: return X; } }; - + } // end clang namespace namespace llvm { diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index 1e4440357b65..79a0d368288c 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -91,39 +91,43 @@ ABSTRACT_DECL(Named, Decl) DECL(TemplateTypeParm, TypeDecl) ABSTRACT_DECL(Value, NamedDecl) DECL(EnumConstant, ValueDecl) - DECL(Function, ValueDecl) - DECL(CXXMethod, FunctionDecl) - DECL(CXXConstructor, CXXMethodDecl) - DECL(CXXDestructor, CXXMethodDecl) - DECL(CXXConversion, CXXMethodDecl) - DECL(Field, ValueDecl) - DECL(ObjCIvar, FieldDecl) - DECL(ObjCAtDefsField, FieldDecl) - DECL(Var, ValueDecl) - DECL(ImplicitParam, VarDecl) - DECL(ParmVar, VarDecl) - DECL(OriginalParmVar, ParmVarDecl) - DECL(NonTypeTemplateParm, VarDecl) + ABSTRACT_DECL(Declarator, ValueDecl) + DECL(Function, DeclaratorDecl) + DECL(CXXMethod, FunctionDecl) + DECL(CXXConstructor, CXXMethodDecl) + DECL(CXXDestructor, CXXMethodDecl) + DECL(CXXConversion, CXXMethodDecl) + DECL(Field, DeclaratorDecl) + DECL(ObjCIvar, FieldDecl) + DECL(ObjCAtDefsField, FieldDecl) + DECL(Var, DeclaratorDecl) + DECL(ImplicitParam, VarDecl) + DECL(ParmVar, VarDecl) + DECL(OriginalParmVar, ParmVarDecl) + DECL(NonTypeTemplateParm, VarDecl) DECL(Template, NamedDecl) DECL(FunctionTemplate, TemplateDecl) DECL(ClassTemplate, TemplateDecl) DECL(TemplateTemplateParm, TemplateDecl) DECL(Using, NamedDecl) + DECL(UnresolvedUsing, NamedDecl) DECL(ObjCMethod, NamedDecl) DECL(ObjCContainer, NamedDecl) DECL(ObjCCategory, ObjCContainerDecl) DECL(ObjCProtocol, ObjCContainerDecl) DECL(ObjCInterface, ObjCContainerDecl) + ABSTRACT_DECL(ObjCImpl, ObjCContainerDecl) + DECL(ObjCCategoryImpl, ObjCImplDecl) + DECL(ObjCImplementation, ObjCImplDecl) DECL(ObjCProperty, NamedDecl) DECL(ObjCCompatibleAlias, NamedDecl) - ABSTRACT_DECL(ObjCImpl, NamedDecl) - DECL(ObjCCategoryImpl, ObjCImplDecl) - DECL(ObjCImplementation, ObjCImplDecl) DECL(LinkageSpec, Decl) DECL(ObjCPropertyImpl, Decl) DECL(ObjCForwardProtocol, Decl) DECL(ObjCClass, Decl) DECL(FileScopeAsm, Decl) +DECL(Friend, Decl) +DECL(FriendTemplate, Decl) DECL(StaticAssert, Decl) LAST_DECL(Block, Decl) @@ -132,21 +136,20 @@ DECL_CONTEXT(TranslationUnit) DECL_CONTEXT(Namespace) DECL_CONTEXT(LinkageSpec) DECL_CONTEXT(ObjCMethod) -DECL_CONTEXT(ObjCCategoryImpl) -DECL_CONTEXT(ObjCImplementation) DECL_CONTEXT_BASE(Tag) DECL_CONTEXT_BASE(Function) DECL_CONTEXT_BASE(ObjCContainer) LAST_DECL_CONTEXT(Block) // Declaration ranges -DECL_RANGE(Named, OverloadedFunction, ObjCImplementation) -DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface) +DECL_RANGE(Named, OverloadedFunction, ObjCCompatibleAlias) +DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation) DECL_RANGE(Field, Field, ObjCAtDefsField) DECL_RANGE(Type, Typedef, TemplateTypeParm) DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization) DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization) DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm) +DECL_RANGE(Declarator, Function, NonTypeTemplateParm) DECL_RANGE(Function, Function, CXXConversion) DECL_RANGE(Template, Template, TemplateTemplateParm) DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 2fcdaa3e2959..2b12bb5c1b6d 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -43,17 +43,17 @@ public: ~ObjCListBase() { assert(List == 0 && "Destroy should have been called before dtor"); } - + void Destroy(ASTContext &Ctx); - + unsigned size() const { return NumElts; } bool empty() const { return NumElts == 0; } - + protected: void set(void *const* InList, unsigned Elts, ASTContext &Ctx); }; - - + + /// ObjCList - This is a simple template class used to hold various lists of /// decls etc, which is heavily used by the ObjC front-end. This only use case /// this supports is setting the list all at once and then reading elements out @@ -64,30 +64,30 @@ public: void set(T* const* InList, unsigned Elts, ASTContext &Ctx) { ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx); } - + typedef T* const * iterator; iterator begin() const { return (iterator)List; } iterator end() const { return (iterator)List+NumElts; } - + T* operator[](unsigned Idx) const { assert(Idx < NumElts && "Invalid access"); return (T*)List[Idx]; } }; - + /// ObjCMethodDecl - Represents an instance or class method declaration. /// ObjC methods can be declared within 4 contexts: class interfaces, /// categories, protocols, and class implementations. While C++ member -/// functions leverage C syntax, Objective-C method syntax is modeled after -/// Smalltalk (using colons to specify argument types/expressions). +/// functions leverage C syntax, Objective-C method syntax is modeled after +/// Smalltalk (using colons to specify argument types/expressions). /// Here are some brief examples: /// /// Setter/getter instance methods: /// - (void)setMenu:(NSMenu *)menu; -/// - (NSMenu *)menu; -/// +/// - (NSMenu *)menu; +/// /// Instance method that takes 2 NSView arguments: /// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView; /// @@ -106,27 +106,27 @@ private: /// instance (true) or class (false) method. bool IsInstance : 1; bool IsVariadic : 1; - + // Synthesized declaration method for a property setter/getter bool IsSynthesized : 1; - + // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum /// @required/@optional unsigned DeclImplementation : 2; - + // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum /// in, inout, etc. unsigned objcDeclQualifier : 6; - + // Type of this method. QualType MethodDeclType; /// ParamInfo - List of pointers to VarDecls for the formal parameters of this /// Method. ObjCList<ParmVarDecl> ParamInfo; - + /// List of attributes for this method declaration. - SourceLocation EndLoc; // the location of the ';' or '{'. - + SourceLocation EndLoc; // the location of the ';' or '}'. + // The following are only used for method definitions, null otherwise. // FIXME: space savings opportunity, consider a sub-class. Stmt *Body; @@ -137,7 +137,7 @@ private: /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily /// constructed by createImplicitParams. ImplicitParamDecl *CmdDecl; - + ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, DeclContext *contextDecl, @@ -150,48 +150,55 @@ private: IsInstance(isInstance), IsVariadic(isVariadic), IsSynthesized(isSynthesized), DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None), - MethodDeclType(T), + MethodDeclType(T), EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {} virtual ~ObjCMethodDecl() {} - + + /// \brief A definition will return its interface declaration. + /// An interface declaration will return its definition. + /// Otherwise it will return itself. + virtual ObjCMethodDecl *getNextRedeclaration(); + public: - + /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); static ObjCMethodDecl *Create(ASTContext &C, - SourceLocation beginLoc, + SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, DeclContext *contextDecl, bool isInstance = true, bool isVariadic = false, bool isSynthesized = false, ImplementationControl impControl = None); - + + virtual ObjCMethodDecl *getCanonicalDecl(); + ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(objcDeclQualifier); } void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } - + // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } SourceLocation getLocEnd() const { return EndLoc; } void setEndLoc(SourceLocation Loc) { EndLoc = Loc; } - SourceRange getSourceRange() const { - return SourceRange(getLocation(), EndLoc); + virtual SourceRange getSourceRange() const { + return SourceRange(getLocation(), EndLoc); } - + ObjCInterfaceDecl *getClassInterface(); const ObjCInterfaceDecl *getClassInterface() const { return const_cast<ObjCMethodDecl*>(this)->getClassInterface(); } - + Selector getSelector() const { return getDeclName().getObjCSelector(); } - unsigned getSynthesizedMethodSize() const; + QualType getResultType() const { return MethodDeclType; } void setResultType(QualType T) { MethodDeclType = T; } - + // Iterator access to formal parameters. unsigned param_size() const { return ParamInfo.size(); } typedef ObjCList<ParmVarDecl>::iterator param_iterator; @@ -212,7 +219,7 @@ public: arg_type_iterator arg_type_end() const { return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType)); } - + /// createImplicitParams - Used to lazily create the self and cmd /// implict parameters. This must be called prior to using getSelfDecl() /// or getCmdDecl(). The call is ignored if the implicit paramters @@ -223,31 +230,34 @@ public: void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; } ImplicitParamDecl * getCmdDecl() const { return CmdDecl; } void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; } - + bool isInstanceMethod() const { return IsInstance; } void setInstanceMethod(bool isInst) { IsInstance = isInst; } bool isVariadic() const { return IsVariadic; } void setVariadic(bool isVar) { IsVariadic = isVar; } - + bool isClassMethod() const { return !IsInstance; } bool isSynthesized() const { return IsSynthesized; } void setSynthesized(bool isSynth) { IsSynthesized = isSynth; } - + // Related to protocols declared in @protocol - void setDeclImplementation(ImplementationControl ic) { - DeclImplementation = ic; + void setDeclImplementation(ImplementationControl ic) { + DeclImplementation = ic; } - ImplementationControl getImplementationControl() const { - return ImplementationControl(DeclImplementation); + ImplementationControl getImplementationControl() const { + return ImplementationControl(DeclImplementation); } - virtual Stmt *getBody() const { - return (Stmt*) Body; + virtual Stmt *getBody() const { + return (Stmt*) Body; } CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; } void setBody(Stmt *B) { Body = B; } + /// \brief Returns whether this specific method is a definition. + bool isThisDeclarationADefinition() const { return Body; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; } static bool classof(const ObjCMethodDecl *D) { return true; } @@ -263,9 +273,9 @@ public: struct ObjCMethodList { ObjCMethodDecl *Method; ObjCMethodList *Next; - + ObjCMethodList() { - Method = 0; + Method = 0; Next = 0; } ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { @@ -275,15 +285,14 @@ struct ObjCMethodList { }; /// ObjCContainerDecl - Represents a container for method declarations. -/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, and -/// ObjCProtocolDecl. -/// FIXME: Use for ObjC implementation decls. +/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, +/// ObjCProtocolDecl, and ObjCImplDecl. /// class ObjCContainerDecl : public NamedDecl, public DeclContext { SourceLocation AtEndLoc; // marks the end of the method container. public: - ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L, + ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : NamedDecl(DK, DC, L, Id), DeclContext(DK) {} @@ -291,24 +300,24 @@ public: // Iterator access to properties. typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator; - prop_iterator prop_begin() const { + prop_iterator prop_begin() const { return prop_iterator(decls_begin()); } - prop_iterator prop_end() const { + prop_iterator prop_end() const { return prop_iterator(decls_end()); } - + // Iterator access to instance/class methods. typedef specific_decl_iterator<ObjCMethodDecl> method_iterator; - method_iterator meth_begin() const { + method_iterator meth_begin() const { return method_iterator(decls_begin()); } - method_iterator meth_end() const { + method_iterator meth_end() const { return method_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isInstanceMethod> + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod> instmeth_iterator; instmeth_iterator instmeth_begin() const { return instmeth_iterator(decls_begin()); @@ -317,8 +326,8 @@ public: return instmeth_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isClassMethod> + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod> classmeth_iterator; classmeth_iterator classmeth_begin() const { return classmeth_iterator(decls_begin()); @@ -328,23 +337,28 @@ public: } // Get the local instance/class method declared in this interface. - ObjCMethodDecl *getInstanceMethod(Selector Sel) const; - ObjCMethodDecl *getClassMethod(Selector Sel) const; + ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *getInstanceMethod(Selector Sel) const { + return getMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *getClassMethod(Selector Sel) const { + return getMethod(Sel, false/*isInstance*/); + } ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; - ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const { - return isInstance ? getInstanceMethod(Sel) : getClassMethod(Sel); - } - ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; // Marks the end of the container. SourceLocation getAtEndLoc() const { return AtEndLoc; } void setAtEndLoc(SourceLocation L) { AtEndLoc = L; } - + + virtual SourceRange getSourceRange() const { + return SourceRange(getLocation(), getAtEndLoc()); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { - return D->getKind() >= ObjCContainerFirst && + return D->getKind() >= ObjCContainerFirst && D->getKind() <= ObjCContainerLast; } static bool classof(const ObjCContainerDecl *D) { return true; } @@ -360,11 +374,11 @@ public: /// ObjCInterfaceDecl - Represents an ObjC class declaration. For example: /// /// // MostPrimitive declares no super class (not particularly useful). -/// @interface MostPrimitive +/// @interface MostPrimitive /// // no instance variables or methods. /// @end /// -/// // NSResponder inherits from NSObject & implements NSCoding (a protocol). +/// // NSResponder inherits from NSObject & implements NSCoding (a protocol). /// @interface NSResponder : NSObject <NSCoding> /// { // instance variables are represented by ObjCIvarDecl. /// id nextResponder; // nextResponder instance variable. @@ -383,32 +397,32 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType mutable Type *TypeForDecl; friend class ASTContext; - + /// Class's super class. ObjCInterfaceDecl *SuperClass; - + /// Protocols referenced in interface header declaration ObjCList<ObjCProtocolDecl> ReferencedProtocols; - + /// Instance variables in the interface. ObjCList<ObjCIvarDecl> IVars; - + /// List of categories defined for this class. /// FIXME: Why is this a linked list?? ObjCCategoryDecl *CategoryList; - + bool ForwardDecl:1; // declared with @class. bool InternalInterface:1; // true - no @interface for @implementation - + SourceLocation ClassLoc; // location of the class identifier. SourceLocation SuperClassLoc; // location of the super class identifier. SourceLocation EndLoc; // marks the '>', '}', or identifier. ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, SourceLocation CLoc, bool FD, bool isInternal); - + virtual ~ObjCInterfaceDecl() {} - + public: /// Destroy - Call destructors and release memory. @@ -416,16 +430,27 @@ public: static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, - IdentifierInfo *Id, + IdentifierInfo *Id, SourceLocation ClassLoc = SourceLocation(), bool ForwardDecl = false, bool isInternal = false); - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { - return ReferencedProtocols; + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + return ReferencedProtocols; } - + + ObjCImplementationDecl *getImplementation() const; + void setImplementation(ObjCImplementationDecl *ImplD); + ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + // Get the local instance/class method declared in a category. + ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const { + return isInstance ? getInstanceMethod(Sel) + : getClassMethod(Sel); + } + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } @@ -436,29 +461,34 @@ public: ivar_iterator ivar_end() const { return IVars.end(); } unsigned ivar_size() const { return IVars.size(); } bool ivar_empty() const { return IVars.empty(); } - + /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num, ASTContext &C) { ReferencedProtocols.set(List, Num, C); } - + + /// mergeClassExtensionProtocolList - Merge class extension's protocol list + /// into the protocol list for this class. + void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, unsigned Num, + ASTContext &C); + void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) { IVars.set(List, Num, C); } bool isForwardDecl() const { return ForwardDecl; } void setForwardDecl(bool val) { ForwardDecl = val; } - + ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } - + ObjCCategoryDecl* getCategoryList() const { return CategoryList; } - void setCategoryList(ObjCCategoryDecl *category) { + void setCategoryList(ObjCCategoryDecl *category) { CategoryList = category; } - + /// isSuperClassOf - Return true if this class is the specified class or is a /// super class of the specified interface class. bool isSuperClassOf(const ObjCInterfaceDecl *I) const { @@ -470,7 +500,7 @@ public: } return false; } - + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName, ObjCInterfaceDecl *&ClassDeclared); ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) { @@ -480,26 +510,41 @@ public: // Lookup a method. First, we search locally. If a method isn't // found, we search referenced protocols and class categories. - ObjCMethodDecl *lookupInstanceMethod(Selector Sel); - ObjCMethodDecl *lookupClassMethod(Selector Sel); + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { + return lookupMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { + return lookupMethod(Sel, false/*isInstance*/); + } ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); + + // Lookup a method in the classes implementation hierarchy. + ObjCMethodDecl *lookupPrivateInstanceMethod(const Selector &Sel); - // Location information, modeled after the Stmt API. + // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } // '@'interface SourceLocation getLocEnd() const { return EndLoc; } void setLocEnd(SourceLocation LE) { EndLoc = LE; }; - + void setClassLoc(SourceLocation Loc) { ClassLoc = Loc; } SourceLocation getClassLoc() const { return ClassLoc; } void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; } SourceLocation getSuperClassLoc() const { return SuperClassLoc; } - + /// isImplicitInterfaceDecl - check that this is an implicitly declared /// ObjCInterfaceDecl node. This is for legacy objective-c @implementation /// declaration without an @interface declaration. bool isImplicitInterfaceDecl() const { return InternalInterface; } void setImplicitInterfaceDecl(bool val) { InternalInterface = val; } - + + /// ClassImplementsProtocol - Checks that 'lProto' protocol + /// has been implemented in IDecl class, its super class or categories (if + /// lookupCategory is true). + bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID = false); + // Low-level accessor Type *getTypeForDecl() const { return TypeForDecl; } void setTypeForDecl(Type *TD) const { TypeForDecl = TD; } @@ -528,18 +573,19 @@ public: enum AccessControl { None, Private, Protected, Public, Package }; - + private: ObjCIvarDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, AccessControl ac, Expr *BW) - : FieldDecl(ObjCIvar, DC, L, Id, T, BW, /*Mutable=*/false), + QualType T, DeclaratorInfo *DInfo, AccessControl ac, Expr *BW) + : FieldDecl(ObjCIvar, DC, L, Id, T, DInfo, BW, /*Mutable=*/false), DeclAccess(ac) {} - + public: static ObjCIvarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, + DeclaratorInfo *DInfo, AccessControl ac, Expr *BW = NULL); - + void setAccessControl(AccessControl ac) { DeclAccess = ac; } AccessControl getAccessControl() const { return AccessControl(DeclAccess); } @@ -547,7 +593,7 @@ public: AccessControl getCanonicalAccessControl() const { return DeclAccess == None ? Protected : AccessControl(DeclAccess); } - + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == ObjCIvar; } static bool classof(const ObjCIvarDecl *D) { return true; } @@ -556,21 +602,23 @@ private: unsigned DeclAccess : 3; }; - + /// ObjCAtDefsFieldDecl - Represents a field declaration created by an /// @defs(...). class ObjCAtDefsFieldDecl : public FieldDecl { private: ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW) - : FieldDecl(ObjCAtDefsField, DC, L, Id, T, BW, /*Mutable=*/false) {} - + : FieldDecl(ObjCAtDefsField, DC, L, Id, T, + /*DInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ? + BW, /*Mutable=*/false) {} + public: static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW); - + virtual void Destroy(ASTContext& C); // Implement isa/cast/dyncast/etc. @@ -579,8 +627,8 @@ public: }; /// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols -/// declare a pure abstract type (i.e no instance variables are permitted). -/// Protocols orginally drew inspiration from C++ pure virtual functions (a C++ +/// declare a pure abstract type (i.e no instance variables are permitted). +/// Protocols orginally drew inspiration from C++ pure virtual functions (a C++ /// feature with nice semantics and lousy syntax:-). Here is an example: /// /// @protocol NSDraggingInfo <refproto1, refproto2> @@ -597,7 +645,7 @@ public: /// /// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and /// protocols are in distinct namespaces. For example, Cocoa defines both -/// an NSObject protocol and class (which isn't allowed in Java). As a result, +/// an NSObject protocol and class (which isn't allowed in Java). As a result, /// protocols are referenced using angle brackets as follows: /// /// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo; @@ -605,78 +653,83 @@ public: class ObjCProtocolDecl : public ObjCContainerDecl { /// Referenced protocols ObjCList<ObjCProtocolDecl> ReferencedProtocols; - + bool isForwardProtoDecl; // declared with @protocol. - + SourceLocation EndLoc; // marks the '>' or identifier. - + ObjCProtocolDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) - : ObjCContainerDecl(ObjCProtocol, DC, L, Id), + : ObjCContainerDecl(ObjCProtocol, DC, L, Id), isForwardProtoDecl(true) { } - + virtual ~ObjCProtocolDecl() {} - + public: - static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, + static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id); /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { return ReferencedProtocols; } typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } unsigned protocol_size() const { return ReferencedProtocols.size(); } - + /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, ASTContext &C) { ReferencedProtocols.set(List, Num, C); } - + ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); - + // Lookup a method. First, we search locally. If a method isn't // found, we search referenced protocols and class categories. - ObjCMethodDecl *lookupInstanceMethod(Selector Sel); - ObjCMethodDecl *lookupClassMethod(Selector Sel); - + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { + return lookupMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { + return lookupMethod(Sel, false/*isInstance*/); + } + bool isForwardDecl() const { return isForwardProtoDecl; } void setForwardDecl(bool val) { isForwardProtoDecl = val; } - // Location information, modeled after the Stmt API. + // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } // '@'protocol SourceLocation getLocEnd() const { return EndLoc; } void setLocEnd(SourceLocation LE) { EndLoc = LE; }; - + static bool classof(const Decl *D) { return D->getKind() == ObjCProtocol; } static bool classof(const ObjCProtocolDecl *D) { return true; } }; - + /// ObjCClassDecl - Specifies a list of forward class declarations. For example: /// /// @class NSCursor, NSImage, NSPasteboard, NSWindow; /// class ObjCClassDecl : public Decl { ObjCList<ObjCInterfaceDecl> ForwardDecls; - - ObjCClassDecl(DeclContext *DC, SourceLocation L, + + ObjCClassDecl(DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *const *Elts, unsigned nElts, ASTContext &C); virtual ~ObjCClassDecl() {} public: - + /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - + static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ObjCInterfaceDecl *const *Elts = 0, + ObjCInterfaceDecl *const *Elts = 0, unsigned nElts = 0); - + typedef ObjCList<ObjCInterfaceDecl>::iterator iterator; iterator begin() const { return ForwardDecls.begin(); } iterator end() const { return ForwardDecls.end(); } @@ -686,33 +739,33 @@ public: void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, unsigned Num) { ForwardDecls.set(List, Num, C); } - + static bool classof(const Decl *D) { return D->getKind() == ObjCClass; } static bool classof(const ObjCClassDecl *D) { return true; } }; /// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations. /// For example: -/// +/// /// @protocol NSTextInput, NSChangeSpelling, NSDraggingInfo; -/// +/// class ObjCForwardProtocolDecl : public Decl { ObjCList<ObjCProtocolDecl> ReferencedProtocols; - + ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, - ASTContext &C); + ASTContext &C); virtual ~ObjCForwardProtocolDecl() {} - + public: static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation L, ObjCProtocolDecl *const *Elts = 0, unsigned Num = 0); /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } @@ -731,7 +784,7 @@ public: /// ObjCCategoryDecl - Represents a category declaration. A category allows /// you to add methods to an existing class (without subclassing or modifying -/// the original class interface or implementation:-). Categories don't allow +/// the original class interface or implementation:-). Categories don't allow /// you to add instance data. The following example adds "myMethod" to all /// NSView's within a process: /// @@ -743,51 +796,54 @@ public: /// several files (a feature more naturally supported in C++). /// /// Categories were originally inspired by dynamic languages such as Common -/// Lisp and Smalltalk. More traditional class-based languages (C++, Java) +/// Lisp and Smalltalk. More traditional class-based languages (C++, Java) /// don't support this level of dynamism, which is both powerful and dangerous. /// class ObjCCategoryDecl : public ObjCContainerDecl { /// Interface belonging to this category ObjCInterfaceDecl *ClassInterface; - + /// referenced protocols in this category. ObjCList<ObjCProtocolDecl> ReferencedProtocols; - + /// Next category belonging to this class. /// FIXME: this should not be a singly-linked list. Move storage elsewhere. ObjCCategoryDecl *NextClassCategory; - + SourceLocation EndLoc; // marks the '>' or identifier. - + ObjCCategoryDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : ObjCContainerDecl(ObjCCategory, DC, L, Id), ClassInterface(0), NextClassCategory(0){ } public: - + static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id); - + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; } - + + ObjCCategoryImplDecl *getImplementation() const; + void setImplementation(ObjCCategoryImplDecl *ImplD); + /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, ASTContext &C) { ReferencedProtocols.set(List, Num, C); } - - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { return ReferencedProtocols; } - + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } unsigned protocol_size() const { return ReferencedProtocols.size(); } - + ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } void setNextClassCategory(ObjCCategoryDecl *Cat) { NextClassCategory = Cat; @@ -796,98 +852,67 @@ public: NextClassCategory = ClassInterface->getCategoryList(); ClassInterface->setCategoryList(this); } - // Location information, modeled after the Stmt API. + // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } // '@'interface SourceLocation getLocEnd() const { return EndLoc; } void setLocEnd(SourceLocation LE) { EndLoc = LE; }; - + static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; } static bool classof(const ObjCCategoryDecl *D) { return true; } }; -class ObjCImplDecl : public NamedDecl, public DeclContext { +class ObjCImplDecl : public ObjCContainerDecl { /// Class interface for this category implementation ObjCInterfaceDecl *ClassInterface; - - SourceLocation EndLoc; - + protected: ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *classInterface) - : NamedDecl(DK, DC, L, - classInterface? classInterface->getDeclName() - : DeclarationName()), - DeclContext(DK), ClassInterface(classInterface) {} - + : ObjCContainerDecl(DK, DC, L, + classInterface? classInterface->getIdentifier() : 0), + ClassInterface(classInterface) {} + public: virtual ~ObjCImplDecl() {} - + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } - void setClassInterface(ObjCInterfaceDecl *IFace) { ClassInterface = IFace; } + void setClassInterface(ObjCInterfaceDecl *IFace); - void addInstanceMethod(ObjCMethodDecl *method) { + void addInstanceMethod(ObjCMethodDecl *method) { // FIXME: Context should be set correctly before we get here. method->setLexicalDeclContext(this); - addDecl(method); + addDecl(method); } - void addClassMethod(ObjCMethodDecl *method) { + void addClassMethod(ObjCMethodDecl *method) { // FIXME: Context should be set correctly before we get here. method->setLexicalDeclContext(this); - addDecl(method); + addDecl(method); } - - // Get the local instance/class method declared in this interface. - ObjCMethodDecl *getInstanceMethod(Selector Sel) const; - ObjCMethodDecl *getClassMethod(Selector Sel) const; - ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const { - return isInstance ? getInstanceMethod(Sel) - : getClassMethod(Sel); - } - + void addPropertyImplementation(ObjCPropertyImplDecl *property); - + ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const; ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const; // Iterator access to properties. typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator; - propimpl_iterator propimpl_begin() const { + propimpl_iterator propimpl_begin() const { return propimpl_iterator(decls_begin()); } - propimpl_iterator propimpl_end() const { + propimpl_iterator propimpl_end() const { return propimpl_iterator(decls_end()); } - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isInstanceMethod> - instmeth_iterator; - instmeth_iterator instmeth_begin() const { - return instmeth_iterator(decls_begin()); - } - instmeth_iterator instmeth_end() const { - return instmeth_iterator(decls_end()); - } - - typedef filtered_decl_iterator<ObjCMethodDecl, - &ObjCMethodDecl::isClassMethod> - classmeth_iterator; - classmeth_iterator classmeth_begin() const { - return classmeth_iterator(decls_begin()); - } - classmeth_iterator classmeth_end() const { - return classmeth_iterator(decls_end()); + static bool classof(const Decl *D) { + return D->getKind() >= ObjCImplFirst && D->getKind() <= ObjCImplLast; } - - // Location information, modeled after the Stmt API. - SourceLocation getLocStart() const { return getLocation(); } - SourceLocation getLocEnd() const { return EndLoc; } - void setLocEnd(SourceLocation LE) { EndLoc = LE; }; + static bool classof(const ObjCImplDecl *D) { return true; } }; - -/// ObjCCategoryImplDecl - An object of this class encapsulates a category -/// @implementation declaration. If a category class has declaration of a -/// property, its implementation must be specified in the category's + +/// ObjCCategoryImplDecl - An object of this class encapsulates a category +/// @implementation declaration. If a category class has declaration of a +/// property, its implementation must be specified in the category's /// @implementation declaration. Example: /// @interface I @end /// @interface I(CATEGORY) @@ -909,34 +934,30 @@ public: static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ObjCInterfaceDecl *classInterface); - + /// getIdentifier - Get the identifier that names the class /// interface associated with this implementation. - IdentifierInfo *getIdentifier() const { - return Id; + IdentifierInfo *getIdentifier() const { + return Id; } void setIdentifier(IdentifierInfo *II) { Id = II; } + ObjCCategoryDecl *getCategoryClass() const; + /// getNameAsCString - Get the name of identifier for the class /// interface associated with this implementation as a C string /// (const char*). const char *getNameAsCString() const { return Id ? Id->getName() : ""; } - + /// @brief Get the name of the class associated with this interface. std::string getNameAsString() const { return Id ? Id->getName() : ""; } - + static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;} static bool classof(const ObjCCategoryImplDecl *D) { return true; } - static DeclContext *castToDeclContext(const ObjCCategoryImplDecl *D) { - return static_cast<DeclContext *>(const_cast<ObjCCategoryImplDecl*>(D)); - } - static ObjCCategoryImplDecl *castFromDeclContext(const DeclContext *DC) { - return static_cast<ObjCCategoryImplDecl *>(const_cast<DeclContext*>(DC)); - } }; /// ObjCImplementationDecl - Represents a class definition - this is where @@ -948,30 +969,30 @@ public: /// @end /// @endcode /// -/// Typically, instance variables are specified in the class interface, +/// Typically, instance variables are specified in the class interface, /// *not* in the implementation. Nevertheless (for legacy reasons), we /// allow instance variables to be specified in the implementation. When /// specified, they need to be *identical* to the interface. /// -class ObjCImplementationDecl : public ObjCImplDecl { +class ObjCImplementationDecl : public ObjCImplDecl { /// Implementation Class's super class. ObjCInterfaceDecl *SuperClass; - - ObjCImplementationDecl(DeclContext *DC, SourceLocation L, + + ObjCImplementationDecl(DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl) - : ObjCImplDecl(ObjCImplementation, DC, L, classInterface), + : ObjCImplDecl(ObjCImplementation, DC, L, classInterface), SuperClass(superDecl){} -public: - static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, +public: + static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl); - + /// getIdentifier - Get the identifier that names the class /// interface associated with this implementation. - IdentifierInfo *getIdentifier() const { - return getClassInterface()->getIdentifier(); + IdentifierInfo *getIdentifier() const { + return getClassInterface()->getIdentifier(); } /// getNameAsCString - Get the name of identifier for the class @@ -989,41 +1010,35 @@ public: const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } ObjCInterfaceDecl *getSuperClass() { return SuperClass; } - + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } - + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; - ivar_iterator ivar_begin() const { - return ivar_iterator(decls_begin()); + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); } - ivar_iterator ivar_end() const { + ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); } - unsigned ivar_size() const { + unsigned ivar_size() const { return std::distance(ivar_begin(), ivar_end()); } - bool ivar_empty() const { + bool ivar_empty() const { return ivar_begin() == ivar_end(); } - + static bool classof(const Decl *D) { return D->getKind() == ObjCImplementation; } static bool classof(const ObjCImplementationDecl *D) { return true; } - static DeclContext *castToDeclContext(const ObjCImplementationDecl *D) { - return static_cast<DeclContext *>(const_cast<ObjCImplementationDecl*>(D)); - } - static ObjCImplementationDecl *castFromDeclContext(const DeclContext *DC) { - return static_cast<ObjCImplementationDecl *>(const_cast<DeclContext*>(DC)); - } }; -/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is +/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is /// declared as @compatibility_alias alias class. class ObjCCompatibleAliasDecl : public NamedDecl { /// Class that this is an alias of. ObjCInterfaceDecl *AliasedClass; - + ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ObjCInterfaceDecl* aliasedClass) : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} @@ -1035,12 +1050,12 @@ public: const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; } - + static bool classof(const Decl *D) { return D->getKind() == ObjCCompatibleAlias; } static bool classof(const ObjCCompatibleAliasDecl *D) { return true; } - + }; /// ObjCPropertyDecl - Represents one property declaration in an interface. @@ -1050,13 +1065,13 @@ public: class ObjCPropertyDecl : public NamedDecl { public: enum PropertyAttributeKind { - OBJC_PR_noattr = 0x00, - OBJC_PR_readonly = 0x01, + OBJC_PR_noattr = 0x00, + OBJC_PR_readonly = 0x01, OBJC_PR_getter = 0x02, - OBJC_PR_assign = 0x04, - OBJC_PR_readwrite = 0x08, + OBJC_PR_assign = 0x04, + OBJC_PR_readwrite = 0x08, OBJC_PR_retain = 0x10, - OBJC_PR_copy = 0x20, + OBJC_PR_copy = 0x20, OBJC_PR_nonatomic = 0x40, OBJC_PR_setter = 0x80 }; @@ -1066,27 +1081,27 @@ public: private: QualType DeclType; unsigned PropertyAttributes : 8; - + // @required/@optional unsigned PropertyImplementation : 2; - + Selector GetterName; // getter name of NULL if no getter Selector SetterName; // setter name of NULL if no setter - + ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property - ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T) : NamedDecl(ObjCProperty, DC, L, Id), DeclType(T), PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None), - GetterName(Selector()), + GetterName(Selector()), SetterName(Selector()), GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {} public: - static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T, PropertyControl propControl = None); QualType getType() const { return DeclType; } @@ -1095,14 +1110,14 @@ public: PropertyAttributeKind getPropertyAttributes() const { return PropertyAttributeKind(PropertyAttributes); } - void setPropertyAttributes(PropertyAttributeKind PRVal) { + void setPropertyAttributes(PropertyAttributeKind PRVal) { PropertyAttributes |= PRVal; } void makeitReadWriteAttribute(void) { PropertyAttributes &= ~OBJC_PR_readonly; PropertyAttributes |= OBJC_PR_readwrite; - } + } // Helper methods for accessing attributes. @@ -1124,38 +1139,38 @@ public: Selector getGetterName() const { return GetterName; } void setGetterName(Selector Sel) { GetterName = Sel; } - + Selector getSetterName() const { return SetterName; } void setSetterName(Selector Sel) { SetterName = Sel; } - + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; } - + // Related to @optional/@required declared in @protocol void setPropertyImplementation(PropertyControl pc) { PropertyImplementation = pc; } PropertyControl getPropertyImplementation() const { return PropertyControl(PropertyImplementation); - } - + } + void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } ObjCIvarDecl *getPropertyIvarDecl() const { return PropertyIvarDecl; } - + static bool classof(const Decl *D) { return D->getKind() == ObjCProperty; } static bool classof(const ObjCPropertyDecl *D) { return true; } }; -/// ObjCPropertyImplDecl - Represents implementation declaration of a property +/// ObjCPropertyImplDecl - Represents implementation declaration of a property /// in a class or category implementation block. For example: /// @synthesize prop1 = ivar1; /// @@ -1174,21 +1189,24 @@ private: ObjCIvarDecl *PropertyIvarDecl; ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, - ObjCPropertyDecl *property, - Kind PK, + ObjCPropertyDecl *property, + Kind PK, ObjCIvarDecl *ivarDecl) - : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), + : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl) { assert (PK == Dynamic || PropertyIvarDecl); } - + public: static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation atLoc, SourceLocation L, - ObjCPropertyDecl *property, - Kind PK, + SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, ObjCIvarDecl *ivarDecl); + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, getLocation()); + } SourceLocation getLocStart() const { return AtLoc; } void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } @@ -1200,7 +1218,7 @@ public: Kind getPropertyImplementation() const { return PropertyIvarDecl ? Synthesize : Dynamic; } - + ObjCIvarDecl *getPropertyIvarDecl() const { return PropertyIvarDecl; } @@ -1209,7 +1227,7 @@ public: static bool classof(const Decl *D) { return D->getKind() == ObjCPropertyImpl; } - static bool classof(const ObjCPropertyImplDecl *D) { return true; } + static bool classof(const ObjCPropertyImplDecl *D) { return true; } }; } // end namespace clang diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 5d0fe158e054..8d44676124fb 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -49,38 +49,38 @@ class TemplateParameterList { unsigned NumParams; TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, - Decl **Params, unsigned NumParams, + NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc); public: - static TemplateParameterList *Create(ASTContext &C, + static TemplateParameterList *Create(ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - Decl **Params, + NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc); /// iterator - Iterates through the template parameters in this list. - typedef Decl** iterator; + typedef NamedDecl** iterator; /// const_iterator - Iterates through the template parameters in this list. - typedef Decl* const* const_iterator; + typedef NamedDecl* const* const_iterator; - iterator begin() { return reinterpret_cast<Decl **>(this + 1); } + iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); } const_iterator begin() const { - return reinterpret_cast<Decl * const *>(this + 1); + return reinterpret_cast<NamedDecl * const *>(this + 1); } iterator end() { return begin() + NumParams; } const_iterator end() const { return begin() + NumParams; } unsigned size() const { return NumParams; } - Decl* getParam(unsigned Idx) { + NamedDecl* getParam(unsigned Idx) { assert(Idx < size() && "Template parameter index out-of-range"); return begin()[Idx]; } - const Decl* getParam(unsigned Idx) const { + const NamedDecl* getParam(unsigned Idx) const { assert(Idx < size() && "Template parameter index out-of-range"); return begin()[Idx]; } @@ -115,10 +115,10 @@ class TemplateArgument { bool CopyArgs; } Args; }; - + /// \brief Location of the beginning of this template argument. SourceLocation StartLoc; - + public: /// \brief The type of template argument we're storing. enum ArgKind { @@ -133,21 +133,21 @@ public: /// The template argument is a value- or type-dependent expression /// stored in an Expr*. Expression = 4, - + /// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. Pack = 5 } Kind; - + /// \brief Construct an empty, invalid template argument. TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { } - + /// \brief Construct a template type argument. TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) { TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); StartLoc = Loc; } - + /// \brief Construct a template argument that refers to a /// declaration, which is either an external declaration or a /// template declaration. @@ -156,7 +156,7 @@ public: TypeOrValue = reinterpret_cast<uintptr_t>(D); StartLoc = Loc; } - + /// \brief Construct an integral constant template argument. TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value, QualType Type) @@ -165,14 +165,14 @@ public: Integer.Type = Type.getAsOpaquePtr(); StartLoc = Loc; } - - /// \brief Construct a template argument that is an expression. + + /// \brief Construct a template argument that is an expression. /// /// This form of template argument only occurs in template argument /// lists used for dependent types and for expression; it will not /// occur in a non-dependent, canonical template argument list. TemplateArgument(Expr *E); - + /// \brief Copy constructor for a template argument. TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { if (Kind == Integral) { @@ -188,27 +188,27 @@ public: TypeOrValue = Other.TypeOrValue; StartLoc = Other.StartLoc; } - + TemplateArgument& operator=(const TemplateArgument& Other) { // FIXME: Does not provide the strong guarantee for exception // safety. using llvm::APSInt; - + // FIXME: Handle Packs assert(Kind != Pack && "FIXME: Handle packs"); assert(Other.Kind != Pack && "FIXME: Handle packs"); - + if (Kind == Other.Kind && Kind == Integral) { // Copy integral values. *this->getAsIntegral() = *Other.getAsIntegral(); - Integer.Type = Other.Integer.Type; + Integer.Type = Other.Integer.Type; } else { // Destroy the current integral value, if that's what we're holding. if (Kind == Integral) getAsIntegral()->~APSInt(); - + Kind = Other.Kind; - + if (Other.Kind == Integral) { new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); Integer.Type = Other.Integer.Type; @@ -216,133 +216,131 @@ public: TypeOrValue = Other.TypeOrValue; } StartLoc = Other.StartLoc; - + return *this; } - + ~TemplateArgument() { using llvm::APSInt; - + if (Kind == Integral) getAsIntegral()->~APSInt(); else if (Kind == Pack && Args.CopyArgs) delete[] Args.Args; } - + /// \brief Return the kind of stored template argument. ArgKind getKind() const { return Kind; } - + /// \brief Determine whether this template argument has no value. bool isNull() const { return Kind == Null; } - + /// \brief Retrieve the template argument as a type. QualType getAsType() const { if (Kind != Type) return QualType(); - - return QualType::getFromOpaquePtr( - reinterpret_cast<void*>(TypeOrValue)); + + return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue)); } - + /// \brief Retrieve the template argument as a declaration. Decl *getAsDecl() const { if (Kind != Declaration) return 0; return reinterpret_cast<Decl *>(TypeOrValue); } - + /// \brief Retrieve the template argument as an integral value. llvm::APSInt *getAsIntegral() { if (Kind != Integral) return 0; return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]); } - + const llvm::APSInt *getAsIntegral() const { return const_cast<TemplateArgument*>(this)->getAsIntegral(); } - + /// \brief Retrieve the type of the integral value. QualType getIntegralType() const { if (Kind != Integral) return QualType(); - + return QualType::getFromOpaquePtr(Integer.Type); } - + void setIntegralType(QualType T) { - assert(Kind == Integral && + assert(Kind == Integral && "Cannot set the integral type of a non-integral template argument"); Integer.Type = T.getAsOpaquePtr(); }; - + /// \brief Retrieve the template argument as an expression. Expr *getAsExpr() const { if (Kind != Expression) return 0; - + 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 + + /// \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; } - + /// \brief Construct a template argument pack. void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs); - + /// \brief Used to insert TemplateArguments into FoldingSets. - void Profile(llvm::FoldingSetNodeID &ID) const { + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const { ID.AddInteger(Kind); switch (Kind) { case Null: break; - + case Type: getAsType().Profile(ID); break; - + case Declaration: - ID.AddPointer(getAsDecl()); // FIXME: Must be canonical! + ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); break; - + case Integral: getAsIntegral()->Profile(ID); getIntegralType().Profile(ID); break; - + case Expression: - // FIXME: We need a canonical representation of expressions. - ID.AddPointer(getAsExpr()); + getAsExpr()->Profile(ID, Context, true); break; - + case Pack: ID.AddInteger(Args.NumArgs); for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I].Profile(ID); + Args.Args[I].Profile(ID, Context); } } }; @@ -352,47 +350,47 @@ class TemplateArgumentListBuilder { TemplateArgument *StructuredArgs; unsigned MaxStructuredArgs; unsigned NumStructuredArgs; - + TemplateArgument *FlatArgs; unsigned MaxFlatArgs; unsigned NumFlatArgs; - + bool AddingToPack; unsigned PackBeginIndex; - + public: TemplateArgumentListBuilder(const TemplateParameterList *Parameters, unsigned NumTemplateArgs) - : StructuredArgs(0), MaxStructuredArgs(Parameters->size()), - NumStructuredArgs(0), FlatArgs(0), + : StructuredArgs(0), MaxStructuredArgs(Parameters->size()), + NumStructuredArgs(0), FlatArgs(0), MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0), AddingToPack(false), PackBeginIndex(0) { } - + void Append(const TemplateArgument& Arg); void BeginPack(); void EndPack(); - + void ReleaseArgs(); - - unsigned flatSize() const { + + unsigned flatSize() const { return NumFlatArgs; } const TemplateArgument *getFlatArguments() const { return FlatArgs; } - + unsigned structuredSize() const { // If we don't have any structured args, just reuse the flat size. if (!StructuredArgs) return flatSize(); - + return NumStructuredArgs; } const TemplateArgument *getStructuredArguments() const { // If we don't have any structured args, just reuse the flat args. if (!StructuredArgs) return getFlatArguments(); - + return StructuredArgs; } }; @@ -408,44 +406,47 @@ class TemplateArgumentList { /// The integer value will be non-zero to indicate that this /// template argument list does not own the pointer. llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments; - + /// \brief The number of template arguments in this template /// argument list. unsigned NumFlatArguments; - + llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments; unsigned NumStructuredArguments; - + public: TemplateArgumentList(ASTContext &Context, TemplateArgumentListBuilder &Builder, bool TakeArgs); + + /// \brief Produces a shallow copy of the given template argument list + TemplateArgumentList(const TemplateArgumentList &Other); ~TemplateArgumentList(); - + /// \brief Retrieve the template argument at a given index. - const TemplateArgument &get(unsigned Idx) const { + const TemplateArgument &get(unsigned Idx) const { assert(Idx < NumFlatArguments && "Invalid template argument index"); return getFlatArgumentList()[Idx]; } - + /// \brief Retrieve the template argument at a given index. const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); } - + /// \brief Retrieve the number of template arguments in this /// template argument list. unsigned size() const { return NumFlatArguments; } - + /// \brief Retrieve the number of template arguments in the /// flattened template argument list. unsigned flat_size() const { return NumFlatArguments; } - + /// \brief Retrieve the flattened template argument list. - const TemplateArgument *getFlatArgumentList() const { + const TemplateArgument *getFlatArgumentList() const { return FlatArguments.getPointer(); } }; - + //===----------------------------------------------------------------------===// // Kinds of Templates //===----------------------------------------------------------------------===// @@ -459,15 +460,13 @@ protected: // This is probably never used. TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0) - { } + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0) { } // Construct a template decl with the given name and parameters. // Used when there is not templated element (tt-params, alias?). TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params) - { } + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params) { } // Construct a template decl with name, parameters, and templated element. TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, @@ -499,82 +498,161 @@ protected: NamedDecl *TemplatedDecl; TemplateParameterList* TemplateParams; }; - -/// \brief Provides information about a function template specialization, + +/// \brief Provides information about a function template specialization, /// which is a FunctionDecl that has been explicitly specialization or /// instantiated from a function template. class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { public: - /// \brief The function template specialization that this structure + /// \brief The function template specialization that this structure /// describes. FunctionDecl *Function; - - /// \brief The function template from which this function template + + /// \brief The function template from which this function template /// specialization was generated. /// - /// The bit will be 0 for an implicit instantiation, 1 for an explicit - /// specialization. - llvm::PointerIntPair<FunctionTemplateDecl *, 1> Template; - + /// The two bits are contain the top 4 values of TemplateSpecializationKind. + llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template; + /// \brief The template arguments used to produce the function template /// specialization from the function template. const TemplateArgumentList *TemplateArguments; + + /// \brief The point at which this function template specialization was + /// first instantiated. + SourceLocation PointOfInstantiation; /// \brief Retrieve the template from which this function was specialized. FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(Template.getInt() + 1); + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode TSK_Undeclared for a function template specialization"); + Template.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this function + /// template specialization. + /// + /// The point of instantiation may be an invalid source location if this + /// function has yet to be instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } - /// \brief Determine whether this is an explicit specialization. - bool isExplicitSpecialization() const { return Template.getInt(); } - - /// \brief Set whether this is an explicit specialization or an implicit - /// instantiation. - void setExplicitSpecialization(bool ES) { - Template.setInt(ES); + /// \brief Set the (first) point of instantiation of this function template + /// specialization. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, TemplateArguments->getFlatArgumentList(), - TemplateArguments->flat_size()); + Profile(ID, TemplateArguments->getFlatArgumentList(), + TemplateArguments->flat_size(), + Function->getASTContext()); } - - static void - Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { + + static void + Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, ASTContext &Context) { ID.AddInteger(NumTemplateArgs); for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) - TemplateArgs[Arg].Profile(ID); - } + TemplateArgs[Arg].Profile(ID, Context); + } +}; + +/// \brief Provides information a specialization of a member of a class +/// template, which may be a member function, static data member, or +/// member class. +class MemberSpecializationInfo { + // The member declaration from which this member was instantiated, and the + // manner in which the instantiation occurred (in the lower two bits). + llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK; + + // The point at which this member was first instantiated. + SourceLocation PointOfInstantiation; + +public: + explicit + MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK) + : MemberAndTSK(IF, TSK - 1), PointOfInstantiation() { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + } + + /// \brief Retrieve the member declaration from which this member was + /// instantiated. + NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1); + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + MemberAndTSK.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this member. + /// If the point of instantiation is an invalid location, then this member + /// has not yet been instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the first point of instantiation. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } }; /// Declaration of a template function. -class FunctionTemplateDecl : public TemplateDecl { +class FunctionTemplateDecl : public TemplateDecl { protected: /// \brief Data that is common to all of the declarations of a given /// function template. struct Common { + Common() : InstantiatedFromMember(0, false) { } + /// \brief The function template specializations for this function /// template, including explicit specializations and instantiations. llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations; + + /// \brief The member function template from which this was most + /// directly instantiated (or null). + /// + /// The boolean value indicates whether this member function template + /// was explicitly specialized. + llvm::PointerIntPair<FunctionTemplateDecl*, 1, bool> InstantiatedFromMember; }; - + /// \brief A pointer to the previous declaration (if this is a redeclaration) /// or to the data that is common to all declarations of this function /// template. llvm::PointerUnion<Common*, FunctionTemplateDecl*> CommonOrPrev; - - /// \brief Retrieves the "common" pointer shared by all + + /// \brief Retrieves the "common" pointer shared by all /// (re-)declarations of the same function template. Calling this routine /// may implicitly allocate memory for the common pointer. Common *getCommonPtr(); - + FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl), CommonOrPrev((Common*)0) { } - + public: void Destroy(ASTContext &C); - + /// Get the underlying function declaration of the template. FunctionDecl *getTemplatedDecl() const { return static_cast<FunctionDecl*>(TemplatedDecl); @@ -585,7 +663,7 @@ public: llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() { return getCommonPtr()->Specializations; } - + /// \brief Retrieve the previous declaration of this function template, or /// NULL if no such declaration exists. const FunctionTemplateDecl *getPreviousDeclaration() const { @@ -597,12 +675,71 @@ public: FunctionTemplateDecl *getPreviousDeclaration() { return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>(); } - + /// \brief Set the previous declaration of this function template. void setPreviousDeclaration(FunctionTemplateDecl *Prev) { if (Prev) CommonOrPrev = Prev; } + + virtual FunctionTemplateDecl *getCanonicalDecl(); + + /// \brief Retrieve the member function template that this function template + /// was instantiated from. + /// + /// This routine will return non-NULL for member function templates of + /// class templates. For example, given: + /// + /// \code + /// template <typename T> + /// struct X { + /// template <typename U> void f(); + /// }; + /// \endcode + /// + /// X<int>::A<float> is a CXXMethodDecl (whose parent is X<int>, a + /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will + /// return X<int>::f, a FunctionTemplateDecl (whose parent is again + /// X<int>) for which getInstantiatedFromMemberTemplate() will return + /// X<T>::f, a FunctionTemplateDecl (whose parent is X<T>, a + /// ClassTemplateDecl). + /// + /// \returns NULL if this is not an instantiation of a member function + /// template. + FunctionTemplateDecl *getInstantiatedFromMemberTemplate() { + return getCommonPtr()->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) { + assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); + getCommonPtr()->InstantiatedFromMember.setPointer(FTD); + } + + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the function template \c X<int>::f is a + /// member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// }; + /// + /// template<> template<typename T> + /// void X<int>::f(int, T); + /// \endcode + bool isMemberSpecialization() { + return getCommonPtr()->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + getCommonPtr()->InstantiatedFromMember.setInt(true); + } /// Create a template function node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, @@ -629,8 +766,7 @@ public: /// the occurrence within the parameter list. /// This class is inheritedly privately by different kinds of template /// parameters and is not part of the Decl hierarchy. Just a facility. -class TemplateParmPosition -{ +class TemplateParmPosition { protected: // FIXME: This should probably never be called, but it's here as TemplateParmPosition() @@ -652,7 +788,7 @@ public: /// Get the position of the template parameter within its parameter list. unsigned getPosition() const { return Position; } - + /// Get the index of the template parameter within its parameter list. unsigned getIndex() const { return Position; } }; @@ -681,10 +817,10 @@ class TemplateTypeParmDecl : public TypeDecl { /// \brief The default template argument, if any. QualType DefaultArgument; - TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, bool Typename, QualType Type, bool ParameterPack) : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename), - InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() { + InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() { TypeForDecl = Type.getTypePtr(); } @@ -745,21 +881,20 @@ class NonTypeTemplateParmDecl NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - SourceLocation TSSL = SourceLocation()) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL), - TemplateParmPosition(D, P), DefaultArgument(0) + DeclaratorInfo *DInfo) + : VarDecl(NonTypeTemplateParm, DC, L, Id, T, DInfo, VarDecl::None), + TemplateParmPosition(D, P), DefaultArgument(0) { } public: static NonTypeTemplateParmDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, - SourceLocation TypeSpecStartLoc = SourceLocation()); + unsigned P, IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo); using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; using TemplateParmPosition::getIndex; - + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { return DefaultArgument; } @@ -811,7 +946,7 @@ public: using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; using TemplateParmPosition::getIndex; - + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { return DefaultArgument; } @@ -834,24 +969,6 @@ public: static bool classof(const TemplateTemplateParmDecl *D) { return true; } }; -// \brief Describes the kind of template specialization that a -// particular template specialization declaration represents. -enum TemplateSpecializationKind { - /// This template specialization was formed from a template-id but - /// has not yet been declared, defined, or instantiated. - TSK_Undeclared = 0, - /// This template specialization was declared or defined by an - /// explicit specialization (C++ [temp.expl.spec]) or partial - /// specialization (C++ [temp.class.spec]). - TSK_ExplicitSpecialization, - /// This template specialization was implicitly instantiated from a - /// template. (C++ [temp.inst]). - TSK_ImplicitInstantiation, - /// This template specialization was instantiated from a template - /// due to an explicit instantiation request (C++ [temp.explicit]). - TSK_ExplicitInstantiation -}; - /// \brief Represents a class template specialization, which refers to /// a class template with a given set of template arguments. /// @@ -861,28 +978,47 @@ enum TemplateSpecializationKind { /// /// \code /// template<typename T> class array; -/// -/// template<> +/// +/// template<> /// class array<bool> { }; // class template specialization array<bool> /// \endcode -class ClassTemplateSpecializationDecl +class ClassTemplateSpecializationDecl : public CXXRecordDecl, public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a class template + /// specialization that was instantiated from a class template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The class template partial specialization from which this + /// class template specialization was instantiated. + ClassTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the class template + /// partial specialization itself. + TemplateArgumentList *TemplateArgs; + }; + /// \brief The template that this specialization specializes - ClassTemplateDecl *SpecializedTemplate; + llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *> + SpecializedTemplate; /// \brief The template arguments used to describe this specialization. TemplateArgumentList TemplateArgs; + /// \brief The point where this template was instantiated (if any) + SourceLocation PointOfInstantiation; + /// \brief The kind of specialization this declaration refers to. /// Really a value of type TemplateSpecializationKind. - unsigned SpecializationKind : 2; + unsigned SpecializationKind : 3; protected: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder); - + TemplateArgumentListBuilder &Builder, + ClassTemplateSpecializationDecl *PrevDecl); + public: static ClassTemplateSpecializationDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation L, @@ -890,12 +1026,18 @@ public: TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl); + virtual void Destroy(ASTContext& C); + + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const; + /// \brief Retrieve the template that this specialization specializes. - ClassTemplateDecl *getSpecializedTemplate() const { - return SpecializedTemplate; - } + ClassTemplateDecl *getSpecializedTemplate() const; - const TemplateArgumentList &getTemplateArgs() const { + /// \brief Retrieve the template arguments of the class template + /// specialization. + const TemplateArgumentList &getTemplateArgs() const { return TemplateArgs; } @@ -909,6 +1051,67 @@ public: SpecializationKind = TSK; } + /// \brief Get the point of instantiation (if any), or null if none. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + void setPointOfInstantiation(SourceLocation Loc) { + assert(Loc.isValid() && "point of instantiation must be valid!"); + PointOfInstantiation = Loc; + } + + /// \brief If this class template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// class template or class template partial specialization from which it + /// was instantiated. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return (ClassTemplateDecl*)0; + + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization; + + return const_cast<ClassTemplateDecl*>( + SpecializedTemplate.get<ClassTemplateDecl*>()); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate members of the class template or class template partial + /// specialization from which this class template specialization was + /// instantiated. + /// + /// \returns For a class template specialization instantiated from the primary + /// template, this function will return the same template arguments as + /// getTemplateArgs(). For a class template specialization instantiated from + /// a class template partial specialization, this function will return the + /// deduced template arguments for the class template partial specialization + /// itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this class template specialization is actually an + /// instantiation of the given class template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, + TemplateArgumentList *TemplateArgs) { + SpecializedPartialSpecialization *PS + = new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + /// \brief Sets the type of this specialization as it was written by /// the user. This will be a class template specialization type. void setTypeAsWritten(QualType T) { @@ -916,18 +1119,19 @@ public: } void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size()); + Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), + getASTContext()); } - static void - Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { + static void + Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, ASTContext &Context) { ID.AddInteger(NumTemplateArgs); for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) - TemplateArgs[Arg].Profile(ID); + TemplateArgs[Arg].Profile(ID, Context); } - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() == ClassTemplateSpecialization || D->getKind() == ClassTemplatePartialSpecialization; } @@ -941,19 +1145,21 @@ public: } }; -class ClassTemplatePartialSpecializationDecl - : public ClassTemplateSpecializationDecl -{ - /// \brief The list of template parameters +class ClassTemplatePartialSpecializationDecl + : public ClassTemplateSpecializationDecl { + /// \brief The list of template parameters TemplateParameterList* TemplateParams; ClassTemplatePartialSpecializationDecl(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder) - : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, - DC, L, SpecializedTemplate, Builder), + TemplateArgumentListBuilder &Builder, + ClassTemplatePartialSpecializationDecl *PrevDecl) + : ClassTemplateSpecializationDecl(Context, + ClassTemplatePartialSpecialization, + DC, L, SpecializedTemplate, Builder, + PrevDecl), TemplateParams(Params) { } public: @@ -971,7 +1177,7 @@ public: // FIXME: Add Profile support! - static bool classof(const Decl *D) { + static bool classof(const Decl *D) { return D->getKind() == ClassTemplatePartialSpecialization; } @@ -986,29 +1192,41 @@ protected: /// \brief Data that is common to all of the declarations of a given /// class template. struct Common { + Common() : InstantiatedFromMember(0, 0) {} + /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; /// \brief The class template partial specializations for this class /// template. - llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> PartialSpecializations; /// \brief The injected-class-name type for this class template. QualType InjectedClassNameType; + + /// \brief The templated member class from which this was most + /// directly instantiated (or null). + /// + /// The boolean value indicates whether this member class template + /// was explicitly specialized. + llvm::PointerIntPair<ClassTemplateDecl *, 1, bool> InstantiatedFromMember; }; + // FIXME: Combine PreviousDeclaration with CommonPtr, as in + // FunctionTemplateDecl. + /// \brief Previous declaration of this class template. ClassTemplateDecl *PreviousDeclaration; /// \brief Pointer to the data that is common to all of the /// declarations of this class template. - /// + /// /// The first declaration of a class template (e.g., the declaration /// with no "previous declaration") owns this pointer. Common *CommonPtr; - + ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl, ClassTemplateDecl *PrevDecl, Common *CommonPtr) @@ -1028,6 +1246,8 @@ public: return PreviousDeclaration; } + virtual ClassTemplateDecl *getCanonicalDecl(); + /// Create a class template node. static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -1048,6 +1268,16 @@ public: return CommonPtr->PartialSpecializations; } + /// \brief Find a class template partial specialization with the given + /// type T. + /// + /// \brief A dependent type that names a specialization of this class + /// template. + /// + /// \returns the class template partial specialization that exactly matches + /// the type \p T, or NULL if no such partial specialization exists. + ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T); + /// \brief Retrieve the type of the injected-class-name for this /// class template. /// @@ -1064,6 +1294,61 @@ public: /// \endcode QualType getInjectedClassNameType(ASTContext &Context); + /// \brief Retrieve the member class template that this class template was + /// derived from. + /// + /// This routine will return non-NULL for templated member classes of + /// class templates. For example, given: + /// + /// \code + /// template <typename T> + /// struct X { + /// template <typename U> struct A {}; + /// }; + /// \endcode + /// + /// X<int>::A<float> is a ClassTemplateSpecializationDecl (whose parent + /// is X<int>, also a CTSD) for which getSpecializedTemplate() will + /// return X<int>::A<U>, a TemplateClassDecl (whose parent is again + /// X<int>) for which getInstantiatedFromMemberTemplate() will return + /// X<T>::A<U>, a TemplateClassDecl (whose parent is X<T>, also a TCD). + /// + /// \returns null if this is not an instantiation of a member class template. + ClassTemplateDecl *getInstantiatedFromMemberTemplate() const { + return CommonPtr->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) { + assert(!CommonPtr->InstantiatedFromMember.getPointer()); + CommonPtr->InstantiatedFromMember.setPointer(CTD); + } + + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the member template \c X<int>::Inner is a + /// member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> struct Inner; + /// }; + /// + /// template<> template<typename T> + /// struct X<int>::Inner { /* ... */ }; + /// \endcode + bool isMemberSpecialization() { + return CommonPtr->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(CommonPtr->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + CommonPtr->InstantiatedFromMember.setInt(true); + } + // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return D->getKind() == ClassTemplate; } @@ -1073,8 +1358,87 @@ public: virtual void Destroy(ASTContext& C); }; +/// Declaration of a friend template. For example: +/// +/// template <typename T> class A { +/// friend class MyVector<T>; // not a friend template +/// template <typename U> friend class B; // friend template +/// template <typename U> friend class Foo<T>::Nested; // friend template +class FriendTemplateDecl : public Decl { +public: + typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion; + +private: + // The number of template parameters; always non-zero. + unsigned NumParams; + + // The parameter list. + TemplateParameterList **Params; + + // The declaration that's a friend of this class. + FriendUnion Friend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + + FriendTemplateDecl(DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc) + : Decl(Decl::FriendTemplate, DC, Loc), + NumParams(NParams), + Params(Params), + Friend(Friend), + FriendLoc(FriendLoc) + {} + +public: + static FriendTemplateDecl *Create(ASTContext &Context, + DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc); + + /// If this friend declaration names a templated type (or + /// a dependent member type of a templated type), return that + /// type; otherwise return null. + Type *getFriendType() const { + return Friend.dyn_cast<Type*>(); + } + + /// If this friend declaration names a templated function (or + /// a member function of a templated type), return that type; + /// otherwise return null. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i <= NumParams); + return Params[i]; + } + + unsigned getNumTemplateParameters() const { + return NumParams; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == Decl::FriendTemplate; + } + static bool classof(const FriendTemplateDecl *D) { return true; } +}; + /// Implementation of inline functions that require the template declarations -inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) +inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) : Function(FTD) { } } /* end of namespace clang */ diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index db140999b045..ed4ac6b5d4e7 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -15,6 +15,8 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" +#include "clang/Basic/PartialDiagnostic.h" namespace llvm { template <typename T> struct DenseMapInfo; @@ -100,7 +102,7 @@ private: /// CXXSpecialName, returns a pointer to it. Otherwise, returns /// a NULL pointer. CXXSpecialName *getAsCXXSpecialName() const { - if (getNameKind() >= CXXConstructorName && + if (getNameKind() >= CXXConstructorName && getNameKind() <= CXXConversionFunctionName) return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask); return 0; @@ -115,16 +117,16 @@ private: // Construct a declaration name from the name of a C++ constructor, // destructor, or conversion function. - DeclarationName(CXXSpecialName *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { + DeclarationName(CXXSpecialName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName"); Ptr |= StoredDeclarationNameExtra; } // Construct a declaration name from the name of a C++ overloaded // operator. - DeclarationName(CXXOperatorIdName *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { + DeclarationName(CXXOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId"); Ptr |= StoredDeclarationNameExtra; } @@ -144,8 +146,8 @@ public: DeclarationName() : Ptr(0) { } // Construct a declaration name from an IdentifierInfo *. - DeclarationName(const IdentifierInfo *II) - : Ptr(reinterpret_cast<uintptr_t>(II)) { + DeclarationName(const IdentifierInfo *II) + : Ptr(reinterpret_cast<uintptr_t>(II)) { assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); } @@ -157,8 +159,8 @@ public: // operator bool() - Evaluates true when this declaration name is // non-empty. - operator bool() const { - return ((Ptr & PtrMask) != 0) || + operator bool() const { + return ((Ptr & PtrMask) != 0) || (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); } @@ -170,10 +172,10 @@ public: bool isObjCOneArgSelector() const { return getStoredNameKind() == StoredObjCOneArgSelector; } - + /// getNameKind - Determine what kind of name this is. NameKind getNameKind() const; - + /// getName - Retrieve the human-readable string for this name. std::string getAsString() const; @@ -181,7 +183,7 @@ public: /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in /// this declaration name, or NULL if this declaration name isn't a /// simple identifier. - IdentifierInfo *getAsIdentifierInfo() const { + IdentifierInfo *getAsIdentifierInfo() const { if (isIdentifier()) return reinterpret_cast<IdentifierInfo *>(Ptr); return 0; @@ -195,12 +197,18 @@ public: /// an opaque pointer. void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); } + static DeclarationName getFromOpaquePtr(void *P) { + DeclarationName N; + N.Ptr = reinterpret_cast<uintptr_t> (P); + return N; + } + static DeclarationName getFromOpaqueInteger(uintptr_t P) { DeclarationName N; N.Ptr = P; return N; } - + /// getCXXNameType - If this name is one of the C++ names (of a /// constructor, destructor, or conversion function), return the /// type associated with that name. @@ -290,32 +298,32 @@ public: /// getCXXConstructorName - Returns the name of a C++ constructor /// for the given Type. - DeclarationName getCXXConstructorName(QualType Ty) { + DeclarationName getCXXConstructorName(CanQualType Ty) { return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty); } /// getCXXDestructorName - Returns the name of a C++ destructor /// for the given Type. - DeclarationName getCXXDestructorName(QualType Ty) { + DeclarationName getCXXDestructorName(CanQualType Ty) { return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty); } /// getCXXConversionFunctionName - Returns the name of a C++ /// conversion function for the given Type. - DeclarationName getCXXConversionFunctionName(QualType Ty) { + DeclarationName getCXXConversionFunctionName(CanQualType Ty) { return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty); } /// getCXXSpecialName - Returns a declaration name for special kind /// of C++ name, e.g., for a constructor, destructor, or conversion /// function. - DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, - QualType Ty); + DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty); /// getCXXOperatorName - Get the name of the overloadable C++ /// operator corresponding to Op. DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); -}; +}; /// Insertion operator for diagnostics. This allows sending DeclarationName's /// into a diagnostic with <<. @@ -325,7 +333,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Diagnostic::ak_declarationname); return DB; } - + +/// Insertion operator for partial diagnostics. This allows binding +/// DeclarationName's into a partial diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + DeclarationName N) { + PD.AddTaggedVal(N.getAsOpaqueInteger(), + Diagnostic::ak_declarationname); + return PD; +} } // end namespace clang @@ -344,7 +360,7 @@ struct DenseMapInfo<clang::DeclarationName> { static unsigned getHashValue(clang::DeclarationName); - static inline bool + static inline bool isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) { return LHS == RHS; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 6a1046e6d03f..d5dff5065d49 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -20,6 +20,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include <vector> namespace clang { @@ -42,20 +43,20 @@ class Expr : public Stmt { QualType TR; protected: - /// TypeDependent - Whether this expression is type-dependent + /// TypeDependent - Whether this expression is type-dependent /// (C++ [temp.dep.expr]). bool TypeDependent : 1; - /// ValueDependent - Whether this expression is value-dependent + /// ValueDependent - Whether this expression is value-dependent /// (C++ [temp.dep.constexpr]). bool ValueDependent : 1; // FIXME: Eventually, this constructor should go away and we should // require every subclass to provide type/value-dependence // information. - Expr(StmtClass SC, QualType T) + Expr(StmtClass SC, QualType T) : Stmt(SC), TypeDependent(false), ValueDependent(false) { - setType(T); + setType(T); } Expr(StmtClass SC, QualType T, bool TD, bool VD) @@ -66,9 +67,18 @@ protected: /// \brief Construct an empty expression. explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } -public: +public: + /// \brief Increases the reference count for this expression. + /// + /// Invoke the Retain() operation when this expression + /// is being shared by another owner. + Expr *Retain() { + Stmt::Retain(); + return this; + } + QualType getType() const { return TR; } - void setType(QualType t) { + void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it // will not have reference type an expression will never have // reference type (C++ [expr]p6). Use @@ -76,16 +86,16 @@ public: // type. Additionally, inspect Expr::isLvalue to determine whether // an expression that is adjusted in this manner should be // considered an lvalue. - assert((TR.isNull() || !TR->isReferenceType()) && + assert((TR.isNull() || !TR->isReferenceType()) && "Expressions can't have reference type"); - TR = t; + TR = t; } /// isValueDependent - Determines whether this expression is /// value-dependent (C++ [temp.dep.constexpr]). For example, the /// array bound of "Chars" in the following example is - /// value-dependent. + /// value-dependent. /// @code /// template<int Size, char (&Chars)[Size]> struct meta_string; /// @endcode @@ -100,7 +110,7 @@ public: /// example, the expressions "x" and "x + y" are type-dependent in /// the following code, but "y" is not type-dependent: /// @code - /// template<typename T> + /// template<typename T> /// void add(T x, int y) { /// x + y; /// } @@ -118,14 +128,14 @@ public: /// getExprLoc - Return the preferred location for the arrow when diagnosing /// a problem with a generic expression. virtual SourceLocation getExprLoc() const { return getLocStart(); } - + /// isUnusedResultAWarning - Return true if this immediate expression should /// be warned about if the result is unused. If so, fill in Loc and Ranges /// with location to warn on and the source range[s] to report with the /// warning. bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, SourceRange &R2) const; - + /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or /// incomplete type other than void. Nonarray expressions that can be lvalues: /// - name, where name must be a variable @@ -150,10 +160,10 @@ public: // Same as above, but excluding checks for non-object and void types in C isLvalueResult isLvalueInternal(ASTContext &Ctx) const; - + /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, - /// and if it is a structure or union, does not have any member (including, + /// and if it is a structure or union, does not have any member (including, /// recursively, any member or element of all contained aggregates or unions) /// with a const-qualified type. /// @@ -177,7 +187,7 @@ public: }; isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = 0) const; - + /// \brief If this expression refers to a bit-field, retrieve the /// declaration of that bit-field. FieldDecl *getBitField(); @@ -185,7 +195,7 @@ public: const FieldDecl *getBitField() const { return const_cast<Expr*>(this)->getBitField(); } - + /// isIntegerConstantExpr - Return true if this expression is a valid integer /// constant expression, and, if so, return its value in Result. If not a /// valid i-c-e, return false and fill in Loc (if specified) with the location @@ -200,16 +210,16 @@ public: /// isConstantInitializer - Returns true if this expression is a constant /// initializer, which can be emitted at compile-time. bool isConstantInitializer(ASTContext &Ctx) const; - + /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult { /// Val - This is the value the expression can be folded to. APValue Val; - + /// HasSideEffects - Whether the evaluated expression has side effects. /// For example, (f() && 0) can be folded, but it still has side effects. bool HasSideEffects; - + /// Diag - If the expression is unfoldable, then Diag contains a note /// diagnostic indicating why it's not foldable. DiagLoc indicates a caret /// position for the error, and DiagExpr is the expression that caused @@ -221,7 +231,7 @@ public: unsigned Diag; const Expr *DiagExpr; SourceLocation DiagLoc; - + EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {} }; @@ -239,25 +249,41 @@ public: /// must be called on an expression that constant folds to an integer. llvm::APSInt EvaluateAsInt(ASTContext &Ctx) const; - /// EvaluateAsLValue - Evaluate an expression to see if it's a valid LValue. + /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue + /// with link time known address. bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const; + /// EvaluateAsAnyLValue - The same as EvaluateAsLValue, except that it + /// also succeeds on stack based, immutable address lvalues. + bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const; + + /// \brief Enumeration used to describe how \c isNullPointerConstant() + /// should cope with value-dependent expressions. + enum NullPointerConstantValueDependence { + /// \brief Specifies that the expression should never be value-dependent. + NPC_NeverValueDependent = 0, + + /// \brief Specifies that a value-dependent expression of integral or + /// dependent type should be considered a null pointer constant. + NPC_ValueDependentIsNull, + + /// \brief Specifies that a value-dependent expression should be considered + /// to never be a null pointer constant. + NPC_ValueDependentIsNotNull + }; + /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. - bool isNullPointerConstant(ASTContext &Ctx) const; - - /// hasGlobalStorage - Return true if this expression has static storage - /// duration. This means that the address of this expression is a link-time - /// constant. - bool hasGlobalStorage() const; + bool isNullPointerConstant(ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const; /// isOBJCGCCandidate - Return true if this expression may be used in a read/ - /// write barrier. + /// write barrier. bool isOBJCGCCandidate(ASTContext &Ctx) const; - + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return - /// its subexpression. If that subexpression is also a ParenExpr, + /// its subexpression. If that subexpression is also a ParenExpr, /// then this method recursively returns its subexpression, and so forth. /// Otherwise, the method returns the current Expr. Expr* IgnoreParens(); @@ -265,12 +291,12 @@ public: /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr /// or CastExprs, returning their operand. Expr *IgnoreParenCasts(); - + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the /// value (including ptr->int casts of the same size). Strip off any /// ParenExpr or CastExprs, returning their operand. Expr *IgnoreParenNoopCasts(ASTContext &Ctx); - + const Expr* IgnoreParens() const { return const_cast<Expr*>(this)->IgnoreParens(); } @@ -280,18 +306,18 @@ public: const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const { return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx); } - + static bool hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs); static bool hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs); - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExprConstant && - T->getStmtClass() <= lastExprConstant; + T->getStmtClass() <= lastExprConstant; } static bool classof(const Expr *) { return true; } }; - + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -299,7 +325,7 @@ public: /// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function, /// enum, etc. class DeclRefExpr : public Expr { - NamedDecl *D; + NamedDecl *D; SourceLocation Loc; protected: @@ -315,14 +341,14 @@ protected: public: // FIXME: Eventually, this constructor will go away and all clients // will have to provide the type- and value-dependent flags. - DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : + DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : Expr(DeclRefExprClass, t), D(d), Loc(l) {} - DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : + DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {} - + /// \brief Construct an empty declaration reference expression. - explicit DeclRefExpr(EmptyShell Empty) + explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) { } NamedDecl *getDecl() { return D; } @@ -332,14 +358,14 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == DeclRefExprClass || T->getStmtClass() == CXXConditionDeclExprClass || - T->getStmtClass() == QualifiedDeclRefExprClass; + T->getStmtClass() == QualifiedDeclRefExprClass; } static bool classof(const DeclRefExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -353,38 +379,35 @@ public: Function, PrettyFunction }; - + private: SourceLocation Loc; IdentType Type; public: - PredefinedExpr(SourceLocation l, QualType type, IdentType IT) - : Expr(PredefinedExprClass, type), Loc(l), Type(IT) {} - + PredefinedExpr(SourceLocation l, QualType type, IdentType IT) + : Expr(PredefinedExprClass, type, type->isDependentType(), + type->isDependentType()), Loc(l), Type(IT) {} + /// \brief Construct an empty predefined expression. - explicit PredefinedExpr(EmptyShell Empty) + explicit PredefinedExpr(EmptyShell Empty) : Expr(PredefinedExprClass, Empty) { } - PredefinedExpr* Clone(ASTContext &C) const; - IdentType getIdentType() const { return Type; } void setIdentType(IdentType IT) { Type = IT; } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - // FIXME: The logic for computing the value of a predefined expr should go - // into a method here that takes the inner-most code decl (a block, function - // or objc method) that the expr lives in. This would allow sema and codegen - // to be consistent for things like sizeof(__func__) etc. - + static std::string ComputeName(ASTContext &Context, IdentType IT, + const Decl *CurrentDecl); + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == PredefinedExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; } static bool classof(const PredefinedExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -394,7 +417,7 @@ class IntegerLiteral : public Expr { llvm::APInt Value; SourceLocation Loc; public: - // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, + // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, // or UnsignedLongLongTy IntegerLiteral(const llvm::APInt &V, QualType type, SourceLocation l) : Expr(IntegerLiteralClass, type), Value(V), Loc(l) { @@ -402,11 +425,9 @@ public: } /// \brief Construct an empty integer literal. - explicit IntegerLiteral(EmptyShell Empty) + explicit IntegerLiteral(EmptyShell Empty) : Expr(IntegerLiteralClass, Empty) { } - IntegerLiteral* Clone(ASTContext &C) const; - const llvm::APInt &getValue() const { return Value; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } @@ -416,11 +437,11 @@ public: void setValue(const llvm::APInt &Val) { Value = Val; } void setLocation(SourceLocation Location) { Loc = Location; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == IntegerLiteralClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == IntegerLiteralClass; } static bool classof(const IntegerLiteral *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -439,21 +460,19 @@ public: /// \brief Construct an empty character literal. CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } - CharacterLiteral* Clone(ASTContext &C) const; - - SourceLocation getLoc() const { return Loc; } + SourceLocation getLocation() const { return Loc; } bool isWide() const { return IsWide; } - + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - + unsigned getValue() const { return Value; } void setLocation(SourceLocation Location) { Loc = Location; } void setWide(bool W) { IsWide = W; } void setValue(unsigned Val) { Value = Val; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CharacterLiteralClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == CharacterLiteralClass; } static bool classof(const CharacterLiteral *) { return true; } @@ -467,16 +486,14 @@ class FloatingLiteral : public Expr { bool IsExact : 1; SourceLocation Loc; public: - FloatingLiteral(const llvm::APFloat &V, bool isexact, + FloatingLiteral(const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) - : Expr(FloatingLiteralClass, Type), Value(V), IsExact(isexact), Loc(L) {} + : Expr(FloatingLiteralClass, Type), Value(V), IsExact(isexact), Loc(L) {} /// \brief Construct an empty floating-point literal. - explicit FloatingLiteral(EmptyShell Empty) + explicit FloatingLiteral(EmptyShell Empty) : Expr(FloatingLiteralClass, Empty), Value(0.0) { } - FloatingLiteral* Clone(ASTContext &C) const; - const llvm::APFloat &getValue() const { return Value; } void setValue(const llvm::APFloat &Val) { Value = Val; } @@ -487,7 +504,7 @@ public: /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. double getValueAsApproximateDouble() const; - + SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -495,14 +512,14 @@ public: // into a method here that takes the inner-most code decl (a block, function // or objc method) that the expr lives in. This would allow sema and codegen // to be consistent for things like sizeof(__func__) etc. - + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == FloatingLiteralClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == FloatingLiteralClass; } static bool classof(const FloatingLiteral *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -518,23 +535,21 @@ class ImaginaryLiteral : public Expr { public: ImaginaryLiteral(Expr *val, QualType Ty) : Expr(ImaginaryLiteralClass, Ty), Val(val) {} - + /// \brief Build an empty imaginary literal. - explicit ImaginaryLiteral(EmptyShell Empty) + explicit ImaginaryLiteral(EmptyShell Empty) : Expr(ImaginaryLiteralClass, Empty) { } const Expr *getSubExpr() const { return cast<Expr>(Val); } Expr *getSubExpr() { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } - ImaginaryLiteral* Clone(ASTContext &C) const; - virtual SourceRange getSourceRange() const { return Val->getSourceRange(); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ImaginaryLiteralClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImaginaryLiteralClass; } static bool classof(const ImaginaryLiteral *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -564,6 +579,10 @@ class StringLiteral : public Expr { SourceLocation TokLocs[1]; StringLiteral(QualType Ty) : Expr(StringLiteralClass, Ty) {} + +protected: + virtual void DoDestroy(ASTContext &C); + public: /// This is the "fully general" constructor that allows representation of /// strings formed from multiple concatenated tokens. @@ -572,7 +591,7 @@ public: const SourceLocation *Loc, unsigned NumStrs); /// Simple constructor for string literals made from one token. - static StringLiteral *Create(ASTContext &C, const char *StrData, + static StringLiteral *Create(ASTContext &C, const char *StrData, unsigned ByteLength, bool Wide, QualType Ty, SourceLocation Loc) { return Create(C, StrData, ByteLength, Wide, Ty, &Loc, 1); @@ -581,33 +600,35 @@ public: /// \brief Construct an empty string literal. static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs); - StringLiteral* Clone(ASTContext &C) const; - void Destroy(ASTContext &C); - + llvm::StringRef getString() const { + return llvm::StringRef(StrData, ByteLength); + } + // FIXME: These are deprecated, replace with StringRef. const char *getStrData() const { return StrData; } unsigned getByteLength() const { return ByteLength; } /// \brief Sets the string data to the given string data. - void setStrData(ASTContext &C, const char *Str, unsigned Len); + void setString(ASTContext &C, llvm::StringRef Str); bool isWide() const { return IsWide; } void setWide(bool W) { IsWide = W; } bool containsNonAsciiOrNull() const { - for (unsigned i = 0; i < getByteLength(); ++i) - if (!isascii(getStrData()[i]) || !getStrData()[i]) + llvm::StringRef Str = getString(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) + if (!isascii(Str[i]) || !Str[i]) return true; return false; } /// getNumConcatenated - Get the number of string literal tokens that were /// concatenated in translation phase #6 to form this string literal. unsigned getNumConcatenated() const { return NumConcatenated; } - + SourceLocation getStrTokenLoc(unsigned TokNum) const { assert(TokNum < NumConcatenated && "Invalid tok number"); return TokLocs[TokNum]; } - void setStrTokenLoc(unsigned TokNum, SourceLocation L) { + void setStrTokenLoc(unsigned TokNum, SourceLocation L) { assert(TokNum < NumConcatenated && "Invalid tok number"); TokLocs[TokNum] = L; } @@ -616,14 +637,14 @@ public: tokloc_iterator tokloc_begin() const { return TokLocs; } tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; } - virtual SourceRange getSourceRange() const { - return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]); + virtual SourceRange getSourceRange() const { + return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == StringLiteralClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == StringLiteralClass; } static bool classof(const StringLiteral *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -637,11 +658,11 @@ class ParenExpr : public Expr { public: ParenExpr(SourceLocation l, SourceLocation r, Expr *val) : Expr(ParenExprClass, val->getType(), - val->isTypeDependent(), val->isValueDependent()), + val->isTypeDependent(), val->isValueDependent()), L(l), R(r), Val(val) {} - + /// \brief Construct an empty parenthesized expression. - explicit ParenExpr(EmptyShell Empty) + explicit ParenExpr(EmptyShell Empty) : Expr(ParenExprClass, Empty) { } const Expr *getSubExpr() const { return cast<Expr>(Val); } @@ -658,11 +679,11 @@ public: SourceLocation getRParen() const { return R; } void setRParen(SourceLocation Loc) { R = Loc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ParenExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenExprClass; } static bool classof(const ParenExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -680,7 +701,7 @@ public: /// later returns zero in the type of the operand. /// /// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose -/// subexpression is a compound literal with the various MemberExpr and +/// subexpression is a compound literal with the various MemberExpr and /// ArraySubscriptExpr's applied to it. /// class UnaryOperator : public Expr { @@ -700,16 +721,16 @@ private: Stmt *Val; Opcode Opc; SourceLocation Loc; -public: +public: UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l) : Expr(UnaryOperatorClass, type, input->isTypeDependent() && opc != OffsetOf, - input->isValueDependent()), + input->isValueDependent()), Val(input), Opc(opc), Loc(l) {} /// \brief Build an empty unary operator. - explicit UnaryOperator(EmptyShell Empty) + explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty), Opc(AddrOf) { } Opcode getOpcode() const { return Opc; } @@ -738,7 +759,8 @@ public: bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; } bool isOffsetOfOp() const { return Opc == OffsetOf; } static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; } - + bool isArithmeticOp() const { return isArithmeticOp(Opc); } + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++" static const char *getOpcodeStr(Opcode Op); @@ -758,12 +780,12 @@ public: return SourceRange(Loc, Val->getLocEnd()); } virtual SourceLocation getExprLoc() const { return Loc; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == UnaryOperatorClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryOperatorClass; } static bool classof(const UnaryOperator *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -779,8 +801,12 @@ class SizeOfAlignOfExpr : public Expr { Stmt *Ex; } Argument; SourceLocation OpLoc, RParenLoc; + +protected: + virtual void DoDestroy(ASTContext& C); + public: - SizeOfAlignOfExpr(bool issizeof, QualType T, + SizeOfAlignOfExpr(bool issizeof, QualType T, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(SizeOfAlignOfExprClass, resultType, @@ -791,7 +817,7 @@ public: Argument.Ty = T.getAsOpaquePtr(); } - SizeOfAlignOfExpr(bool issizeof, Expr *E, + SizeOfAlignOfExpr(bool issizeof, Expr *E, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(SizeOfAlignOfExprClass, resultType, @@ -806,8 +832,6 @@ public: explicit SizeOfAlignOfExpr(EmptyShell Empty) : Expr(SizeOfAlignOfExprClass, Empty) { } - virtual void Destroy(ASTContext& C); - bool isSizeOf() const { return isSizeof; } void setSizeof(bool S) { isSizeof = S; } @@ -825,9 +849,9 @@ public: } void setArgument(Expr *E) { Argument.Ex = E; isType = false; } - void setArgument(QualType T) { - Argument.Ty = T.getAsOpaquePtr(); - isType = true; + void setArgument(QualType T) { + Argument.Ty = T.getAsOpaquePtr(); + isType = true; } /// Gets the argument type, or the type of the argument expression, whichever @@ -846,11 +870,11 @@ public: return SourceRange(OpLoc, RParenLoc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == SizeOfAlignOfExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == SizeOfAlignOfExprClass; } static bool classof(const SizeOfAlignOfExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -863,7 +887,7 @@ public: /// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. class ArraySubscriptExpr : public Expr { enum { LHS, RHS, END_EXPR=2 }; - Stmt* SubExprs[END_EXPR]; + Stmt* SubExprs[END_EXPR]; SourceLocation RBracketLoc; public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, @@ -875,7 +899,7 @@ public: SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } - + /// \brief Create an empty array subscript expression. explicit ArraySubscriptExpr(EmptyShell Shell) : Expr(ArraySubscriptExprClass, Shell) { } @@ -896,37 +920,37 @@ public: Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); } const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } - - Expr *getBase() { + + Expr *getBase() { return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); } - - const Expr *getBase() const { + + const Expr *getBase() const { return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); } - - Expr *getIdx() { + + Expr *getIdx() { return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); } - + const Expr *getIdx() const { return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); - } - - virtual SourceRange getSourceRange() const { + } + + virtual SourceRange getSourceRange() const { return SourceRange(getLHS()->getLocStart(), RBracketLoc); } - + SourceLocation getRBracketLoc() const { return RBracketLoc; } void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } virtual SourceLocation getExprLoc() const { return getBase()->getExprLoc(); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ArraySubscriptExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArraySubscriptExprClass; } static bool classof(const ArraySubscriptExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -934,9 +958,9 @@ public: /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). -/// CallExpr itself represents a normal function call, e.g., "f(x, 2)", +/// CallExpr itself represents a normal function call, e.g., "f(x, 2)", /// while its subclasses may represent alternative syntax that (semantically) -/// results in a function call. For example, CXXOperatorCallExpr is +/// results in a function call. For example, CXXOperatorCallExpr is /// a subclass for overloaded operator calls that use operator syntax, e.g., /// "str1 + str2" to resolve to a function call. class CallExpr : public Expr { @@ -944,31 +968,37 @@ class CallExpr : public Expr { Stmt **SubExprs; unsigned NumArgs; SourceLocation RParenLoc; - + protected: // This version of the constructor is for derived classes. CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, unsigned numargs, QualType t, SourceLocation rparenloc); - + + virtual void DoDestroy(ASTContext& C); + public: - CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t, + CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t, SourceLocation rparenloc); - + /// \brief Build an empty call expression. - CallExpr(ASTContext &C, EmptyShell Empty); + CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty); ~CallExpr() {} - - void Destroy(ASTContext& C); - + const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } void setCallee(Expr *F) { SubExprs[FN] = F; } - + + /// \brief If the callee is a FunctionDecl, return it. Otherwise return 0. + FunctionDecl *getDirectCallee(); + const FunctionDecl *getDirectCallee() const { + return const_cast<CallExpr*>(this)->getDirectCallee(); + } + /// getNumArgs - Return the number of actual arguments to this call. /// unsigned getNumArgs() const { return NumArgs; } - + /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < NumArgs && "Arg access out of range!"); @@ -978,26 +1008,26 @@ public: assert(Arg < NumArgs && "Arg access out of range!"); return cast<Expr>(SubExprs[Arg+ARGS_START]); } - + /// setArg - Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { assert(Arg < NumArgs && "Arg access out of range!"); SubExprs[Arg+ARGS_START] = ArgExpr; } - + /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. void setNumArgs(ASTContext& C, unsigned NumArgs); - + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; - + arg_iterator arg_begin() { return SubExprs+ARGS_START; } arg_iterator arg_end() { return SubExprs+ARGS_START+getNumArgs(); } const_arg_iterator arg_begin() const { return SubExprs+ARGS_START; } const_arg_iterator arg_end() const { return SubExprs+ARGS_START+getNumArgs();} - + /// getNumCommas - Return the number of commas that must have been present in /// this function call. unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; } @@ -1005,23 +1035,23 @@ public: /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If /// not, return 0. unsigned isBuiltinCall(ASTContext &Context) const; - - /// getCallReturnType - Get the return type of the call expr. This is not - /// always the type of the expr itself, if the return type is a reference + + /// getCallReturnType - Get the return type of the call expr. This is not + /// always the type of the expr itself, if the return type is a reference /// type. QualType getCallReturnType() const; - + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + virtual SourceRange getSourceRange() const { return SourceRange(getCallee()->getLocStart(), RParenLoc); } - - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == CallExprClass || T->getStmtClass() == CXXOperatorCallExprClass || - T->getStmtClass() == CXXMemberCallExprClass; + T->getStmtClass() == CXXMemberCallExprClass; } static bool classof(const CallExpr *) { return true; } static bool classof(const CXXOperatorCallExpr *) { return true; } @@ -1032,31 +1062,131 @@ public: virtual child_iterator child_end(); }; +/// \brief Represents the qualifier that may precede a C++ name, e.g., the +/// "std::" in "std::sort". +struct NameQualifier { + /// \brief The nested name specifier. + NestedNameSpecifier *NNS; + + /// \brief The source range covered by the nested name specifier. + SourceRange Range; +}; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +struct ExplicitTemplateArgumentList { + /// \brief The source location of the left angle bracket ('<'); + SourceLocation LAngleLoc; + + /// \brief The source location of the right angle bracket ('>'); + SourceLocation RAngleLoc; + + /// \brief The number of template arguments in TemplateArgs. + /// The actual template arguments (if any) are stored after the + /// ExplicitTemplateArgumentList structure. + unsigned NumTemplateArgs; + + /// \brief Retrieve the template arguments + TemplateArgument *getTemplateArgs() { + return reinterpret_cast<TemplateArgument *> (this + 1); + } + + /// \brief Retrieve the template arguments + const TemplateArgument *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgument *> (this + 1); + } +}; + /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr : public Expr { /// Base - the expression for the base pointer or structure references. In /// X.F, this is "X". Stmt *Base; - + /// MemberDecl - This is the decl being referenced by the field/member name. /// In X.F, this is the decl referenced by F. NamedDecl *MemberDecl; - + /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; - + /// IsArrow - True if this is "X->F", false if this is "X.F". - bool IsArrow; + bool IsArrow : 1; + + /// \brief True if this member expression used a nested-name-specifier to + /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier + /// structure is allocated immediately after the MemberExpr. + bool HasQualifier : 1; + + /// \brief True if this member expression specified a template argument list + /// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList + /// structure (and its TemplateArguments) are allocated immediately after + /// the MemberExpr or, if the member expression also has a qualifier, after + /// the NameQualifier structure. + bool HasExplicitTemplateArgumentList : 1; + + /// \brief Retrieve the qualifier that preceded the member name, if any. + NameQualifier *getMemberQualifier() { + if (!HasQualifier) + return 0; + + return reinterpret_cast<NameQualifier *> (this + 1); + } + + /// \brief Retrieve the qualifier that preceded the member name, if any. + const NameQualifier *getMemberQualifier() const { + return const_cast<MemberExpr *>(this)->getMemberQualifier(); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { + if (!HasExplicitTemplateArgumentList) + return 0; + + if (!HasQualifier) + return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); + + return reinterpret_cast<ExplicitTemplateArgumentList *>( + getMemberQualifier() + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList(); + } + + MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, + SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, + bool has_explicit, SourceLocation langle, + const TemplateArgument *targs, unsigned numtargs, + SourceLocation rangle, QualType ty); + public: MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, - QualType ty) - : Expr(MemberExprClass, ty, + QualType ty) + : Expr(MemberExprClass, ty, base->isTypeDependent(), base->isValueDependent()), - Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {} + Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), + HasQualifier(false), HasExplicitTemplateArgumentList(false) {} /// \brief Build an empty member reference expression. - explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { } + explicit MemberExpr(EmptyShell Empty) + : Expr(MemberExprClass, Empty), HasQualifier(false), + HasExplicitTemplateArgumentList(false) { } + + static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, + NestedNameSpecifier *qual, SourceRange qualrange, + NamedDecl *memberdecl, + SourceLocation l, + bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, + unsigned numtargs, + SourceLocation rangle, + QualType ty); void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast<Expr>(Base); } @@ -1068,6 +1198,73 @@ public: NamedDecl *getMemberDecl() const { return MemberDecl; } void setMemberDecl(NamedDecl *D) { MemberDecl = D; } + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return HasQualifier; } + + /// \brief If the member name was qualified, retrieves the source range of + /// the nested-name-specifier that precedes the member name. Otherwise, + /// returns an empty source range. + SourceRange getQualifierRange() const { + if (!HasQualifier) + return SourceRange(); + + return getMemberQualifier()->Range; + } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { + if (!HasQualifier) + return 0; + + return getMemberQualifier()->NNS; + } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgumentList() { + return HasExplicitTemplateArgumentList; + } + + /// \brief Retrieve the location of the left angle bracket following the + /// member name ('<'), if any. + SourceLocation getLAngleLoc() const { + if (!HasExplicitTemplateArgumentList) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgument *getTemplateArgs() const { + if (!HasExplicitTemplateArgumentList) + return 0; + + return getExplicitTemplateArgumentList()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!HasExplicitTemplateArgumentList) + return 0; + + return getExplicitTemplateArgumentList()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket following the + /// template arguments ('>'). + SourceLocation getRAngleLoc() const { + if (!HasExplicitTemplateArgumentList) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->RAngleLoc; + } + bool isArrow() const { return IsArrow; } void setArrow(bool A) { IsArrow = A; } @@ -1079,25 +1276,29 @@ public: virtual SourceRange getSourceRange() const { // If we have an implicit base (like a C++ implicit this), // make sure not to return its location + SourceLocation EndLoc = MemberLoc; + if (HasExplicitTemplateArgumentList) + EndLoc = getRAngleLoc(); + SourceLocation BaseLoc = getBase()->getLocStart(); if (BaseLoc.isInvalid()) - return SourceRange(MemberLoc, MemberLoc); - return SourceRange(BaseLoc, MemberLoc); + return SourceRange(MemberLoc, EndLoc); + return SourceRange(BaseLoc, EndLoc); } - + virtual SourceLocation getExprLoc() const { return MemberLoc; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == MemberExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == MemberExprClass; } static bool classof(const MemberExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; -/// CompoundLiteralExpr - [C99 6.5.2.5] +/// CompoundLiteralExpr - [C99 6.5.2.5] /// class CompoundLiteralExpr : public Expr { /// LParenLoc - If non-null, this is the location of the left paren in a @@ -1111,7 +1312,7 @@ public: bool fileScope) : Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init), FileScope(fileScope) {} - + /// \brief Construct an empty compound literal. explicit CompoundLiteralExpr(EmptyShell Empty) : Expr(CompoundLiteralExprClass, Empty) { } @@ -1135,11 +1336,11 @@ public: return SourceRange(LParenLoc, Init->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CompoundLiteralExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundLiteralExprClass; } static bool classof(const CompoundLiteralExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1150,28 +1351,85 @@ public: /// representation in the source code (ExplicitCastExpr's derived /// classes). class CastExpr : public Expr { +public: + /// CastKind - the kind of cast this represents. + enum CastKind { + /// CK_Unknown - Unknown cast kind. + /// FIXME: The goal is to get rid of this and make all casts have a + /// kind so that the AST client doesn't have to try to figure out what's + /// going on. + CK_Unknown, + + /// CK_BitCast - Used for reinterpret_cast. + CK_BitCast, + + /// CK_NoOp - Used for const_cast. + CK_NoOp, + + /// CK_DerivedToBase - Derived to base class casts. + CK_DerivedToBase, + + /// CK_Dynamic - Dynamic cast. + CK_Dynamic, + + /// CK_ToUnion - Cast to union (GCC extension). + CK_ToUnion, + + /// CK_ArrayToPointerDecay - Array to pointer decay. + CK_ArrayToPointerDecay, + + // CK_FunctionToPointerDecay - Function to pointer decay. + CK_FunctionToPointerDecay, + + /// CK_NullToMemberPointer - Null pointer to member pointer. + CK_NullToMemberPointer, + + /// CK_BaseToDerivedMemberPointer - Member pointer in base class to + /// member pointer in derived class. + CK_BaseToDerivedMemberPointer, + + /// CK_UserDefinedConversion - Conversion using a user defined type + /// conversion function. + CK_UserDefinedConversion, + + /// CK_ConstructorConversion - Conversion by constructor + CK_ConstructorConversion, + + /// CK_IntegralToPointer - Integral to pointer + CK_IntegralToPointer, + + /// CK_PointerToIntegral - Pointer to integral + CK_PointerToIntegral + }; + +private: + CastKind Kind; Stmt *Op; protected: - CastExpr(StmtClass SC, QualType ty, Expr *op) : + CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op) : Expr(SC, ty, // Cast expressions are type-dependent if the type is // dependent (C++ [temp.dep.expr]p3). ty->isDependentType(), // Cast expressions are value-dependent if the type is // dependent or if the subexpression is value-dependent. - ty->isDependentType() || (op && op->isValueDependent())), - Op(op) {} - + ty->isDependentType() || (op && op->isValueDependent())), + Kind(kind), Op(op) {} + /// \brief Construct an empty cast. - CastExpr(StmtClass SC, EmptyShell Empty) + CastExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { } - + public: + CastKind getCastKind() const { return Kind; } + void setCastKind(CastKind K) { Kind = K; } + const char *getCastKindName() const; + Expr *getSubExpr() { return cast<Expr>(Op); } const Expr *getSubExpr() const { return cast<Expr>(Op); } void setSubExpr(Expr *E) { Op = E; } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) return true; @@ -1182,7 +1440,7 @@ public: return false; } static bool classof(const CastExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1200,7 +1458,7 @@ public: /// @code /// class Base { }; /// class Derived : public Base { }; -/// void f(Derived d) { +/// void f(Derived d) { /// Base& b = d; // initializer is an ImplicitCastExpr to an lvalue of type Base /// } /// @endcode @@ -1209,11 +1467,11 @@ class ImplicitCastExpr : public CastExpr { bool LvalueCast; public: - ImplicitCastExpr(QualType ty, Expr *op, bool Lvalue) : - CastExpr(ImplicitCastExprClass, ty, op), LvalueCast(Lvalue) { } + ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, bool Lvalue) : + CastExpr(ImplicitCastExprClass, ty, kind, op), LvalueCast(Lvalue) { } /// \brief Construct an empty implicit cast. - explicit ImplicitCastExpr(EmptyShell Shell) + explicit ImplicitCastExpr(EmptyShell Shell) : CastExpr(ImplicitCastExprClass, Shell) { } @@ -1227,14 +1485,14 @@ public: /// setLvalueCast - Set whether this cast produces an lvalue. void setLvalueCast(bool Lvalue) { LvalueCast = Lvalue; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ImplicitCastExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitCastExprClass; } static bool classof(const ImplicitCastExpr *) { return true; } }; /// ExplicitCastExpr - An explicit cast written in the source -/// code. +/// code. /// /// This class is effectively an abstract class, because it provides /// the basic representation of an explicitly-written cast without @@ -1255,11 +1513,12 @@ class ExplicitCastExpr : public CastExpr { QualType TypeAsWritten; protected: - ExplicitCastExpr(StmtClass SC, QualType exprTy, Expr *op, QualType writtenTy) - : CastExpr(SC, exprTy, op), TypeAsWritten(writtenTy) {} + ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind, + Expr *op, QualType writtenTy) + : CastExpr(SC, exprTy, kind, op), TypeAsWritten(writtenTy) {} /// \brief Construct an empty explicit cast. - ExplicitCastExpr(StmtClass SC, EmptyShell Shell) + ExplicitCastExpr(StmtClass SC, EmptyShell Shell) : CastExpr(SC, Shell) { } public: @@ -1268,7 +1527,7 @@ public: QualType getTypeAsWritten() const { return TypeAsWritten; } void setTypeAsWritten(QualType T) { TypeAsWritten = T; } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass) return true; @@ -1287,13 +1546,13 @@ class CStyleCastExpr : public ExplicitCastExpr { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren public: - CStyleCastExpr(QualType exprTy, Expr *op, QualType writtenTy, - SourceLocation l, SourceLocation r) : - ExplicitCastExpr(CStyleCastExprClass, exprTy, op, writtenTy), + CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, QualType writtenTy, + SourceLocation l, SourceLocation r) : + ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy), LPLoc(l), RPLoc(r) {} /// \brief Construct an empty C-style explicit cast. - explicit CStyleCastExpr(EmptyShell Shell) + explicit CStyleCastExpr(EmptyShell Shell) : ExplicitCastExpr(CStyleCastExprClass, Shell) { } SourceLocation getLParenLoc() const { return LPLoc; } @@ -1305,8 +1564,8 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CStyleCastExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == CStyleCastExprClass; } static bool classof(const CStyleCastExpr *) { return true; } }; @@ -1358,22 +1617,22 @@ private: Stmt* SubExprs[END_EXPR]; Opcode Opc; SourceLocation OpLoc; -public: - +public: + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, SourceLocation opLoc) : Expr(BinaryOperatorClass, ResTy, lhs->isTypeDependent() || rhs->isTypeDependent(), - lhs->isValueDependent() || rhs->isValueDependent()), + lhs->isValueDependent() || rhs->isValueDependent()), Opc(opc), OpLoc(opLoc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - assert(!isCompoundAssignmentOp() && + assert(!isCompoundAssignmentOp() && "Use ArithAssignBinaryOperator for compound assignments"); } /// \brief Construct an empty binary operator. - explicit BinaryOperator(EmptyShell Empty) + explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty), Opc(Comma) { } SourceLocation getOperatorLoc() const { return OpLoc; } @@ -1390,7 +1649,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd()); } - + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". static const char *getOpcodeStr(Opcode Op); @@ -1412,19 +1671,19 @@ public: static bool isRelationalOp(Opcode Opc) { return Opc >= LT && Opc <= GE; } bool isRelationalOp() const { return isRelationalOp(Opc); } - static bool isEqualityOp(Opcode Opc) { return Opc == EQ || Opc == NE; } + static bool isEqualityOp(Opcode Opc) { return Opc == EQ || Opc == NE; } bool isEqualityOp() const { return isEqualityOp(Opc); } - + static bool isLogicalOp(Opcode Opc) { return Opc == LAnd || Opc == LOr; } bool isLogicalOp() const { return isLogicalOp(Opc); } bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; } bool isCompoundAssignmentOp() const { return Opc > Assign && Opc <= OrAssign;} bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; } - - static bool classof(const Stmt *S) { + + static bool classof(const Stmt *S) { return S->getStmtClass() == BinaryOperatorClass || - S->getStmtClass() == CompoundAssignOperatorClass; + S->getStmtClass() == CompoundAssignOperatorClass; } static bool classof(const BinaryOperator *) { return true; } @@ -1440,7 +1699,7 @@ protected: SubExprs[RHS] = rhs; } - BinaryOperator(StmtClass SC, EmptyShell Empty) + BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty), Opc(MulAssign) { } }; @@ -1461,7 +1720,7 @@ public: : BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { - assert(isCompoundAssignmentOp() && + assert(isCompoundAssignmentOp() && "Only should be used for compound assignments"); } @@ -1479,8 +1738,8 @@ public: void setComputationResultType(QualType T) { ComputationResultType = T; } static bool classof(const CompoundAssignOperator *) { return true; } - static bool classof(const Stmt *S) { - return S->getStmtClass() == CompoundAssignOperatorClass; + static bool classof(const Stmt *S) { + return S->getStmtClass() == CompoundAssignOperatorClass; } }; @@ -1490,16 +1749,20 @@ public: class ConditionalOperator : public Expr { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. + SourceLocation QuestionLoc, ColonLoc; public: - ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t) + ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, + SourceLocation CLoc, Expr *rhs, QualType t) : Expr(ConditionalOperatorClass, t, // FIXME: the type of the conditional operator doesn't // depend on the type of the conditional, but the standard // seems to imply that it could. File a bug! ((lhs && lhs->isTypeDependent()) || (rhs && rhs->isTypeDependent())), - (cond->isValueDependent() || + (cond->isValueDependent() || (lhs && lhs->isValueDependent()) || - (rhs && rhs->isValueDependent()))) { + (rhs && rhs->isValueDependent()))), + QuestionLoc(QLoc), + ColonLoc(CLoc) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; @@ -1519,29 +1782,35 @@ public: // will be the same as getLHS() except a GCC extension allows the left // subexpression to be omitted, and instead of the condition be returned. // e.g: x ?: y is shorthand for x ? x : y, except that the expression "x" - // is only evaluated once. + // is only evaluated once. Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS] ? SubExprs[LHS] : SubExprs[COND]); } - + // getTrueExpr - Return the subexpression representing the value of the ?: // expression if the condition evaluates to false. This is the same as getRHS. Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); } - + Expr *getLHS() const { return cast_or_null<Expr>(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } + SourceLocation getQuestionLoc() const { return QuestionLoc; } + void setQuestionLoc(SourceLocation L) { QuestionLoc = L; } + + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + virtual SourceRange getSourceRange() const { return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ConditionalOperatorClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass; } static bool classof(const ConditionalOperator *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1555,9 +1824,9 @@ public: AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L, QualType t) : Expr(AddrLabelExprClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} - + /// \brief Build an empty address of a label expression. - explicit AddrLabelExpr(EmptyShell Empty) + explicit AddrLabelExpr(EmptyShell Empty) : Expr(AddrLabelExprClass, Empty) { } SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } @@ -1568,15 +1837,15 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(AmpAmpLoc, LabelLoc); } - + LabelStmt *getLabel() const { return Label; } void setLabel(LabelStmt *S) { Label = S; } static bool classof(const Stmt *T) { - return T->getStmtClass() == AddrLabelExprClass; + return T->getStmtClass() == AddrLabelExprClass; } static bool classof(const AddrLabelExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1592,7 +1861,7 @@ public: StmtExpr(CompoundStmt *substmt, QualType T, SourceLocation lp, SourceLocation rp) : Expr(StmtExprClass, T), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } - + /// \brief Build an empty statement expression. explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } @@ -1603,17 +1872,17 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(LParenLoc, RParenLoc); } - + SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - + static bool classof(const Stmt *T) { - return T->getStmtClass() == StmtExprClass; + return T->getStmtClass() == StmtExprClass; } static bool classof(const StmtExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1628,8 +1897,8 @@ class TypesCompatibleExpr : public Expr { QualType Type2; SourceLocation BuiltinLoc, RParenLoc; public: - TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc, - QualType t1, QualType t2, SourceLocation RP) : + TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc, + QualType t1, QualType t2, SourceLocation RP) : Expr(TypesCompatibleExprClass, ReturnType), Type1(t1), Type2(t2), BuiltinLoc(BLoc), RParenLoc(RP) {} @@ -1641,21 +1910,21 @@ public: void setArgType1(QualType T) { Type1 = T; } QualType getArgType2() const { return Type2; } void setArgType2(QualType T) { Type2 = T; } - + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } - + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - + virtual SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { - return T->getStmtClass() == TypesCompatibleExprClass; + return T->getStmtClass() == TypesCompatibleExprClass; } static bool classof(const TypesCompatibleExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1677,25 +1946,28 @@ class ShuffleVectorExpr : public Expr { Stmt **SubExprs; unsigned NumExprs; +protected: + virtual void DoDestroy(ASTContext &C); + public: - ShuffleVectorExpr(Expr **args, unsigned nexpr, - QualType Type, SourceLocation BLoc, - SourceLocation RP) : + ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP) : Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) { - - SubExprs = new Stmt*[nexpr]; + + SubExprs = new (C) Stmt*[nexpr]; for (unsigned i = 0; i < nexpr; i++) SubExprs[i] = args[i]; } /// \brief Build an empty vector-shuffle expression. - explicit ShuffleVectorExpr(EmptyShell Empty) + explicit ShuffleVectorExpr(EmptyShell Empty) : Expr(ShuffleVectorExprClass, Empty), SubExprs(0) { } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } - + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } @@ -1703,19 +1975,17 @@ public: return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { - return T->getStmtClass() == ShuffleVectorExprClass; + return T->getStmtClass() == ShuffleVectorExprClass; } static bool classof(const ShuffleVectorExpr *) { return true; } - - ~ShuffleVectorExpr() { - delete [] SubExprs; - } - + + ~ShuffleVectorExpr() {} + /// getNumSubExprs - Return the size of the SubExprs array. This includes the /// constant expression, the actual arguments passed in, and the function /// pointers. unsigned getNumSubExprs() const { return NumExprs; } - + /// getExpr - Return the Expr at the specified index. Expr *getExpr(unsigned Index) { assert((Index < NumExprs) && "Arg access out of range!"); @@ -1726,20 +1996,20 @@ public: return cast<Expr>(SubExprs[Index]); } - void setExprs(Expr ** Exprs, unsigned NumExprs); + void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs); unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) { assert((N < NumExprs - 2) && "Shuffle idx out of range!"); return getExpr(N+2)->EvaluateAsInt(Ctx).getZExtValue(); } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. -/// This AST node is similar to the conditional operator (?:) in C, with +/// This AST node is similar to the conditional operator (?:) in C, with /// the following exceptions: /// - the test expression must be a integer constant expression. /// - the expression returned acts like the chosen subexpression in every @@ -1753,13 +2023,13 @@ class ChooseExpr : public Expr { SourceLocation BuiltinLoc, RParenLoc; public: ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t, - SourceLocation RP) - : Expr(ChooseExprClass, t), + SourceLocation RP, bool TypeDependent, bool ValueDependent) + : Expr(ChooseExprClass, t, TypeDependent, ValueDependent), BuiltinLoc(BLoc), RParenLoc(RP) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - } + } /// \brief Build an empty __builtin_choose_expr. explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } @@ -1783,7 +2053,7 @@ public: SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } - + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } @@ -1791,10 +2061,10 @@ public: return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { - return T->getStmtClass() == ChooseExprClass; + return T->getStmtClass() == ChooseExprClass; } static bool classof(const ChooseExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1811,14 +2081,12 @@ class GNUNullExpr : public Expr { SourceLocation TokenLoc; public: - GNUNullExpr(QualType Ty, SourceLocation Loc) + GNUNullExpr(QualType Ty, SourceLocation Loc) : Expr(GNUNullExprClass, Ty), TokenLoc(Loc) { } /// \brief Build an empty GNU __null expression. explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } - GNUNullExpr* Clone(ASTContext &C) const; - /// getTokenLocation - The location of the __null token. SourceLocation getTokenLocation() const { return TokenLoc; } void setTokenLocation(SourceLocation L) { TokenLoc = L; } @@ -1827,10 +2095,10 @@ public: return SourceRange(TokenLoc); } static bool classof(const Stmt *T) { - return T->getStmtClass() == GNUNullExprClass; + return T->getStmtClass() == GNUNullExprClass; } static bool classof(const GNUNullExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -1846,7 +2114,7 @@ public: Val(e), BuiltinLoc(BLoc), RParenLoc(RPLoc) { } - + /// \brief Create an empty __builtin_va_start expression. explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { } @@ -1856,23 +2124,23 @@ public: SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } - + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); - } + } static bool classof(const Stmt *T) { return T->getStmtClass() == VAArgExprClass; } static bool classof(const VAArgExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); - virtual child_iterator child_end(); + virtual child_iterator child_end(); }; - + /// @brief Describes an C or C++ initializer list. /// /// InitListExpr describes an initializer list, which can be used to @@ -1911,9 +2179,10 @@ public: /// return NULL, indicating that the current initializer list also /// serves as its syntactic form. class InitListExpr : public Expr { + // FIXME: Eliminate this vector in favor of ASTContext allocation std::vector<Stmt *> InitExprs; SourceLocation LBraceLoc, RBraceLoc; - + /// Contains the initializer list that describes the syntactic form /// written in the source code. InitListExpr *SyntacticForm; @@ -1932,27 +2201,27 @@ public: /// \brief Build an empty initializer list. explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty) { } - + unsigned getNumInits() const { return InitExprs.size(); } - - const Expr* getInit(unsigned Init) const { + + const Expr* getInit(unsigned Init) const { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null<Expr>(InitExprs[Init]); } - - Expr* getInit(unsigned Init) { + + Expr* getInit(unsigned Init) { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null<Expr>(InitExprs[Init]); } - - void setInit(unsigned Init, Expr *expr) { + + void setInit(unsigned Init, Expr *expr) { assert(Init < getNumInits() && "Initializer access out of range!"); InitExprs[Init] = expr; } /// \brief Reserve space for some number of initializers. void reserveInits(unsigned NumInits); - + /// @brief Specify the number of initializers /// /// If there are more than @p NumInits initializers, the remaining @@ -1984,7 +2253,7 @@ public: bool isExplicit() { return LBraceLoc.isValid() && RBraceLoc.isValid(); } - + SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } @@ -1993,30 +2262,30 @@ public: /// @brief Retrieve the initializer list that describes the /// syntactic form of the initializer. /// - /// + /// InitListExpr *getSyntacticForm() const { return SyntacticForm; } void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; } bool hadArrayRangeDesignator() const { return HadArrayRangeDesignator; } - void sawArrayRangeDesignator(bool ARD = true) { + void sawArrayRangeDesignator(bool ARD = true) { HadArrayRangeDesignator = ARD; } virtual SourceRange getSourceRange() const { return SourceRange(LBraceLoc, RBraceLoc); - } + } static bool classof(const Stmt *T) { - return T->getStmtClass() == InitListExprClass; + return T->getStmtClass() == InitListExprClass; } static bool classof(const InitListExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); - + typedef std::vector<Stmt *>::iterator iterator; typedef std::vector<Stmt *>::reverse_iterator reverse_iterator; - + iterator begin() { return InitExprs.begin(); } iterator end() { return InitExprs.end(); } reverse_iterator rbegin() { return InitExprs.rbegin(); } @@ -2030,7 +2299,7 @@ public: /// designators, or GNU array-range designators) followed by an /// expression that initializes the field or element(s) that the /// designators refer to. For example, given: -/// +/// /// @code /// struct point { /// double x; @@ -2070,7 +2339,7 @@ private: unsigned NumSubExprs : 16; - DesignatedInitExpr(QualType Ty, unsigned NumDesignators, + DesignatedInitExpr(QualType Ty, unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, Expr **IndexExprs, unsigned NumIndexExprs, @@ -2080,6 +2349,9 @@ private: : Expr(DesignatedInitExprClass, EmptyShell()), NumDesignators(0), Designators(0), NumSubExprs(NumSubExprs) { } +protected: + virtual void DoDestroy(ASTContext &C); + public: /// A field designator, e.g., ".x". struct FieldDesignator { @@ -2090,10 +2362,10 @@ public: /// IdentifierInfo*. After semantic analysis has resolved that /// name, the field designator will instead store a FieldDecl*. uintptr_t NameOrField; - + /// The location of the '.' in the designated initializer. unsigned DotLoc; - + /// The location of the field name in the designated initializer. unsigned FieldLoc; }; @@ -2109,7 +2381,7 @@ public: /// indices. Only valid for GNU array-range designators. unsigned EllipsisLoc; /// The location of the ']' terminating the array range designator. - unsigned RBracketLoc; + unsigned RBracketLoc; }; /// @brief Represents a single C99 designator. @@ -2138,8 +2410,8 @@ public: Designator() {} /// @brief Initializes a field designator. - Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, - SourceLocation FieldLoc) + Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, + SourceLocation FieldLoc) : Kind(FieldDesignator) { Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01; Field.DotLoc = DotLoc.getRawEncoding(); @@ -2147,7 +2419,7 @@ public: } /// @brief Initializes an array designator. - Designator(unsigned Index, SourceLocation LBracketLoc, + Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation RBracketLoc) : Kind(ArrayDesignator) { ArrayOrRange.Index = Index; @@ -2157,7 +2429,7 @@ public: } /// @brief Initializes a GNU array-range designator. - Designator(unsigned Index, SourceLocation LBracketLoc, + Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation EllipsisLoc, SourceLocation RBracketLoc) : Kind(ArrayRangeDesignator) { ArrayOrRange.Index = Index; @@ -2227,7 +2499,7 @@ public: } }; - static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, + static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, unsigned NumDesignators, Expr **IndexExprs, unsigned NumIndexExprs, SourceLocation EqualOrColonLoc, @@ -2241,8 +2513,8 @@ public: // Iterator access to the designators. typedef Designator* designators_iterator; designators_iterator designators_begin() { return Designators; } - designators_iterator designators_end() { - return Designators + NumDesignators; + designators_iterator designators_end() { + return Designators + NumDesignators; } Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } @@ -2264,7 +2536,7 @@ public: void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } /// @brief Retrieve the initializer value. - Expr *getInit() const { + Expr *getInit() const { return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin()); } @@ -2294,21 +2566,19 @@ public: /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). - void ExpandDesignator(unsigned Idx, const Designator *First, + void ExpandDesignator(unsigned Idx, const Designator *First, const Designator *Last); virtual SourceRange getSourceRange() const; - virtual void Destroy(ASTContext &C); - static bool classof(const Stmt *T) { - return T->getStmtClass() == DesignatedInitExprClass; + return T->getStmtClass() == DesignatedInitExprClass; } static bool classof(const DesignatedInitExpr *) { return true; } // Iterators virtual child_iterator child_begin(); - virtual child_iterator child_end(); + virtual child_iterator child_end(); }; /// \brief Represents an implicitly-generated value initialization of @@ -2319,16 +2589,16 @@ public: /// initializations not explicitly specified by the user. /// /// \see InitListExpr -class ImplicitValueInitExpr : public Expr { +class ImplicitValueInitExpr : public Expr { public: - explicit ImplicitValueInitExpr(QualType ty) + explicit ImplicitValueInitExpr(QualType ty) : Expr(ImplicitValueInitExprClass, ty) { } /// \brief Construct an empty implicit value initialization. explicit ImplicitValueInitExpr(EmptyShell Empty) : Expr(ImplicitValueInitExprClass, Empty) { } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitValueInitExprClass; } static bool classof(const ImplicitValueInitExpr *) { return true; } @@ -2337,13 +2607,60 @@ public: return SourceRange(); } - ImplicitValueInitExpr *Clone(ASTContext &C) const; + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +class ParenListExpr : public Expr { + Stmt **Exprs; + unsigned NumExprs; + SourceLocation LParenLoc, RParenLoc; + +protected: + virtual void DoDestroy(ASTContext& C); + +public: + ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, + unsigned numexprs, SourceLocation rparenloc); + + ~ParenListExpr() {} + + /// \brief Build an empty paren list. + //explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } + + unsigned getNumExprs() const { return NumExprs; } + + const Expr* getExpr(unsigned Init) const { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr* getExpr(unsigned Init) { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); } + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(LParenLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenListExprClass; + } + static bool classof(const ParenListExpr *) { return true; } // Iterators virtual child_iterator child_begin(); - virtual child_iterator child_end(); + virtual child_iterator child_end(); }; + //===----------------------------------------------------------------------===// // Clang Extensions //===----------------------------------------------------------------------===// @@ -2363,9 +2680,9 @@ class ExtVectorElementExpr : public Expr { public: ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor, SourceLocation loc) - : Expr(ExtVectorElementExprClass, ty), + : Expr(ExtVectorElementExprClass, ty), Base(base), Accessor(&accessor), AccessorLoc(loc) {} - + /// \brief Build an empty vector element expression. explicit ExtVectorElementExpr(EmptyShell Empty) : Expr(ExtVectorElementExprClass, Empty) { } @@ -2382,28 +2699,28 @@ public: /// getNumElements - Get the number of components being selected. unsigned getNumElements() const; - + /// containsDuplicateElements - Return true if any element access is /// repeated. bool containsDuplicateElements() const; - + /// getEncodedElementAccess - Encode the elements accessed into an llvm /// aggregate Constant of ConstantInt(s). void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const; - + virtual SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), AccessorLoc); } - + /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool isArrow() const; - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ExtVectorElementExprClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExtVectorElementExprClass; } static bool classof(const ExtVectorElementExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -2418,7 +2735,7 @@ protected: bool HasBlockDeclRefExprs; public: BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs) - : Expr(BlockExprClass, ty), + : Expr(BlockExprClass, ty), TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {} /// \brief Build an empty block expression. @@ -2445,25 +2762,25 @@ public: bool hasBlockDeclRefExprs() const { return HasBlockDeclRefExprs; } void setHasBlockDeclRefExprs(bool BDRE) { HasBlockDeclRefExprs = BDRE; } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == BlockExprClass; } static bool classof(const BlockExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + /// BlockDeclRefExpr - A reference to a declared variable, function, /// enum, etc. class BlockDeclRefExpr : public Expr { - ValueDecl *D; + ValueDecl *D; SourceLocation Loc; bool IsByRef : 1; bool ConstQualAdded : 1; public: - BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef, + BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef, bool constAdded = false) : Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded) {} @@ -2472,7 +2789,7 @@ public: // block. explicit BlockDeclRefExpr(EmptyShell Empty) : Expr(BlockDeclRefExprClass, Empty) { } - + ValueDecl *getDecl() { return D; } const ValueDecl *getDecl() const { return D; } void setDecl(ValueDecl *VD) { D = VD; } @@ -2481,18 +2798,18 @@ public: void setLocation(SourceLocation L) { Loc = L; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - + bool isByRef() const { return IsByRef; } void setByRef(bool BR) { IsByRef = BR; } - + bool isConstQualAdded() const { return ConstQualAdded; } void setConstQualAdded(bool C) { ConstQualAdded = C; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == BlockDeclRefExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == BlockDeclRefExprClass; } static bool classof(const BlockDeclRefExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 7d76a49d1267..3f66b1f40bfc 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -22,6 +22,7 @@ namespace clang { class CXXConstructorDecl; class CXXDestructorDecl; + class CXXMethodDecl; class CXXTemporary; //===--------------------------------------------------------------------===// @@ -46,15 +47,19 @@ class CXXOperatorCallExpr : public CallExpr { OverloadedOperatorKind Operator; public: - CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, - Expr **args, unsigned numargs, QualType t, + CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, + Expr **args, unsigned numargs, QualType t, SourceLocation operatorloc) : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc), Operator(Op) {} + explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : + CallExpr(C, CXXOperatorCallExprClass, Empty) { } + /// getOperator - Returns the kind of overloaded operator that this /// expression refers to. OverloadedOperatorKind getOperator() const { return Operator; } + void setOperator(OverloadedOperatorKind Kind) { Operator = Kind; } /// getOperatorLoc - Returns the location of the operator symbol in /// the expression. When @c getOperator()==OO_Call, this is the @@ -64,9 +69,9 @@ public: SourceLocation getOperatorLoc() const { return getRParenLoc(); } virtual SourceRange getSourceRange() const; - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXOperatorCallExprClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXOperatorCallExprClass; } static bool classof(const CXXOperatorCallExpr *) { return true; } }; @@ -90,7 +95,7 @@ public: /// operation would return "x". Expr *getImplicitObjectArgument(); - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXMemberCallExprClass; } static bool classof(const CXXMemberCallExpr *) { return true; } @@ -108,9 +113,9 @@ private: SourceLocation Loc; // the location of the casting op protected: - CXXNamedCastExpr(StmtClass SC, QualType ty, Expr *op, QualType writtenTy, - SourceLocation l) - : ExplicitCastExpr(SC, ty, op, writtenTy), Loc(l) {} + CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op, + QualType writtenTy, SourceLocation l) + : ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {} public: const char *getCastName() const; @@ -123,7 +128,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd()); } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { switch (T->getStmtClass()) { case CXXNamedCastExprClass: case CXXStaticCastExprClass: @@ -139,32 +144,34 @@ public: }; /// CXXStaticCastExpr - A C++ @c static_cast expression (C++ [expr.static.cast]). -/// +/// /// This expression node represents a C++ static cast, e.g., /// @c static_cast<int>(1.0). class CXXStaticCastExpr : public CXXNamedCastExpr { public: - CXXStaticCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXStaticCastExprClass, ty, op, writtenTy, l) {} + CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op, + QualType writtenTy, SourceLocation l) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {} - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXStaticCastExprClass; } static bool classof(const CXXStaticCastExpr *) { return true; } }; /// CXXDynamicCastExpr - A C++ @c dynamic_cast expression -/// (C++ [expr.dynamic.cast]), which may perform a run-time check to +/// (C++ [expr.dynamic.cast]), which may perform a run-time check to /// determine how to perform the type cast. -/// +/// /// This expression node represents a dynamic cast, e.g., /// @c dynamic_cast<Derived*>(BasePtr). class CXXDynamicCastExpr : public CXXNamedCastExpr { public: - CXXDynamicCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, op, writtenTy, l) {} + CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, QualType writtenTy, + SourceLocation l) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {} - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDynamicCastExprClass; } static bool classof(const CXXDynamicCastExpr *) { return true; } @@ -173,16 +180,17 @@ public: /// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++ /// [expr.reinterpret.cast]), which provides a differently-typed view /// of a value but performs no actual work at run time. -/// +/// /// This expression node represents a reinterpret cast, e.g., /// @c reinterpret_cast<int>(VoidPtr). class CXXReinterpretCastExpr : public CXXNamedCastExpr { public: - CXXReinterpretCastExpr(QualType ty, Expr *op, QualType writtenTy, - SourceLocation l) - : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, op, writtenTy, l) {} + CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op, + QualType writtenTy, SourceLocation l) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, + writtenTy, l) {} - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXReinterpretCastExprClass; } static bool classof(const CXXReinterpretCastExpr *) { return true; } @@ -190,41 +198,39 @@ public: /// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]), /// which can remove type qualifiers but does not change the underlying value. -/// +/// /// This expression node represents a const cast, e.g., /// @c const_cast<char*>(PtrToConstChar). class CXXConstCastExpr : public CXXNamedCastExpr { public: - CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy, + CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXConstCastExprClass, ty, op, writtenTy, l) {} + : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {} - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstCastExprClass; } static bool classof(const CXXConstCastExpr *) { return true; } }; /// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal. -/// +/// class CXXBoolLiteralExpr : public Expr { bool Value; SourceLocation Loc; public: - CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : Expr(CXXBoolLiteralExprClass, Ty), Value(val), Loc(l) {} - CXXBoolLiteralExpr* Clone(ASTContext &C) const; - bool getValue() const { return Value; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXBoolLiteralExprClass; } static bool classof(const CXXBoolLiteralExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -237,8 +243,6 @@ public: CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : Expr(CXXNullPtrLiteralExprClass, Ty), Loc(l) {} - CXXNullPtrLiteralExpr* Clone(ASTContext &C) const; - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } static bool classof(const Stmt *T) { @@ -318,7 +322,7 @@ class CXXThisExpr : public Expr { SourceLocation Loc; public: - CXXThisExpr(SourceLocation L, QualType Type) + CXXThisExpr(SourceLocation L, QualType Type) : Expr(CXXThisExprClass, Type, // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) @@ -327,7 +331,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXThisExprClass; } static bool classof(const CXXThisExpr *) { return true; } @@ -379,14 +383,20 @@ public: /// supply arguments for all of the parameters. class CXXDefaultArgExpr : public Expr { ParmVarDecl *Param; + +protected: + CXXDefaultArgExpr(StmtClass SC, ParmVarDecl *param) + : Expr(SC, param->hasUnparsedDefaultArg() ? + param->getType().getNonReferenceType() + : param->getDefaultArg()->getType()), + Param(param) { } + public: // Param is the parameter whose default argument is used by this // expression. - explicit CXXDefaultArgExpr(ParmVarDecl *param) - : Expr(CXXDefaultArgExprClass, - param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType() - : param->getDefaultArg()->getType()), - Param(param) { } + static CXXDefaultArgExpr *Create(ASTContext &C, ParmVarDecl *Param) { + return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Param); + } // Retrieve the parameter that the argument was created from. const ParmVarDecl *getParam() const { return Param; } @@ -416,36 +426,39 @@ public: class CXXTemporary { /// Destructor - The destructor that needs to be called. const CXXDestructorDecl *Destructor; - + CXXTemporary(const CXXDestructorDecl *destructor) : Destructor(destructor) { } ~CXXTemporary() { } public: - static CXXTemporary *Create(ASTContext &C, + static CXXTemporary *Create(ASTContext &C, const CXXDestructorDecl *Destructor); - void Destroy(ASTContext &C); - + + void Destroy(ASTContext &Ctx); + const CXXDestructorDecl *getDestructor() const { return Destructor; } }; -/// CXXBindTemporaryExpr - Represents binding an expression to a temporary, +/// CXXBindTemporaryExpr - Represents binding an expression to a temporary, /// so its destructor can be called later. class CXXBindTemporaryExpr : public Expr { CXXTemporary *Temp; - + Stmt *SubExpr; - CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr) + CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr) : Expr(CXXBindTemporaryExprClass, subexpr->getType()), Temp(temp), SubExpr(subexpr) { } - ~CXXBindTemporaryExpr() { } + ~CXXBindTemporaryExpr() { } + +protected: + virtual void DoDestroy(ASTContext &C); public: - static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp, + static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp, Expr* SubExpr); - void Destroy(ASTContext &C); - + CXXTemporary *getTemporary() { return Temp; } const CXXTemporary *getTemporary() const { return Temp; } @@ -453,7 +466,9 @@ public: Expr *getSubExpr() { return cast<Expr>(SubExpr); } void setSubExpr(Expr *E) { SubExpr = E; } - virtual SourceRange getSourceRange() const { return SourceRange(); } + virtual SourceRange getSourceRange() const { + return SubExpr->getSourceRange(); + } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *T) { @@ -471,32 +486,38 @@ class CXXConstructExpr : public Expr { CXXConstructorDecl *Constructor; bool Elidable; - + Stmt **Args; unsigned NumArgs; - protected: - CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs); - ~CXXConstructExpr() { } + ~CXXConstructExpr() { } + + virtual void DoDestroy(ASTContext &C); public: + /// \brief Construct an empty C++ construction expression that will store + /// \p numargs arguments. + CXXConstructExpr(EmptyShell Empty, ASTContext &C, unsigned numargs); + static CXXConstructExpr *Create(ASTContext &C, QualType T, - CXXConstructorDecl *D, bool Elidable, + CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs); - - void Destroy(ASTContext &C); - - CXXConstructorDecl* getConstructor() const { return Constructor; } + + CXXConstructorDecl* getConstructor() const { return Constructor; } + void setConstructor(CXXConstructorDecl *C) { Constructor = C; } + /// \brief Whether this construction is elidable. bool isElidable() const { return Elidable; } - + void setElidable(bool E) { Elidable = E; } + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; - + arg_iterator arg_begin() { return Args; } arg_iterator arg_end() { return Args + NumArgs; } const_arg_iterator arg_begin() const { return Args; } @@ -504,14 +525,36 @@ public: unsigned getNumArgs() const { return NumArgs; } - virtual SourceRange getSourceRange() const { return SourceRange(); } + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + Args[Arg] = ArgExpr; + } + + virtual SourceRange getSourceRange() const { + // FIXME: Should we know where the parentheses are, if there are any? + if (NumArgs == 0) + return SourceRange(); + + return SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstructExprClass || T->getStmtClass() == CXXTemporaryObjectExprClass; } static bool classof(const CXXConstructExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -524,20 +567,21 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr { SourceLocation TyBeginLoc; SourceLocation RParenLoc; public: - CXXFunctionalCastExpr(QualType ty, QualType writtenTy, - SourceLocation tyBeginLoc, Expr *castExpr, - SourceLocation rParenLoc) : - ExplicitCastExpr(CXXFunctionalCastExprClass, ty, castExpr, writtenTy), - TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + CXXFunctionalCastExpr(QualType ty, QualType writtenTy, + SourceLocation tyBeginLoc, CastKind kind, + Expr *castExpr, SourceLocation rParenLoc) + : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr, + writtenTy), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - + virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXFunctionalCastExprClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFunctionalCastExprClass; } static bool classof(const CXXFunctionalCastExpr *) { return true; } }; @@ -545,7 +589,7 @@ public: /// @brief Represents a C++ functional cast expression that builds a /// temporary object. /// -/// This expression type represents a C++ "functional" cast +/// This expression type represents a C++ "functional" cast /// (C++[expr.type.conv]) with N != 1 arguments that invokes a /// constructor to build a temporary object. If N == 0 but no /// constructor will be called (because the functional cast is @@ -566,12 +610,12 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr { SourceLocation RParenLoc; public: - CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, - QualType writtenTy, SourceLocation tyBeginLoc, - Expr **Args,unsigned NumArgs, + CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, + QualType writtenTy, SourceLocation tyBeginLoc, + Expr **Args,unsigned NumArgs, SourceLocation rParenLoc); - ~CXXTemporaryObjectExpr() { } + ~CXXTemporaryObjectExpr() { } SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -579,7 +623,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXTemporaryObjectExprClass; } static bool classof(const CXXTemporaryObjectExpr *) { return true; } @@ -596,30 +640,28 @@ class CXXZeroInitValueExpr : public Expr { public: CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc, - SourceLocation rParenLoc ) : + SourceLocation rParenLoc ) : Expr(CXXZeroInitValueExprClass, ty, false, false), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} - + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } /// @brief Whether this initialization expression was /// implicitly-generated. - bool isImplicit() const { - return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); + bool isImplicit() const { + return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); } virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } - - CXXZeroInitValueExpr* Clone(ASTContext &C) const; - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXZeroInitValueExprClass; } static bool classof(const CXXZeroInitValueExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -634,28 +676,26 @@ class CXXConditionDeclExpr : public DeclRefExpr { public: CXXConditionDeclExpr(SourceLocation startLoc, SourceLocation eqLoc, VarDecl *var) - : DeclRefExpr(CXXConditionDeclExprClass, var, + : DeclRefExpr(CXXConditionDeclExprClass, var, var->getType().getNonReferenceType(), startLoc, var->getType()->isDependentType(), /*FIXME:integral constant?*/ var->getType()->isDependentType()) {} - virtual void Destroy(ASTContext& Ctx); - SourceLocation getStartLoc() const { return getLocation(); } - + VarDecl *getVarDecl() { return cast<VarDecl>(getDecl()); } const VarDecl *getVarDecl() const { return cast<VarDecl>(getDecl()); } virtual SourceRange getSourceRange() const { return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd()); } - - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConditionDeclExprClass; } static bool classof(const CXXConditionDeclExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -707,7 +747,7 @@ public: QualType getAllocatedType() const { assert(getType()->isPointerType()); - return getType()->getAsPointerType()->getPointeeType(); + return getType()->getAs<PointerType>()->getPointeeType(); } FunctionDecl *getOperatorNew() const { return OperatorNew; } @@ -831,6 +871,108 @@ public: virtual child_iterator child_end(); }; +/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]). +/// +/// Example: +/// +/// \code +/// template<typename T> +/// void destroy(T* ptr) { +/// ptr->~T(); +/// } +/// \endcode +/// +/// When the template is parsed, the expression \c ptr->~T will be stored as +/// a member reference expression. If it then instantiated with a scalar type +/// as a template argument for T, the resulting expression will be a +/// pseudo-destructor expression. +class CXXPseudoDestructorExpr : public Expr { + /// \brief The base expression (that is being destroyed). + Stmt *Base; + + /// \brief Whether the operator was an arrow ('->'); otherwise, it was a + /// period ('.'). + bool IsArrow : 1; + + /// \brief The location of the '.' or '->' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that follows the operator, if present. + NestedNameSpecifier *Qualifier; + + /// \brief The source range that covers the nested-name-specifier, if + /// present. + SourceRange QualifierRange; + + /// \brief The type being destroyed. + QualType DestroyedType; + + /// \brief The location of the type after the '~'. + SourceLocation DestroyedTypeLoc; + +public: + CXXPseudoDestructorExpr(ASTContext &Context, + Expr *Base, bool isArrow, SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + QualType DestroyedType, + SourceLocation DestroyedTypeLoc) + : Expr(CXXPseudoDestructorExprClass, + Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, + false, 0)), + /*isTypeDependent=*/false, + /*isValueDependent=*/Base->isValueDependent()), + Base(static_cast<Stmt *>(Base)), IsArrow(isArrow), + OperatorLoc(OperatorLoc), Qualifier(Qualifier), + QualifierRange(QualifierRange), DestroyedType(DestroyedType), + DestroyedTypeLoc(DestroyedTypeLoc) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return Qualifier != 0; } + + /// \brief If the member name was qualified, retrieves the source range of + /// the nested-name-specifier that precedes the member name. Otherwise, + /// returns an empty source range. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Determine whether this pseudo-destructor expression was written + /// using an '->' (otherwise, it used a '.'). + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// \brief Retrieve the location of the '.' or '->' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the type that is being destroyed. + QualType getDestroyedType() const { return DestroyedType; } + + /// \brief Retrieve the location of the type being destroyed. + SourceLocation getDestroyedTypeLoc() const { return DestroyedTypeLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(Base->getLocStart(), DestroyedTypeLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXPseudoDestructorExprClass; + } + static bool classof(const CXXPseudoDestructorExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// \brief Represents the name of a function that has not been /// resolved to any declaration. /// @@ -848,7 +990,7 @@ public: /// } /// @endcode class UnresolvedFunctionNameExpr : public Expr { - /// The name that was present in the source + /// The name that was present in the source DeclarationName Name; /// The location of this name in the source code @@ -867,9 +1009,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - UnresolvedFunctionNameExpr* Clone(ASTContext &C) const; - - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == UnresolvedFunctionNameExprClass; } static bool classof(const UnresolvedFunctionNameExpr *) { return true; } @@ -909,7 +1049,7 @@ public: QualType getQueriedType() const { return QueriedType; } - bool EvaluateTrait() const; + bool EvaluateTrait(ASTContext&) const; static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryTypeTraitExprClass; @@ -934,9 +1074,9 @@ class QualifiedDeclRefExpr : public DeclRefExpr { NestedNameSpecifier *NNS; public: - QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, + QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD, SourceRange R, NestedNameSpecifier *NNS) - : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), + : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), QualifierRange(R), NNS(NNS) { } /// \brief Retrieve the source range of the nested-name-specifier. @@ -946,8 +1086,8 @@ public: /// declaration. NestedNameSpecifier *getQualifier() const { return NNS; } - virtual SourceRange getSourceRange() const { - return SourceRange(QualifierRange.getBegin(), getLocation()); + virtual SourceRange getSourceRange() const { + return SourceRange(QualifierRange.getBegin(), getLocation()); } static bool classof(const Stmt *T) { @@ -985,11 +1125,16 @@ class UnresolvedDeclRefExpr : public Expr { /// declaration name. NestedNameSpecifier *NNS; + /// \brief Whether this expr is an address of (&) operand. + bool IsAddressOfOperand; + public: UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, - SourceRange R, NestedNameSpecifier *NNS) - : Expr(UnresolvedDeclRefExprClass, T, true, true), - Name(N), Loc(L), QualifierRange(R), NNS(NNS) { } + SourceRange R, NestedNameSpecifier *NNS, + bool IsAddressOfOperand) + : Expr(UnresolvedDeclRefExprClass, T, true, true), + Name(N), Loc(L), QualifierRange(R), NNS(NNS), + IsAddressOfOperand(IsAddressOfOperand) { } /// \brief Retrieve the name that this expression refers to. DeclarationName getDeclName() const { return Name; } @@ -1004,8 +1149,11 @@ public: /// declaration. NestedNameSpecifier *getQualifier() const { return NNS; } - virtual SourceRange getSourceRange() const { - return SourceRange(QualifierRange.getBegin(), getLocation()); + /// \brief Retrieve whether this is an address of (&) operand. + + bool isAddressOfOperand() const { return IsAddressOfOperand; } + virtual SourceRange getSourceRange() const { + return SourceRange(QualifierRange.getBegin(), getLocation()); } static bool classof(const Stmt *T) { @@ -1017,40 +1165,42 @@ public: virtual StmtIterator child_end(); }; -/// \brief An expression that refers to a C++ template-id, such as -/// @c isa<FunctionDecl>. +/// \brief An expression that refers to a C++ template-id, such as +/// @c isa<FunctionDecl>. class TemplateIdRefExpr : public Expr { /// \brief If this template-id was qualified-id, e.g., @c std::sort<int>, /// this nested name specifier contains the @c std::. NestedNameSpecifier *Qualifier; - + /// \brief If this template-id was a qualified-id, e.g., @c std::sort<int>, /// this covers the source code range of the @c std::. SourceRange QualifierRange; - + /// \brief The actual template to which this template-id refers. TemplateName Template; - + /// \brief The source location of the template name. SourceLocation TemplateNameLoc; /// \brief The source location of the left angle bracket ('<'); SourceLocation LAngleLoc; - + /// \brief The source location of the right angle bracket ('>'); SourceLocation RAngleLoc; - + /// \brief The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; - + TemplateIdRefExpr(QualType T, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - + + virtual void DoDestroy(ASTContext &Context); + public: static TemplateIdRefExpr * Create(ASTContext &Context, QualType T, @@ -1058,77 +1208,77 @@ public: TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - - void Destroy(ASTContext &Context); - + /// \brief Retrieve the nested name specifier used to qualify the name of /// this template-id, e.g., the "std::sort" in @c std::sort<int>, or NULL /// if this template-id was an unqualified-id. NestedNameSpecifier *getQualifier() const { return Qualifier; } - + /// \brief Retrieve the source range describing the nested name specifier /// used to qualified the name of this template-id, if the name was qualified. SourceRange getQualifierRange() const { return QualifierRange; } - + /// \brief Retrieve the name of the template referenced, e.g., "sort" in /// @c std::sort<int>; TemplateName getTemplateName() const { return Template; } - + /// \brief Retrieve the location of the name of the template referenced, e.g., /// the location of "sort" in @c std::sort<int>. SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; } - - /// \brief Retrieve the location of the left angle bracket following the + + /// \brief Retrieve the location of the left angle bracket following the /// template name ('<'). SourceLocation getLAngleLoc() const { return LAngleLoc; } - + /// \brief Retrieve the template arguments provided as part of this /// template-id. - const TemplateArgument *getTemplateArgs() const { + const TemplateArgument *getTemplateArgs() const { return reinterpret_cast<const TemplateArgument *>(this + 1); } - + /// \brief Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { return NumTemplateArgs; } - - /// \brief Retrieve the location of the right angle bracket following the + + /// \brief Retrieve the location of the right angle bracket following the /// template arguments ('>'). SourceLocation getRAngleLoc() const { return RAngleLoc; } - + virtual SourceRange getSourceRange() const { return SourceRange(Qualifier? QualifierRange.getBegin() : TemplateNameLoc, RAngleLoc); } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); - - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == TemplateIdRefExprClass; } static bool classof(const TemplateIdRefExpr *) { return true; } }; - + class CXXExprWithTemporaries : public Expr { Stmt *SubExpr; - + CXXTemporary **Temps; unsigned NumTemps; bool ShouldDestroyTemps; - - CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps, + + CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps, bool ShouldDestroyTemps); ~CXXExprWithTemporaries(); - + +protected: + virtual void DoDestroy(ASTContext &C); + public: static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps, bool ShouldDestroyTemporaries); - void Destroy(ASTContext &C); - + unsigned getNumTemporaries() const { return NumTemps; } CXXTemporary *getTemporary(unsigned i) { assert(i < NumTemps && "Index out of range"); @@ -1138,16 +1288,18 @@ public: assert(i < NumTemps && "Index out of range"); return Temps[i]; } - + bool shouldDestroyTemporaries() const { return ShouldDestroyTemps; } - + void removeLastTemporary() { NumTemps--; } - + Expr *getSubExpr() { return cast<Expr>(SubExpr); } const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } void setSubExpr(Expr *E) { SubExpr = E; } - virtual SourceRange getSourceRange() const { return SourceRange(); } + virtual SourceRange getSourceRange() const { + return SubExpr->getSourceRange(); + } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *T) { @@ -1196,7 +1348,7 @@ class CXXUnresolvedConstructExpr : public Expr { /// \brief The number of arguments used to construct the type. unsigned NumArgs; - + CXXUnresolvedConstructExpr(SourceLocation TyBegin, QualType T, SourceLocation LParenLoc, @@ -1205,7 +1357,7 @@ class CXXUnresolvedConstructExpr : public Expr { SourceLocation RParenLoc); public: - static CXXUnresolvedConstructExpr *Create(ASTContext &C, + static CXXUnresolvedConstructExpr *Create(ASTContext &C, SourceLocation TyBegin, QualType T, SourceLocation LParenLoc, @@ -1247,7 +1399,7 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXUnresolvedConstructExprClass; } static bool classof(const CXXUnresolvedConstructExpr *) { return true; } @@ -1257,37 +1409,108 @@ public: virtual child_iterator child_end(); }; -/// \brief +/// \brief Represents a C++ member access expression where the actual member +/// referenced could not be resolved, e.g., because the base expression or the +/// member name was dependent. class CXXUnresolvedMemberExpr : public Expr { /// \brief The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Stmt *Base; - + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. - bool IsArrow; + bool IsArrow : 1; + + /// \brief Whether this member expression has explicitly-specified template + /// arguments. + bool HasExplicitTemplateArgumentList : 1; /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifier *Qualifier; + + /// \brief The source range covering the nested name specifier. + SourceRange QualifierRange; + + /// \brief In a qualified member access expression such as t->Base::f, this + /// member stores the resolves of name lookup in the context of the member + /// access expression, to be used at instantiation time. + /// + /// FIXME: This member, along with the Qualifier and QualifierRange, could + /// be stuck into a structure that is optionally allocated at the end of + /// the CXXUnresolvedMemberExpr, to save space in the common case. + NamedDecl *FirstQualifierFoundInScope; + /// \brief The member to which this member expression refers, which /// can be name, overloaded operator, or destructor. - /// FIXME: could also be a template-id, and we might have a - /// nested-name-specifier as well. + /// FIXME: could also be a template-id DeclarationName Member; /// \brief The location of the member name. SourceLocation MemberLoc; + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { + if (!HasExplicitTemplateArgumentList) + return 0; + + return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast<CXXUnresolvedMemberExpr *>(this) + ->getExplicitTemplateArgumentList(); + } + + CXXUnresolvedMemberExpr(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); + public: - CXXUnresolvedMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + CXXUnresolvedMemberExpr(ASTContext &C, + Expr *Base, bool IsArrow, SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc) - : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc), - Member(Member), MemberLoc(MemberLoc) { } + : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + Member(Member), MemberLoc(MemberLoc) { } + + static CXXUnresolvedMemberExpr * + Create(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. @@ -1303,6 +1526,29 @@ public: SourceLocation getOperatorLoc() const { return OperatorLoc; } void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Retrieve the source range covering the nested-name-specifier + /// that qualifies the member name. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the first part of the nested-name-specifier that was + /// found in the scope of the member access expression when the member access + /// was initially parsed. + /// + /// This function only returns a useful result when member access expression + /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration + /// returned by this function describes what was found by unqualified name + /// lookup for the identifier "Base" within the scope of the member access + /// expression itself. At template instantiation time, this information is + /// combined with the results of name lookup into the type of the object + /// expression itself (the class type of x). + NamedDecl *getFirstQualifierFoundInScope() const { + return FirstQualifierFoundInScope; + } + /// \brief Retrieve the name of the member that this expression /// refers to. DeclarationName getMember() const { return Member; } @@ -1313,11 +1559,58 @@ public: SourceLocation getMemberLoc() const { return MemberLoc; } void setMemberLoc(SourceLocation L) { MemberLoc = L; } + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgumentList() { + return HasExplicitTemplateArgumentList; + } + + /// \brief Retrieve the location of the left angle bracket following the + /// member name ('<'), if any. + SourceLocation getLAngleLoc() const { + if (!HasExplicitTemplateArgumentList) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgument *getTemplateArgs() const { + if (!HasExplicitTemplateArgumentList) + return 0; + + return getExplicitTemplateArgumentList()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!HasExplicitTemplateArgumentList) + return 0; + + return getExplicitTemplateArgumentList()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket following the + /// template arguments ('>'). + SourceLocation getRAngleLoc() const { + if (!HasExplicitTemplateArgumentList) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->RAngleLoc; + } + virtual SourceRange getSourceRange() const { + if (HasExplicitTemplateArgumentList) + return SourceRange(Base->getSourceRange().getBegin(), + getRAngleLoc()); + return SourceRange(Base->getSourceRange().getBegin(), MemberLoc); } - static bool classof(const Stmt *T) { + + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXUnresolvedMemberExprClass; } static bool classof(const CXXUnresolvedMemberExpr *) { return true; } diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index e00833b5820e..0613f4c095f8 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -22,7 +22,7 @@ namespace clang { class ASTContext; class ObjCMethodDecl; class ObjCPropertyDecl; - + /// ObjCStringLiteral, used for Objective-C string literals /// i.e. @"foo". class ObjCStringLiteral : public Expr { @@ -34,8 +34,6 @@ public: explicit ObjCStringLiteral(EmptyShell Empty) : Expr(ObjCStringLiteralClass, Empty) {} - ObjCStringLiteral* Clone(ASTContext &C) const; - StringLiteral *getString() { return cast<StringLiteral>(String); } const StringLiteral *getString() const { return cast<StringLiteral>(String); } void setString(StringLiteral *S) { String = S; } @@ -43,20 +41,20 @@ public: SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } - virtual SourceRange getSourceRange() const { + virtual SourceRange getSourceRange() const { return SourceRange(AtLoc, String->getLocEnd()); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCStringLiteralClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCStringLiteralClass; } - static bool classof(const ObjCStringLiteral *) { return true; } - + static bool classof(const ObjCStringLiteral *) { return true; } + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + /// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type /// and behavior as StringLiteral except that the string initializer is obtained /// from ASTContext with the encoding type as an argument. @@ -64,32 +62,32 @@ class ObjCEncodeExpr : public Expr { QualType EncType; SourceLocation AtLoc, RParenLoc; public: - ObjCEncodeExpr(QualType T, QualType ET, + ObjCEncodeExpr(QualType T, QualType ET, SourceLocation at, SourceLocation rp) - : Expr(ObjCEncodeExprClass, T, ET->isDependentType(), + : Expr(ObjCEncodeExprClass, T, ET->isDependentType(), ET->isDependentType()), EncType(ET), AtLoc(at), RParenLoc(rp) {} - + explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} - + SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - + QualType getEncodedType() const { return EncType; } void setEncodedType(QualType T) { EncType = T; } - + virtual SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCEncodeExprClass; } static bool classof(const ObjCEncodeExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -106,11 +104,9 @@ public: explicit ObjCSelectorExpr(EmptyShell Empty) : Expr(ObjCSelectorExprClass, Empty) {} - ObjCSelectorExpr *Clone(ASTContext &C) const; - Selector getSelector() const { return SelName; } void setSelector(Selector S) { SelName = S; } - + SourceLocation getAtLoc() const { return AtLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } @@ -119,26 +115,26 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } - + /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return SelName.getNumArgs(); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCSelectorExprClass; } static bool classof(const ObjCSelectorExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + /// ObjCProtocolExpr used for protocol expression in Objective-C. This is used /// as: @protocol(foo), as in: /// obj conformsToProtocol:@protocol(foo)] /// The return type is "Protocol*". -class ObjCProtocolExpr : public Expr { - ObjCProtocolDecl *TheProtocol; +class ObjCProtocolExpr : public Expr { + ObjCProtocolDecl *TheProtocol; SourceLocation AtLoc, RParenLoc; public: ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, @@ -148,11 +144,9 @@ public: explicit ObjCProtocolExpr(EmptyShell Empty) : Expr(ObjCProtocolExprClass, Empty) {} - ObjCProtocolExpr *Clone(ASTContext &C) const; - ObjCProtocolDecl *getProtocol() const { return TheProtocol; } void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; } - + SourceLocation getAtLoc() const { return AtLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } @@ -161,12 +155,12 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCProtocolExprClass; } static bool classof(const ObjCProtocolExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -179,44 +173,44 @@ class ObjCIvarRefExpr : public Expr { Stmt *Base; bool IsArrow:1; // True if this is "X->F", false if this is "X.F". bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). - + public: ObjCIvarRefExpr(ObjCIvarDecl *d, - QualType t, SourceLocation l, Expr *base=0, - bool arrow = false, bool freeIvar = false) : + QualType t, SourceLocation l, Expr *base=0, + bool arrow = false, bool freeIvar = false) : Expr(ObjCIvarRefExprClass, t), D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {} - + explicit ObjCIvarRefExpr(EmptyShell Empty) : Expr(ObjCIvarRefExprClass, Empty) {} ObjCIvarDecl *getDecl() { return D; } const ObjCIvarDecl *getDecl() const { return D; } void setDecl(ObjCIvarDecl *d) { D = d; } - + const Expr *getBase() const { return cast<Expr>(Base); } Expr *getBase() { return cast<Expr>(Base); } void setBase(Expr * base) { Base = base; } - + bool isArrow() const { return IsArrow; } bool isFreeIvar() const { return IsFreeIvar; } void setIsArrow(bool A) { IsArrow = A; } void setIsFreeIvar(bool A) { IsFreeIvar = A; } - + SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { + virtual SourceRange getSourceRange() const { return isFreeIvar() ? SourceRange(Loc) - : SourceRange(getBase()->getLocStart(), Loc); + : SourceRange(getBase()->getLocStart(), Loc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCIvarRefExprClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIvarRefExprClass; } static bool classof(const ObjCIvarRefExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -231,113 +225,129 @@ private: SourceLocation IdLoc; Stmt *Base; public: - ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, SourceLocation l, Expr *base) : Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) { } - + explicit ObjCPropertyRefExpr(EmptyShell Empty) : Expr(ObjCPropertyRefExprClass, Empty) {} ObjCPropertyDecl *getProperty() const { return AsProperty; } void setProperty(ObjCPropertyDecl *D) { AsProperty = D; } - + const Expr *getBase() const { return cast<Expr>(Base); } Expr *getBase() { return cast<Expr>(Base); } void setBase(Expr *base) { Base = base; } - + SourceLocation getLocation() const { return IdLoc; } void setLocation(SourceLocation L) { IdLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), IdLoc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCPropertyRefExprClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCPropertyRefExprClass; } static bool classof(const ObjCPropertyRefExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; -/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties -/// (i.e. methods following the property naming convention). KVC stands for -/// Key Value Encoding, a generic concept for accessing or setting a 'Key' -/// value for an object. -/// -class ObjCKVCRefExpr : public Expr { +/// ObjCImplicitSetterGetterRefExpr - A dot-syntax expression to access two +/// methods; one to set a value to an 'ivar' (Setter) and the other to access +/// an 'ivar' (Setter). +/// An example for use of this AST is: +/// @code +/// @interface Test { } +/// - (Test *)crash; +/// - (void)setCrash: (Test*)value; +/// @end +/// void foo(Test *p1, Test *p2) +/// { +/// p2.crash = p1.crash; // Uses ObjCImplicitSetterGetterRefExpr AST +/// } +/// @endcode +class ObjCImplicitSetterGetterRefExpr : public Expr { + /// Setter - Setter method user declared for setting its 'ivar' to a value ObjCMethodDecl *Setter; + /// Getter - Getter method user declared for accessing 'ivar' it controls. ObjCMethodDecl *Getter; - SourceLocation Loc; + /// Location of the member in the dot syntax notation. This is location + /// of the getter method. + SourceLocation MemberLoc; // FIXME: Swizzle these into a single pointer. Stmt *Base; - ObjCInterfaceDecl *ClassProp; + ObjCInterfaceDecl *InterfaceDecl; + /// Location of the receiver class in the dot syntax notation + /// used to call a class method setter/getter. SourceLocation ClassLoc; - + public: - ObjCKVCRefExpr(ObjCMethodDecl *getter, - QualType t, + ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter, + QualType t, ObjCMethodDecl *setter, SourceLocation l, Expr *base) - : Expr(ObjCKVCRefExprClass, t), Setter(setter), - Getter(getter), Loc(l), Base(base), ClassProp(0), + : Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter), + Getter(getter), MemberLoc(l), Base(base), InterfaceDecl(0), ClassLoc(SourceLocation()) { } - ObjCKVCRefExpr(ObjCMethodDecl *getter, - QualType t, + ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter, + QualType t, ObjCMethodDecl *setter, SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL) - : Expr(ObjCKVCRefExprClass, t), Setter(setter), - Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) { + : Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter), + Getter(getter), MemberLoc(l), Base(0), InterfaceDecl(C), ClassLoc(CL) { } - explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){} + explicit ObjCImplicitSetterGetterRefExpr(EmptyShell Empty) + : Expr(ObjCImplicitSetterGetterRefExprClass, Empty){} ObjCMethodDecl *getGetterMethod() const { return Getter; } ObjCMethodDecl *getSetterMethod() const { return Setter; } - ObjCInterfaceDecl *getClassProp() const { return ClassProp; } + ObjCInterfaceDecl *getInterfaceDecl() const { return InterfaceDecl; } void setGetterMethod(ObjCMethodDecl *D) { Getter = D; } void setSetterMethod(ObjCMethodDecl *D) { Setter = D; } - void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; } - + void setInterfaceDecl(ObjCInterfaceDecl *D) { InterfaceDecl = D; } + virtual SourceRange getSourceRange() const { if (Base) - return SourceRange(getBase()->getLocStart(), Loc); - return SourceRange(ClassLoc, Loc); + return SourceRange(getBase()->getLocStart(), MemberLoc); + return SourceRange(ClassLoc, MemberLoc); } const Expr *getBase() const { return cast_or_null<Expr>(Base); } Expr *getBase() { return cast_or_null<Expr>(Base); } void setBase(Expr *base) { Base = base; } - - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } + + SourceLocation getLocation() const { return MemberLoc; } + void setLocation(SourceLocation L) { MemberLoc = L; } SourceLocation getClassLoc() const { return ClassLoc; } void setClassLoc(SourceLocation L) { ClassLoc = L; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCKVCRefExprClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCImplicitSetterGetterRefExprClass; } - static bool classof(const ObjCKVCRefExpr *) { return true; } - + static bool classof(const ObjCImplicitSetterGetterRefExpr *) { return true; } + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + class ObjCMessageExpr : public Expr { // SubExprs - The receiver and arguments of the message expression. Stmt **SubExprs; - + // NumArgs - The number of arguments (not including the receiver) to the // message expression. unsigned NumArgs; - + // A unigue name for this message. Selector SelName; - - // A method prototype for this message (optional). + + // A method prototype for this message (optional). // FIXME: Since method decls contain the selector, and most messages have a // prototype, consider devising a scheme for unifying SelName/MethodProto. ObjCMethodDecl *MethodProto; @@ -350,7 +360,7 @@ class ObjCMessageExpr : public Expr { // Bit-swizzling flags. enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 }; unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; } - + public: /// This constructor is used to represent class messages where the /// ObjCInterfaceDecl* of the receiver is not known. @@ -366,28 +376,28 @@ public: QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); - + // constructor for instance messages. ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); - + explicit ObjCMessageExpr(EmptyShell Empty) : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {} - + ~ObjCMessageExpr() { delete [] SubExprs; } - + /// getReceiver - Returns the receiver of the message expression. /// This can be NULL if the message is for class methods. For /// class methods, use getClassName. /// FIXME: need to handle/detect 'super' usage within a class method. - Expr *getReceiver() { + Expr *getReceiver() { uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; return (x & Flags) == IsInstMeth ? (Expr*) x : 0; - } + } const Expr *getReceiver() const { return const_cast<ObjCMessageExpr*>(this)->getReceiver(); } @@ -395,36 +405,36 @@ public: void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; } Selector getSelector() const { return SelName; } void setSelector(Selector S) { SelName = S; } - + const ObjCMethodDecl *getMethodDecl() const { return MethodProto; } ObjCMethodDecl *getMethodDecl() { return MethodProto; } void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; } - + typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo; - + /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl* /// and IdentifierInfo* of the invoked class. Both can be NULL if this /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none - /// was available when this ObjCMessageExpr object was constructed. - ClassInfo getClassInfo() const; + /// was available when this ObjCMessageExpr object was constructed. + ClassInfo getClassInfo() const; void setClassInfo(const ClassInfo &C); - + /// getClassName - For class methods, this returns the invoked class, - /// and returns NULL otherwise. For instance methods, use getReceiver. + /// and returns NULL otherwise. For instance methods, use getReceiver. IdentifierInfo *getClassName() const { return getClassInfo().second; } - + /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return NumArgs; } - void setNumArgs(unsigned nArgs) { - NumArgs = nArgs; + void setNumArgs(unsigned nArgs) { + NumArgs = nArgs; // FIXME: should always allocate SubExprs via the ASTContext's // allocator. if (!SubExprs) SubExprs = new Stmt* [NumArgs + 1]; } - + /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < NumArgs && "Arg access out of range!"); @@ -439,13 +449,13 @@ public: assert(Arg < NumArgs && "Arg access out of range!"); SubExprs[Arg+ARGS_START] = ArgExpr; } - + SourceLocation getLeftLoc() const { return LBracloc; } SourceLocation getRightLoc() const { return RBracloc; } void setLeftLoc(SourceLocation L) { LBracloc = L; } void setRightLoc(SourceLocation L) { RBracloc = L; } - + void setSourceRange(SourceRange R) { LBracloc = R.getBegin(); RBracloc = R.getEnd(); @@ -458,14 +468,14 @@ public: return T->getStmtClass() == ObjCMessageExprClass; } static bool classof(const ObjCMessageExpr *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); - + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; - + arg_iterator arg_begin() { return &SubExprs[ARGS_START]; } arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; } const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; } @@ -477,16 +487,16 @@ public: class ObjCSuperExpr : public Expr { SourceLocation Loc; public: - ObjCSuperExpr(SourceLocation L, QualType Type) + ObjCSuperExpr(SourceLocation L, QualType Type) : Expr(ObjCSuperExprClass, Type), Loc(L) { } explicit ObjCSuperExpr(EmptyShell Empty) : Expr(ObjCSuperExprClass, Empty) {} SourceLocation getLoc() const { return Loc; } void setLoc(SourceLocation L) { Loc = L; } - + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - static bool classof(const Stmt *T) { + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCSuperExprClass; } static bool classof(const ObjCSuperExpr *) { return true; } @@ -496,6 +506,52 @@ public: virtual child_iterator child_end(); }; +/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. +/// (similiar in spirit to MemberExpr). +class ObjCIsaExpr : public Expr { + /// Base - the expression for the base object pointer. + Stmt *Base; + + /// IsaMemberLoc - This is the location of the 'isa'. + SourceLocation IsaMemberLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow; +public: + ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) + : Expr(ObjCIsaExprClass, ty), + Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} + + /// \brief Build an empty expression. + explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; } + void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(getBase()->getLocStart(), IsaMemberLoc); + } + + virtual SourceLocation getExprLoc() const { return IsaMemberLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIsaExprClass; + } + static bool classof(const ObjCIsaExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 6f862a55d4ba..0670d1a62094 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -33,7 +33,7 @@ struct VisibleDeclaration { /// \brief The name of the declarations. DeclarationName Name; - /// \brief The ID numbers of all of the declarations with this name. + /// \brief The ID numbers of all of the declarations with this name. /// /// These declarations have not necessarily been de-serialized. llvm::SmallVector<unsigned, 4> Declarations; @@ -65,7 +65,7 @@ public: /// replaced with the sorted set of source ranges corresponding to /// comments in the source code. virtual void ReadComments(std::vector<SourceRange> &Comments) = 0; - + /// \brief Resolve a type ID into a type, potentially building a new /// type. virtual QualType GetType(uint32_t ID) = 0; @@ -151,7 +151,7 @@ public: this->Ptr = reinterpret_cast<uint64_t>(Ptr); return *this; } - + LazyOffsetPtr &operator=(uint64_t Offset) { assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); if (Offset == 0) @@ -177,7 +177,7 @@ public: /// \returns a pointer to the AST node. T* get(ExternalASTSource *Source) const { if (isOffset()) { - assert(Source && + assert(Source && "Cannot deserialize a lazy pointer without an AST source"); Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); } diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index b304cc8e8a04..1594b090fea5 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" @@ -26,7 +27,7 @@ namespace clang { class ASTContext; class NamespaceDecl; class IdentifierInfo; -class PrintingPolicy; +struct PrintingPolicy; class Type; class LangOptions; @@ -80,8 +81,8 @@ private: /// \brief Copy constructor used internally to clone nested name /// specifiers. - NestedNameSpecifier(const NestedNameSpecifier &Other) - : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), + NestedNameSpecifier(const NestedNameSpecifier &Other) + : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), Specifier(Other.Specifier) { } @@ -89,7 +90,7 @@ private: /// \brief Either find or insert the given nested name specifier /// mockup in the given context. - static NestedNameSpecifier *FindOrInsert(ASTContext &Context, + static NestedNameSpecifier *FindOrInsert(ASTContext &Context, const NestedNameSpecifier &Mockup); public: @@ -98,20 +99,28 @@ public: /// The prefix must be dependent, since nested name specifiers /// referencing an identifier are only permitted when the identifier /// cannot be resolved. - static NestedNameSpecifier *Create(ASTContext &Context, - NestedNameSpecifier *Prefix, + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, IdentifierInfo *II); /// \brief Builds a nested name specifier that names a namespace. - static NestedNameSpecifier *Create(ASTContext &Context, - NestedNameSpecifier *Prefix, + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, NamespaceDecl *NS); /// \brief Builds a nested name specifier that names a type. - static NestedNameSpecifier *Create(ASTContext &Context, - NestedNameSpecifier *Prefix, + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, bool Template, Type *T); + /// \brief Builds a specifier that consists of just an identifier. + /// + /// The nested-name-specifier is assumed to be dependent, but has no + /// prefix because the prefix is implied by something outside of the + /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent + /// type. + static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II); + /// \brief Returns the nested name specifier representing the global /// scope. static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context); @@ -126,10 +135,10 @@ public: NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } /// \brief Determine what kind of nested name specifier is stored. - SpecifierKind getKind() const { + SpecifierKind getKind() const { if (Specifier == 0) return Global; - return (SpecifierKind)Prefix.getInt(); + return (SpecifierKind)Prefix.getInt(); } /// \brief Retrieve the identifier stored in this nested name @@ -140,7 +149,7 @@ public: return 0; } - + /// \brief Retrieve the namespace stored in this nested name /// specifier. NamespaceDecl *getAsNamespace() const { @@ -152,7 +161,7 @@ public: /// \brief Retrieve the type stored in this nested name specifier. Type *getAsType() const { - if (Prefix.getInt() == TypeSpec || + if (Prefix.getInt() == TypeSpec || Prefix.getInt() == TypeSpecWithTemplate) return (Type *)Specifier; @@ -179,6 +188,15 @@ public: void dump(const LangOptions &LO); }; +/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + NestedNameSpecifier *NNS) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS), + Diagnostic::ak_nestednamespec); + return DB; +} + } #endif diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index c669991ccc08..f826e1117b66 100644 --- a/include/clang/AST/ParentMap.h +++ b/include/clang/AST/ParentMap.h @@ -17,7 +17,7 @@ namespace clang { class Stmt; class Expr; - + class ParentMap { void* Impl; public: @@ -30,7 +30,7 @@ public: const Stmt *getParent(const Stmt* S) const { return getParent(const_cast<Stmt*>(S)); } - + const Stmt *getParentIgnoreParens(const Stmt *S) const { return getParentIgnoreParens(const_cast<Stmt*>(S)); } @@ -38,13 +38,13 @@ public: bool hasParent(Stmt* S) const { return getParent(S) != 0; } - + bool isConsumedExpr(Expr *E) const; - + bool isConsumedExpr(const Expr *E) const { return isConsumedExpr(const_cast<Expr*>(E)); } }; - + } // end clang namespace #endif diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 6ad3a6bcc276..0635ec5dcd51 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -34,9 +34,10 @@ public: /// declarations should be printed. struct PrintingPolicy { /// \brief Create a default printing policy for C. - PrintingPolicy(const LangOptions &LO) + PrintingPolicy(const LangOptions &LO) : Indentation(2), LangOpts(LO), SuppressSpecifiers(false), - SuppressTag(false), SuppressTagKind(false), Dump(false) { } + SuppressTag(false), SuppressTagKind(false), SuppressScope(false), + Dump(false), ConstantArraySizeAsWritten(false) { } /// \brief The number of spaces to use to indent each line. unsigned Indentation : 8; @@ -74,11 +75,32 @@ struct PrintingPolicy { /// kind of tag, e.g., "struct", "union", "enum". bool SuppressTagKind : 1; + /// \brief Suppresses printing of scope specifiers. + bool SuppressScope : 1; + /// \brief True when we are "dumping" rather than "pretty-printing", /// where dumping involves printing the internal details of the AST /// and pretty-printing involves printing something similar to /// source code. bool Dump : 1; + + /// \brief Whether we should print the sizes of constant array expressions + /// as written in the sources. + /// + /// This flag is determines whether arrays types declared as + /// + /// \code + /// int a[4+10*10]; + /// char a[] = "A string"; + /// \endcode + /// + /// will be printed as written or as follows: + /// + /// \code + /// int a[104]; + /// char a[9] = "A string"; + /// \endcode + bool ConstantArraySizeAsWritten : 1; }; } // end namespace clang diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index ab184563da23..7490b1d66b3e 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -18,83 +18,175 @@ namespace clang { class ASTContext; + class FieldDecl; class RecordDecl; + class CXXRecordDecl; -/// ASTRecordLayout - +/// ASTRecordLayout - /// This class contains layout information for one RecordDecl, /// which is a struct/union/class. The decl represented must be a definition, -/// not a forward declaration. -/// This class is also used to contain layout information for one +/// not a forward declaration. +/// This class is also used to contain layout information for one /// ObjCInterfaceDecl. FIXME - Find appropriate name. /// These objects are managed by ASTContext. class ASTRecordLayout { - uint64_t Size; // Size of record in bits. - uint64_t NextOffset; // Next available offset + /// Size - Size of record in bits. + uint64_t Size; + + /// DataSize - Size of record in bits without tail padding. + uint64_t DataSize; + + /// FieldOffsets - Array of field offsets in bits. uint64_t *FieldOffsets; - unsigned Alignment; // Alignment of record in bits. - unsigned FieldCount; // Number of fields + + // Alignment - Alignment of record in bits. + unsigned Alignment; + + // FieldCount - Number of fields. + unsigned FieldCount; + + struct CXXRecordLayoutInfo { + /// NonVirtualSize - The non-virtual size (in bits) of an object, which is + /// the size of the object without virtual bases. + uint64_t NonVirtualSize; + + /// NonVirtualAlign - The non-virtual alignment (in bits) of an object, + /// which is the alignment of the object without virtual bases. + uint64_t NonVirtualAlign; + + /// PrimaryBase - The primary base for our vtable. + const CXXRecordDecl *PrimaryBase; + /// PrimaryBase - Wether or not the primary base was a virtual base. + bool PrimaryBaseWasVirtual; + + /// BaseOffsets - Contains a map from base classes to their offset. + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets; + + /// VBaseOffsets - Contains a map from vbase classes to their offset. + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets; + }; + + /// CXXInfo - If the record layout is for a C++ record, this will have + /// C++ specific information about the record. + CXXRecordLayoutInfo *CXXInfo; + friend class ASTContext; + friend class ASTRecordLayoutBuilder; - ASTRecordLayout(uint64_t S = 0, unsigned A = 8) - : Size(S), NextOffset(S), Alignment(A), FieldCount(0) {} - ~ASTRecordLayout() { - delete [] FieldOffsets; + ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize, + const uint64_t *fieldoffsets, unsigned fieldcount) + : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), + FieldCount(fieldcount), CXXInfo(0) { + if (FieldCount > 0) { + FieldOffsets = new uint64_t[FieldCount]; + for (unsigned i = 0; i < FieldCount; ++i) + FieldOffsets[i] = fieldoffsets[i]; + } } - /// Initialize record layout. N is the number of fields in this record. - void InitializeLayout(unsigned N) { - FieldCount = N; - FieldOffsets = new uint64_t[N]; - } + // Constructor for C++ records. + ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize, + const uint64_t *fieldoffsets, unsigned fieldcount, + uint64_t nonvirtualsize, unsigned nonvirtualalign, + const CXXRecordDecl *PB, bool PBVirtual, + const std::pair<const CXXRecordDecl *, uint64_t> *bases, + unsigned numbases, + const std::pair<const CXXRecordDecl *, uint64_t> *vbases, + unsigned numvbases) + : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), + FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { + if (FieldCount > 0) { + FieldOffsets = new uint64_t[FieldCount]; + for (unsigned i = 0; i < FieldCount; ++i) + FieldOffsets[i] = fieldoffsets[i]; + } - /// Finalize record layout. Adjust record size based on the alignment. - void FinalizeLayout(bool ForceNonEmpty = false) { - // In C++, records cannot be of size 0. - if (ForceNonEmpty && Size == 0) - Size = 8; - // Finally, round the size of the record up to the alignment of the - // record itself. - Size = (Size + (Alignment-1)) & ~(Alignment-1); + CXXInfo->PrimaryBase = PB; + CXXInfo->PrimaryBaseWasVirtual = PBVirtual; + CXXInfo->NonVirtualSize = nonvirtualsize; + CXXInfo->NonVirtualAlign = nonvirtualalign; + for (unsigned i = 0; i != numbases; ++i) + CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; + for (unsigned i = 0; i != numvbases; ++i) + CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; } - void SetFieldOffset(unsigned FieldNo, uint64_t Offset) { - assert (FieldNo < FieldCount && "Invalid Field No"); - FieldOffsets[FieldNo] = Offset; + ~ASTRecordLayout() { + delete [] FieldOffsets; + delete CXXInfo; } - void SetAlignment(unsigned A) { Alignment = A; } - - /// LayoutField - Field layout. StructPacking is the specified - /// packing alignment (maximum alignment) in bits to use for the - /// structure, or 0 if no packing alignment is specified. - void LayoutField(const FieldDecl *FD, unsigned FieldNo, - bool IsUnion, unsigned StructPacking, - ASTContext &Context); - ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT public: - + /// getAlignment - Get the record alignment in bits. unsigned getAlignment() const { return Alignment; } /// getSize - Get the record size in bits. uint64_t getSize() const { return Size; } - + /// getFieldCount - Get the number of fields in the layout. unsigned getFieldCount() const { return FieldCount; } - + /// getFieldOffset - Get the offset of the given field index, in /// bits. uint64_t getFieldOffset(unsigned FieldNo) const { assert (FieldNo < FieldCount && "Invalid Field No"); return FieldOffsets[FieldNo]; } - - /// getNextOffset - Get the next available (unused) offset in the - /// structure, in bits. - uint64_t getNextOffset() const { - return NextOffset; + + /// getDataSize() - Get the record data size, which is the record size + /// without tail padding, in bits. + uint64_t getDataSize() const { + return DataSize; + } + + /// getNonVirtualSize - Get the non-virtual size (in bits) of an object, + /// which is the size of the object without virtual bases. + uint64_t getNonVirtualSize() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualSize; + } + + /// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object, + /// which is the alignment of the object without virtual bases. + unsigned getNonVirtualAlign() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualAlign; + } + + /// getPrimaryBase - Get the primary base. + const CXXRecordDecl *getPrimaryBase() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBase; + } + /// getPrimaryBaseWasVirtual - Indicates if the primary base was virtual. + bool getPrimaryBaseWasVirtual() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBaseWasVirtual; + } + + /// getBaseClassOffset - Get the offset, in bits, for the given base class. + uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return CXXInfo->BaseOffsets[Base]; + } + + /// getVBaseClassOffset - Get the offset, in bits, for the given base class. + uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return CXXInfo->VBaseOffsets[VBase]; } }; diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h new file mode 100644 index 000000000000..458af1f14423 --- /dev/null +++ b/include/clang/AST/Redeclarable.h @@ -0,0 +1,162 @@ +//===-- Redeclarable.h - Base for Decls that can be redeclared -*- 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 the Redeclarable interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_REDECLARABLE_H +#define LLVM_CLANG_AST_REDECLARABLE_H + +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { + +/// \brief Provides common interface for the Decls that can be redeclared. +template<typename decl_type> +class Redeclarable { + +protected: + struct DeclLink : public llvm::PointerIntPair<decl_type *, 1, bool> { + DeclLink(decl_type *D, bool isLatest) + : llvm::PointerIntPair<decl_type *, 1, bool>(D, isLatest) { } + + typedef llvm::PointerIntPair<decl_type *, 1, bool> base_type; + + bool NextIsPrevious() const { return base_type::getInt() == false; } + bool NextIsLatest() const { return base_type::getInt() == true; } + decl_type *getNext() const { return base_type::getPointer(); } + }; + + struct PreviousDeclLink : public DeclLink { + PreviousDeclLink(decl_type *D) : DeclLink(D, false) { } + }; + + struct LatestDeclLink : public DeclLink { + LatestDeclLink(decl_type *D) : DeclLink(D, true) { } + }; + + /// \brief Points to the next redeclaration in the chain. + /// + /// If NextIsPrevious() is true, this is a link to the previous declaration + /// of this same Decl. If NextIsLatest() is true, this is the first + /// declaration and Link points to the latest declaration. For example: + /// + /// #1 int f(int x, int y = 1); // <pointer to #3, true> + /// #2 int f(int x = 0, int y); // <pointer to #1, false> + /// #3 int f(int x, int y) { return x + y; } // <pointer to #2, false> + /// + /// If there is only one declaration, it is <pointer to self, true> + DeclLink RedeclLink; + +public: + Redeclarable() : RedeclLink(LatestDeclLink(static_cast<decl_type*>(this))) { } + + /// \brief Return the previous declaration of this declaration or NULL if this + /// is the first declaration. + decl_type *getPreviousDeclaration() { + if (RedeclLink.NextIsPrevious()) + return RedeclLink.getNext(); + return 0; + } + const decl_type *getPreviousDeclaration() const { + return const_cast<decl_type *>( + static_cast<const decl_type*>(this))->getPreviousDeclaration(); + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + decl_type *getFirstDeclaration() { + decl_type *D = static_cast<decl_type*>(this); + while (D->getPreviousDeclaration()) + D = D->getPreviousDeclaration(); + return D; + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + const decl_type *getFirstDeclaration() const { + const decl_type *D = static_cast<const decl_type*>(this); + while (D->getPreviousDeclaration()) + D = D->getPreviousDeclaration(); + return D; + } + + /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the + /// first and only declaration. + void setPreviousDeclaration(decl_type *PrevDecl) { + decl_type *First; + + if (PrevDecl) { + // Point to previous. + RedeclLink = PreviousDeclLink(PrevDecl); + First = PrevDecl->getFirstDeclaration(); + assert(First->RedeclLink.NextIsLatest() && "Expected first"); + } else { + // Make this first. + First = static_cast<decl_type*>(this); + } + + // First one will point to this one as latest. + First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); + } + + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + decl_type *Current; + decl_type *Starter; + + public: + typedef decl_type* value_type; + typedef decl_type* reference; + typedef decl_type* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + decl_type *Next = Current->RedeclLink.getNext(); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same decl. + /// It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast<decl_type*>( + static_cast<const decl_type*>(this))); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } +}; + +} + +#endif diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 0a64dafd4e2c..411f215e912e 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -21,11 +21,14 @@ #include "clang/AST/StmtIterator.h" #include "clang/AST/DeclGroup.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/iterator.h" #include "clang/AST/ASTContext.h" #include <string> using llvm::dyn_cast_or_null; +namespace llvm { + class FoldingSetNodeID; +} + namespace clang { class ASTContext; class Expr; @@ -36,21 +39,21 @@ namespace clang { class SourceManager; class StringLiteral; class SwitchStmt; - + //===----------------------------------------------------------------------===// // ExprIterator - Iterators for iterating over Stmt* arrays that contain // only Expr*. This is needed because AST nodes use Stmt* arrays to store // references to children (to be compatible with StmtIterator). //===----------------------------------------------------------------------===// - + class Stmt; class Expr; - + class ExprIterator { Stmt** I; public: ExprIterator(Stmt** i) : I(i) {} - ExprIterator() : I(0) {} + ExprIterator() : I(0) {} ExprIterator& operator++() { ++I; return *this; } ExprIterator operator-(size_t i) { return I-i; } ExprIterator operator+(size_t i) { return I+i; } @@ -64,12 +67,12 @@ namespace clang { bool operator>(const ExprIterator& R) const { return I > R.I; } bool operator>=(const ExprIterator& R) const { return I >= R.I; } }; - + class ConstExprIterator { Stmt* const * I; public: ConstExprIterator(Stmt* const* i) : I(i) {} - ConstExprIterator() : I(0) {} + ConstExprIterator() : I(0) {} ConstExprIterator& operator++() { ++I; return *this; } ConstExprIterator operator+(size_t i) { return I+i; } ConstExprIterator operator-(size_t i) { return I-i; } @@ -81,12 +84,12 @@ namespace clang { bool operator!=(const ConstExprIterator& R) const { return I != R.I; } bool operator>(const ConstExprIterator& R) const { return I > R.I; } bool operator>=(const ConstExprIterator& R) const { return I >= R.I; } - }; - + }; + //===----------------------------------------------------------------------===// // AST classes for statements. //===----------------------------------------------------------------------===// - + /// Stmt - This represents one statement. /// class Stmt { @@ -101,7 +104,11 @@ public: #include "clang/AST/StmtNodes.def" }; private: - const StmtClass sClass; + /// \brief The statement class. + const unsigned sClass : 8; + + /// \brief The reference count for this statement. + unsigned RefCount : 24; // Make vanilla 'new' and 'delete' illegal for Stmts. protected: @@ -112,20 +119,20 @@ protected: void operator delete(void* data) throw() { assert(0 && "Stmts cannot be released with regular 'delete'."); } - + public: // Only allow allocation of Stmts using the allocator in ASTContext - // or by doing a placement new. + // or by doing a placement new. void* operator new(size_t bytes, ASTContext& C, unsigned alignment = 16) throw() { return ::operator new(bytes, C, alignment); } - + void* operator new(size_t bytes, ASTContext* C, unsigned alignment = 16) throw() { return ::operator new(bytes, *C, alignment); } - + void* operator new(size_t bytes, void* mem) throw() { return mem; } @@ -145,23 +152,48 @@ protected: /// DestroyChildren - Invoked by destructors of subclasses of Stmt to /// recursively release child AST nodes. void DestroyChildren(ASTContext& Ctx); - + /// \brief Construct an empty statement. - explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC) { + explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC), RefCount(1) { if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); } + /// \brief Virtual method that performs the actual destruction of + /// this statement. + /// + /// Subclasses should override this method (not Destroy()) to + /// provide class-specific destruction. + virtual void DoDestroy(ASTContext &Ctx); + public: - Stmt(StmtClass SC) : sClass(SC) { + Stmt(StmtClass SC) : sClass(SC), RefCount(1) { if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); } virtual ~Stmt() {} - - virtual void Destroy(ASTContext &Ctx); - StmtClass getStmtClass() const { return sClass; } + /// \brief Destroy the current statement and its children. + void Destroy(ASTContext &Ctx) { + assert(RefCount >= 1); + if (--RefCount == 0) + DoDestroy(Ctx); + } + + /// \brief Increases the reference count for this statement. + /// + /// Invoke the Retain() operation when this statement or expression + /// is being shared by another owner. + Stmt *Retain() { + assert(RefCount >= 1); + ++RefCount; + return this; + } + + StmtClass getStmtClass() const { + assert(RefCount >= 1 && "Referencing already-destroyed statement!"); + return (StmtClass)sClass; + } const char *getStmtClassName() const; - + /// SourceLocation tokens are not useful in isolation - they are low level /// value objects created/interpreted by SourceManager. We assume AST /// clients will have a pointer to the respective SourceManager. @@ -187,23 +219,23 @@ public: /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST /// back to its original source language syntax. void dumpPretty(ASTContext& Context) const; - void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper, + void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation = 0) const { printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation); } void printPretty(llvm::raw_ostream &OS, ASTContext &Context, - PrinterHelper *Helper, + PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation = 0) const; - + /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only /// works on systems with GraphViz (Mac OS X) or dot+gv installed. void viewAST() const; - + // Implement isa<T> support. - static bool classof(const Stmt *) { return true; } - + static bool classof(const Stmt *) { return true; } + /// hasImplicitControlFlow - Some statements (e.g. short circuited operations) /// contain implicit control-flow in the order their subexpressions /// are evaluated. This predicate returns true if this statement has @@ -216,46 +248,60 @@ public: /// AST node. This permits easy iteration over all nodes in the AST. typedef StmtIterator child_iterator; typedef ConstStmtIterator const_child_iterator; - + virtual child_iterator child_begin() = 0; virtual child_iterator child_end() = 0; - + const_child_iterator child_begin() const { return const_child_iterator(const_cast<Stmt*>(this)->child_begin()); } - + const_child_iterator child_end() const { return const_child_iterator(const_cast<Stmt*>(this)->child_end()); } + + /// \brief Produce a unique representation of the given statement. + /// + /// \brief ID once the profiling operation is complete, will contain + /// the unique representation of the given statement. + /// + /// \brief Context the AST context in which the statement resides + /// + /// \brief Canonical whether the profile should be based on the canonical + /// representation of this statement (e.g., where non-type template + /// parameters are identified by index/level rather than their + /// declaration pointers) or the exact representation of the statement as + /// written in the source. + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical); }; /// DeclStmt - Adaptor class for mixing declarations with statements and /// expressions. For example, CompoundStmt mixes statements, expressions -/// and declarations (variables, types). Another example is ForStmt, where +/// and declarations (variables, types). Another example is ForStmt, where /// the first statement can be an expression or a declaration. /// class DeclStmt : public Stmt { DeclGroupRef DG; SourceLocation StartLoc, EndLoc; + public: - DeclStmt(DeclGroupRef dg, SourceLocation startLoc, + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), StartLoc(startLoc), EndLoc(endLoc) {} - + /// \brief Build an empty declaration statement. explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } - virtual void Destroy(ASTContext& Ctx); - /// isSingleDecl - This method returns true if this DeclStmt refers /// to a single Decl. bool isSingleDecl() const { return DG.isSingleDecl(); } - + const Decl *getSingleDecl() const { return DG.getSingleDecl(); } - Decl *getSingleDecl() { return DG.getSingleDecl(); } - + Decl *getSingleDecl() { return DG.getSingleDecl(); } + const DeclGroupRef getDeclGroup() const { return DG; } DeclGroupRef getDeclGroup() { return DG; } void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } @@ -268,19 +314,19 @@ public: SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == DeclStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclStmtClass; } static bool classof(const DeclStmt *) { return true; } - + // Iterators over subexpressions. virtual child_iterator child_begin(); virtual child_iterator child_end(); - + typedef DeclGroupRef::iterator decl_iterator; typedef DeclGroupRef::const_iterator const_decl_iterator; - + decl_iterator decl_begin() { return DG.begin(); } decl_iterator decl_end() { return DG.end(); } const_decl_iterator decl_begin() const { return DG.begin(); } @@ -297,18 +343,16 @@ public: /// \brief Build an empty null statement. explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { } - NullStmt* Clone(ASTContext &C) const; - SourceLocation getSemiLoc() const { return SemiLoc; } void setSemiLoc(SourceLocation L) { SemiLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == NullStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NullStmtClass; } static bool classof(const NullStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -321,24 +365,24 @@ class CompoundStmt : public Stmt { unsigned NumStmts; SourceLocation LBracLoc, RBracLoc; public: - CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts, + CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts, SourceLocation LB, SourceLocation RB) : Stmt(CompoundStmtClass), NumStmts(numStmts), LBracLoc(LB), RBracLoc(RB) { if (NumStmts == 0) { Body = 0; return; } - + Body = new (C) Stmt*[NumStmts]; memcpy(Body, StmtStart, numStmts * sizeof(*Body)); - } + } // \brief Build an empty compound statement. explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { } void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); - + bool body_empty() const { return NumStmts == 0; } unsigned size() const { return NumStmts; } @@ -366,25 +410,25 @@ public: const_reverse_body_iterator body_rbegin() const { return const_reverse_body_iterator(body_end()); } - + const_reverse_body_iterator body_rend() const { return const_reverse_body_iterator(body_begin()); } - - virtual SourceRange getSourceRange() const { - return SourceRange(LBracLoc, RBracLoc); + + virtual SourceRange getSourceRange() const { + return SourceRange(LBracLoc, RBracLoc); } - + SourceLocation getLBracLoc() const { return LBracLoc; } void setLBracLoc(SourceLocation L) { LBracLoc = L; } SourceLocation getRBracLoc() const { return RBracLoc; } void setRBracLoc(SourceLocation L) { RBracLoc = L; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CompoundStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundStmtClass; } static bool classof(const CompoundStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -398,7 +442,7 @@ protected: SwitchCase *NextSwitchCase; SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {} - + public: const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } @@ -409,19 +453,19 @@ public: Stmt *getSubStmt() { return v_getSubStmt(); } virtual SourceRange getSourceRange() const { return SourceRange(); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CaseStmtClass || + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass || T->getStmtClass() == DefaultStmtClass; } static bool classof(const SwitchCase *) { return true; } protected: - virtual Stmt* v_getSubStmt() = 0; + virtual Stmt* v_getSubStmt() = 0; }; class CaseStmt : public SwitchCase { enum { SUBSTMT, LHS, RHS, END_EXPR }; - Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for + Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for // GNU "case 1 ... 4" extension SourceLocation CaseLoc; SourceLocation EllipsisLoc; @@ -430,7 +474,7 @@ class CaseStmt : public SwitchCase { virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, - SourceLocation ellipsisLoc, SourceLocation colonLoc) + SourceLocation ellipsisLoc, SourceLocation colonLoc) : SwitchCase(CaseStmtClass) { SubExprs[SUBSTMT] = 0; SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); @@ -454,32 +498,32 @@ public: Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } - const Expr *getLHS() const { - return reinterpret_cast<const Expr*>(SubExprs[LHS]); + const Expr *getLHS() const { + return reinterpret_cast<const Expr*>(SubExprs[LHS]); } - const Expr *getRHS() const { - return reinterpret_cast<const Expr*>(SubExprs[RHS]); + const Expr *getRHS() const { + return reinterpret_cast<const Expr*>(SubExprs[RHS]); } const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } - - + + virtual SourceRange getSourceRange() const { // Handle deeply nested case statements with iteration instead of recursion. const CaseStmt *CS = this; while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) CS = CS2; - - return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd()); + + return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CaseStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass; } static bool classof(const CaseStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -491,7 +535,7 @@ class DefaultStmt : public SwitchCase { SourceLocation ColonLoc; virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: - DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL), ColonLoc(CL) {} @@ -507,14 +551,14 @@ public: SourceLocation getColonLoc() const { return ColonLoc; } void setColonLoc(SourceLocation L) { ColonLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(DefaultLoc, SubStmt->getLocEnd()); + virtual SourceRange getSourceRange() const { + return SourceRange(DefaultLoc, SubStmt->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == DefaultStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == DefaultStmtClass; } static bool classof(const DefaultStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -525,13 +569,13 @@ class LabelStmt : public Stmt { Stmt *SubStmt; SourceLocation IdentLoc; public: - LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) - : Stmt(LabelStmtClass), Label(label), + LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) + : Stmt(LabelStmtClass), Label(label), SubStmt(substmt), IdentLoc(IL) {} // \brief Build an empty label statement. explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } - + SourceLocation getIdentLoc() const { return IdentLoc; } IdentifierInfo *getID() const { return Label; } void setID(IdentifierInfo *II) { Label = II; } @@ -541,14 +585,14 @@ public: void setIdentLoc(SourceLocation L) { IdentLoc = L; } void setSubStmt(Stmt *SS) { SubStmt = SS; } - virtual SourceRange getSourceRange() const { - return SourceRange(IdentLoc, SubStmt->getLocEnd()); - } - static bool classof(const Stmt *T) { - return T->getStmtClass() == LabelStmtClass; + virtual SourceRange getSourceRange() const { + return SourceRange(IdentLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == LabelStmtClass; } static bool classof(const LabelStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -563,8 +607,8 @@ class IfStmt : public Stmt { SourceLocation IfLoc; SourceLocation ElseLoc; public: - IfStmt(SourceLocation IL, Expr *cond, Stmt *then, - SourceLocation EL = SourceLocation(), Stmt *elsev = 0) + IfStmt(SourceLocation IL, Expr *cond, Stmt *then, + SourceLocation EL = SourceLocation(), Stmt *elsev = 0) : Stmt(IfStmtClass) { SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[THEN] = then; @@ -572,14 +616,14 @@ public: IfLoc = IL; ElseLoc = EL; } - + /// \brief Build an empty if/then/else statement explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } const Stmt *getThen() const { return SubExprs[THEN]; } - void setThen(Stmt *S) { SubExprs[THEN] = S; } + void setThen(Stmt *S) { SubExprs[THEN] = S; } const Stmt *getElse() const { return SubExprs[ELSE]; } void setElse(Stmt *S) { SubExprs[ELSE] = S; } @@ -592,18 +636,18 @@ public: SourceLocation getElseLoc() const { return ElseLoc; } void setElseLoc(SourceLocation L) { ElseLoc = L; } - virtual SourceRange getSourceRange() const { + virtual SourceRange getSourceRange() const { if (SubExprs[ELSE]) return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); else return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd()); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == IfStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IfStmtClass; } static bool classof(const IfStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -613,16 +657,20 @@ public: /// class SwitchStmt : public Stmt { enum { COND, BODY, END_EXPR }; - Stmt* SubExprs[END_EXPR]; + Stmt* SubExprs[END_EXPR]; // This points to a linked list of case and default statements. SwitchCase *FirstCase; SourceLocation SwitchLoc; + +protected: + virtual void DoDestroy(ASTContext &Ctx); + public: SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[BODY] = NULL; } - + /// \brief Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } @@ -635,28 +683,34 @@ public: Stmt *getBody() { return SubExprs[BODY]; } void setBody(Stmt *S) { SubExprs[BODY] = S; } SwitchCase *getSwitchCaseList() { return FirstCase; } + + /// \brief Set the case list for this switch statement. + /// + /// The caller is responsible for incrementing the retain counts on + /// all of the SwitchCase statements in this list. void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } SourceLocation getSwitchLoc() const { return SwitchLoc; } void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } - void setBody(Stmt *S, SourceLocation SL) { - SubExprs[BODY] = S; + void setBody(Stmt *S, SourceLocation SL) { + SubExprs[BODY] = S; SwitchLoc = SL; - } + } void addSwitchCase(SwitchCase *SC) { assert(!SC->getNextSwitchCase() && "case/default already added to a switch"); + SC->Retain(); SC->setNextSwitchCase(FirstCase); FirstCase = SC; } - virtual SourceRange getSourceRange() const { - return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); + virtual SourceRange getSourceRange() const { + return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == SwitchStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == SwitchStmtClass; } static bool classof(const SwitchStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -675,7 +729,7 @@ public: SubExprs[BODY] = body; WhileLoc = WL; } - + /// \brief Build an empty while statement. explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } @@ -689,14 +743,14 @@ public: SourceLocation getWhileLoc() const { return WhileLoc; } void setWhileLoc(SourceLocation L) { WhileLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); + virtual SourceRange getSourceRange() const { + return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == WhileStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == WhileStmtClass; } static bool classof(const WhileStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -717,16 +771,16 @@ public: : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) { SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[BODY] = body; - } + } /// \brief Build an empty do-while statement. explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } - + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } Stmt *getBody() { return SubExprs[BODY]; } - const Stmt *getBody() const { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } void setBody(Stmt *S) { SubExprs[BODY] = S; } SourceLocation getDoLoc() const { return DoLoc; } @@ -737,11 +791,11 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(DoLoc, RParenLoc); + virtual SourceRange getSourceRange() const { + return SourceRange(DoLoc, RParenLoc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == DoStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == DoStmtClass; } static bool classof(const DoStmt *) { return true; } @@ -763,7 +817,7 @@ class ForStmt : public Stmt { public: ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL, - SourceLocation LP, SourceLocation RP) + SourceLocation LP, SourceLocation RP) : Stmt(ForStmtClass) { SubExprs[INIT] = Init; SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); @@ -773,7 +827,7 @@ public: LParenLoc = LP; RParenLoc = RP; } - + /// \brief Build an empty for statement. explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } @@ -799,19 +853,19 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + virtual SourceRange getSourceRange() const { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ForStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ForStmtClass; } static bool classof(const ForStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + /// GotoStmt - This represents a direct goto. /// class GotoStmt : public Stmt { @@ -819,9 +873,9 @@ class GotoStmt : public Stmt { SourceLocation GotoLoc; SourceLocation LabelLoc; public: - GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) + GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} - + /// \brief Build an empty goto statement. explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } @@ -833,14 +887,14 @@ public: SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(GotoLoc, LabelLoc); + virtual SourceRange getSourceRange() const { + return SourceRange(GotoLoc, LabelLoc); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == GotoStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == GotoStmtClass; } static bool classof(const GotoStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -853,20 +907,20 @@ class IndirectGotoStmt : public Stmt { SourceLocation StarLoc; Stmt *Target; public: - IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, Expr *target) : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), Target((Stmt*)target) {} /// \brief Build an empty indirect goto statement. - explicit IndirectGotoStmt(EmptyShell Empty) + explicit IndirectGotoStmt(EmptyShell Empty) : Stmt(IndirectGotoStmtClass, Empty) { } - + void setGotoLoc(SourceLocation L) { GotoLoc = L; } SourceLocation getGotoLoc() const { return GotoLoc; } void setStarLoc(SourceLocation L) { StarLoc = L; } SourceLocation getStarLoc() const { return StarLoc; } - + Expr *getTarget(); const Expr *getTarget() const; void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } @@ -874,12 +928,12 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(GotoLoc, Target->getLocEnd()); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == IndirectGotoStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IndirectGotoStmtClass; } static bool classof(const IndirectGotoStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -892,24 +946,22 @@ class ContinueStmt : public Stmt { SourceLocation ContinueLoc; public: ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} - + /// \brief Build an empty continue statement. explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } SourceLocation getContinueLoc() const { return ContinueLoc; } void setContinueLoc(SourceLocation L) { ContinueLoc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(ContinueLoc); + virtual SourceRange getSourceRange() const { + return SourceRange(ContinueLoc); } - ContinueStmt* Clone(ASTContext &C) const; - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ContinueStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ContinueStmtClass; } static bool classof(const ContinueStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -921,7 +973,7 @@ class BreakStmt : public Stmt { SourceLocation BreakLoc; public: BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {} - + /// \brief Build an empty break statement. explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } @@ -930,13 +982,11 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); } - BreakStmt* Clone(ASTContext &C) const; - - static bool classof(const Stmt *T) { - return T->getStmtClass() == BreakStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == BreakStmtClass; } static bool classof(const BreakStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -956,7 +1006,7 @@ class ReturnStmt : public Stmt { Stmt *RetExpr; SourceLocation RetLoc; public: - ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass), + ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL) {} /// \brief Build an empty return expression. @@ -970,12 +1020,12 @@ public: void setReturnLoc(SourceLocation L) { RetLoc = L; } virtual SourceRange getSourceRange() const; - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ReturnStmtClass; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ReturnStmtClass; } static bool classof(const ReturnStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -989,18 +1039,18 @@ class AsmStmt : public Stmt { bool IsSimple; bool IsVolatile; - + unsigned NumOutputs; unsigned NumInputs; - + llvm::SmallVector<std::string, 4> Names; llvm::SmallVector<StringLiteral*, 4> Constraints; llvm::SmallVector<Stmt*, 4> Exprs; llvm::SmallVector<StringLiteral*, 4> Clobbers; public: - AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, - unsigned numoutputs, unsigned numinputs, + AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, + unsigned numoutputs, unsigned numinputs, std::string *names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc); @@ -1043,10 +1093,10 @@ public: : MyKind(Operand), Str(), OperandNo(OpNo) { Str += Modifier; } - + bool isString() const { return MyKind == String; } bool isOperand() const { return MyKind == Operand; } - + const std::string &getString() const { assert(isString()); return Str; @@ -1056,7 +1106,7 @@ public: assert(isOperand()); return OperandNo; } - + /// getModifier - Get the modifier for this operand, if present. This /// returns '\0' if there was no modifier. char getModifier() const { @@ -1064,16 +1114,16 @@ public: return Str[0]; } }; - + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. This handles canonicalization and /// translation of strings from GCC syntax to LLVM IR syntax, and handles - //// flattening of named references like %[foo] to Operand AsmStringPiece's. + //// flattening of named references like %[foo] to Operand AsmStringPiece's. unsigned AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece> &Pieces, ASTContext &C, unsigned &DiagOffs) const; - - + + //===--- Output operands ---===// unsigned getNumOutputs() const { return NumOutputs; } @@ -1086,72 +1136,72 @@ public: /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). std::string getOutputConstraint(unsigned i) const; - + const StringLiteral *getOutputConstraintLiteral(unsigned i) const { return Constraints[i]; } StringLiteral *getOutputConstraintLiteral(unsigned i) { return Constraints[i]; } - - + + Expr *getOutputExpr(unsigned i); - + const Expr *getOutputExpr(unsigned i) const { return const_cast<AsmStmt*>(this)->getOutputExpr(i); } - + /// isOutputPlusConstraint - Return true if the specified output constraint /// is a "+" constraint (which is both an input and an output) or false if it /// is an "=" constraint (just an output). bool isOutputPlusConstraint(unsigned i) const { return getOutputConstraint(i)[0] == '+'; } - + /// getNumPlusOperands - Return the number of output operands that have a "+" /// constraint. unsigned getNumPlusOperands() const; - + //===--- Input operands ---===// - - unsigned getNumInputs() const { return NumInputs; } - + + unsigned getNumInputs() const { return NumInputs; } + const std::string &getInputName(unsigned i) const { return Names[i + NumOutputs]; } - + /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. std::string getInputConstraint(unsigned i) const; - + const StringLiteral *getInputConstraintLiteral(unsigned i) const { return Constraints[i + NumOutputs]; } StringLiteral *getInputConstraintLiteral(unsigned i) { return Constraints[i + NumOutputs]; } - - + + Expr *getInputExpr(unsigned i); - + const Expr *getInputExpr(unsigned i) const { return const_cast<AsmStmt*>(this)->getInputExpr(i); } void setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, + unsigned NumInputs, const std::string *Names, StringLiteral **Constraints, Stmt **Exprs); //===--- Other ---===// - + /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. int getNamedOperand(const std::string &SymbolicName) const; - + unsigned getNumClobbers() const { return Clobbers.size(); } StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } @@ -1161,62 +1211,62 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(AsmLoc, RParenLoc); } - + static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;} static bool classof(const AsmStmt *) { return true; } - + // Input expr iterators. - + typedef ExprIterator inputs_iterator; typedef ConstExprIterator const_inputs_iterator; - + inputs_iterator begin_inputs() { return Exprs.data() + NumOutputs; } - + inputs_iterator end_inputs() { return Exprs.data() + NumOutputs + NumInputs; } - + const_inputs_iterator begin_inputs() const { return Exprs.data() + NumOutputs; } - + const_inputs_iterator end_inputs() const { return Exprs.data() + NumOutputs + NumInputs; } - + // Output expr iterators. - + typedef ExprIterator outputs_iterator; typedef ConstExprIterator const_outputs_iterator; - + outputs_iterator begin_outputs() { return Exprs.data(); } outputs_iterator end_outputs() { return Exprs.data() + NumOutputs; } - + const_outputs_iterator begin_outputs() const { return Exprs.data(); } const_outputs_iterator end_outputs() const { return Exprs.data() + NumOutputs; } - + // Input name iterator. - + const std::string *begin_output_names() const { return &Names[0]; } - + const std::string *end_output_names() const { return &Names[0] + NumOutputs; } - - // Child iterators - + + // Child iterators + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 2338f1457a84..28fe348c4591 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -29,13 +29,14 @@ class CXXCatchStmt : public Stmt { /// The handler block. Stmt *HandlerBlock; +protected: + virtual void DoDestroy(ASTContext& Ctx); + public: CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), HandlerBlock(handlerBlock) {} - virtual void Destroy(ASTContext& Ctx); - virtual SourceRange getSourceRange() const { return SourceRange(CatchLoc, HandlerBlock->getLocEnd()); } diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h index 1bfac6a9587e..25d015287b75 100644 --- a/include/clang/AST/StmtGraphTraits.h +++ b/include/clang/AST/StmtGraphTraits.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a template specialization of llvm::GraphTraits to +// This file defines a template specialization of llvm::GraphTraits to // treat ASTs (Stmt*) as graphs // //===----------------------------------------------------------------------===// @@ -20,7 +20,7 @@ #include "llvm/ADT/DepthFirstIterator.h" namespace llvm { - + //template <typename T> struct GraphTraits; @@ -28,23 +28,23 @@ template <> struct GraphTraits<clang::Stmt*> { typedef clang::Stmt NodeType; typedef clang::Stmt::child_iterator ChildIteratorType; typedef llvm::df_iterator<clang::Stmt*> nodes_iterator; - + static NodeType* getEntryNode(clang::Stmt* S) { return S; } - + static inline ChildIteratorType child_begin(NodeType* N) { if (N) return N->child_begin(); else return ChildIteratorType(); } - + static inline ChildIteratorType child_end(NodeType* N) { if (N) return N->child_end(); else return ChildIteratorType(); } - + static nodes_iterator nodes_begin(clang::Stmt* S) { return df_begin(S); } - + static nodes_iterator nodes_end(clang::Stmt* S) { return df_end(S); } @@ -55,29 +55,29 @@ template <> struct GraphTraits<const clang::Stmt*> { typedef const clang::Stmt NodeType; typedef clang::Stmt::const_child_iterator ChildIteratorType; typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator; - + static NodeType* getEntryNode(const clang::Stmt* S) { return S; } - + static inline ChildIteratorType child_begin(NodeType* N) { if (N) return N->child_begin(); - else return ChildIteratorType(); + else return ChildIteratorType(); } - + static inline ChildIteratorType child_end(NodeType* N) { if (N) return N->child_end(); else return ChildIteratorType(); } - + static nodes_iterator nodes_begin(const clang::Stmt* S) { return df_begin(S); } - + static nodes_iterator nodes_end(const clang::Stmt* S) { return df_end(S); } }; - + } // end namespace llvm #endif diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index 35bd5ada0256..2d523fffce74 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -14,54 +14,54 @@ #ifndef LLVM_CLANG_AST_STMT_ITR_H #define LLVM_CLANG_AST_STMT_ITR_H -#include "llvm/ADT/iterator.h" #include "llvm/Support/DataTypes.h" #include <cassert> +#include <iterator> namespace clang { class Stmt; class Decl; class VariableArrayType; - + class StmtIteratorBase { protected: enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3, Flags = 0x3 }; - + union { Stmt** stmt; Decl* decl; Decl** DGI; }; - uintptr_t RawVAPtr; + uintptr_t RawVAPtr; Decl** DGE; bool inDecl() const { return (RawVAPtr & Flags) == DeclMode; } - + bool inDeclGroup() const { return (RawVAPtr & Flags) == DeclGroupMode; } - - bool inSizeOfTypeVA() const { + + bool inSizeOfTypeVA() const { return (RawVAPtr & Flags) == SizeOfTypeVAMode; } - + bool inStmt() const { return (RawVAPtr & Flags) == 0; } - + VariableArrayType* getVAPtr() const { return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags); } - + void setVAPtr(VariableArrayType* P) { - assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); + assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); } - + void NextDecl(bool ImmediateAdvance = true); bool HandleDecl(Decl* D); void NextVA(); - + Stmt*& GetDeclExpr() const; StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {} @@ -70,22 +70,22 @@ protected: StmtIteratorBase(Decl** dgi, Decl** dge); StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {} }; - - + + template <typename DERIVED, typename REFERENCE> -class StmtIteratorImpl : public StmtIteratorBase, +class StmtIteratorImpl : public StmtIteratorBase, public std::iterator<std::forward_iterator_tag, - REFERENCE, ptrdiff_t, - REFERENCE, REFERENCE> { + REFERENCE, ptrdiff_t, + REFERENCE, REFERENCE> { protected: StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {} public: - StmtIteratorImpl() {} + StmtIteratorImpl() {} StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {} StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {} StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {} StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {} - + DERIVED& operator++() { if (inDecl() || inDeclGroup()) { if (getVAPtr()) NextVA(); @@ -95,36 +95,36 @@ public: NextVA(); else ++stmt; - + return static_cast<DERIVED&>(*this); } - + DERIVED operator++(int) { DERIVED tmp = static_cast<DERIVED&>(*this); operator++(); return tmp; } - + bool operator==(const DERIVED& RHS) const { return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr; } - + bool operator!=(const DERIVED& RHS) const { return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr; } - - REFERENCE operator*() const { + + REFERENCE operator*() const { return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr()); } - - REFERENCE operator->() const { return operator*(); } + + REFERENCE operator->() const { return operator*(); } }; struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {} - StmtIterator(Decl** dgi, Decl** dge) + StmtIterator(Decl** dgi, Decl** dge) : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} @@ -133,10 +133,10 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, const Stmt*> { - explicit ConstStmtIterator() : + explicit ConstStmtIterator() : StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {} - - ConstStmtIterator(const StmtIterator& RHS) : + + ConstStmtIterator(const StmtIterator& RHS) : StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} }; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index a95a62731186..8d7e4b5fc0a3 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -25,6 +25,10 @@ # define EXPR(Type, Base) STMT(Type, Base) #endif +#ifndef ABSTRACT_EXPR +# define ABSTRACT_EXPR(Type, Base) EXPR(Type, Base) +#endif + // Normal Statements. STMT(NullStmt , Stmt) FIRST_STMT(NullStmt) @@ -64,7 +68,7 @@ STMT(CXXTryStmt , Stmt) LAST_STMT(CXXTryStmt) // Expressions. -EXPR(Expr , Stmt) +ABSTRACT_EXPR(Expr , Stmt) FIRST_EXPR(Expr) EXPR(PredefinedExpr , Expr) EXPR(DeclRefExpr , Expr) @@ -91,6 +95,7 @@ EXPR(ExtVectorElementExpr , Expr) EXPR(InitListExpr , Expr) EXPR(DesignatedInitExpr , Expr) EXPR(ImplicitValueInitExpr , Expr) +EXPR(ParenListExpr , Expr) EXPR(VAArgExpr , Expr) // GNU Extensions. @@ -119,6 +124,7 @@ EXPR(CXXZeroInitValueExpr , Expr) EXPR(CXXConditionDeclExpr , DeclRefExpr) EXPR(CXXNewExpr , Expr) EXPR(CXXDeleteExpr , Expr) +EXPR(CXXPseudoDestructorExpr, Expr) EXPR(UnresolvedFunctionNameExpr , Expr) EXPR(UnaryTypeTraitExpr , Expr) EXPR(QualifiedDeclRefExpr , DeclRefExpr) @@ -139,8 +145,9 @@ EXPR(ObjCSelectorExpr , Expr) EXPR(ObjCProtocolExpr , Expr) EXPR(ObjCIvarRefExpr , Expr) EXPR(ObjCPropertyRefExpr , Expr) -EXPR(ObjCKVCRefExpr , Expr) +EXPR(ObjCImplicitSetterGetterRefExpr , Expr) EXPR(ObjCSuperExpr , Expr) +EXPR(ObjCIsaExpr , Expr) // Clang Extensions. EXPR(ShuffleVectorExpr , Expr) @@ -149,8 +156,9 @@ EXPR(BlockDeclRefExpr , Expr) LAST_EXPR(BlockDeclRefExpr) -#undef STMT +#undef ABSTRACT_EXPR #undef EXPR +#undef STMT #undef FIRST_STMT #undef LAST_STMT #undef FIRST_EXPR diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h index 8ae707174403..3fd8f1672deb 100644 --- a/include/clang/AST/StmtObjC.h +++ b/include/clang/AST/StmtObjC.h @@ -27,47 +27,47 @@ class ObjCForCollectionStmt : public Stmt { SourceLocation ForLoc; SourceLocation RParenLoc; public: - ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, + ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, SourceLocation FCL, SourceLocation RPL); - explicit ObjCForCollectionStmt(EmptyShell Empty) : + explicit ObjCForCollectionStmt(EmptyShell Empty) : Stmt(ObjCForCollectionStmtClass, Empty) { } - + Stmt *getElement() { return SubExprs[ELEM]; } - Expr *getCollection() { - return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + Expr *getCollection() { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); } Stmt *getBody() { return SubExprs[BODY]; } - + const Stmt *getElement() const { return SubExprs[ELEM]; } - const Expr *getCollection() const { + const Expr *getCollection() const { return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); } const Stmt *getBody() const { return SubExprs[BODY]; } - + void setElement(Stmt *S) { SubExprs[ELEM] = S; } - void setCollection(Expr *E) { + void setCollection(Expr *E) { SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E); } void setBody(Stmt *S) { SubExprs[BODY] = S; } - + SourceLocation getForLoc() const { return ForLoc; } void setForLoc(SourceLocation Loc) { ForLoc = Loc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - - virtual SourceRange getSourceRange() const { - return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + + virtual SourceRange getSourceRange() const { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCForCollectionStmtClass; + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCForCollectionStmtClass; } static bool classof(const ObjCForCollectionStmt *) { return true; } - + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); -}; - +}; + /// ObjCAtCatchStmt - This represents objective-c's @catch statement. class ObjCAtCatchStmt : public Stmt { private: @@ -78,95 +78,95 @@ private: public: ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, - ParmVarDecl *catchVarDecl, + ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, Stmt *atCatchList); - explicit ObjCAtCatchStmt(EmptyShell Empty) : + explicit ObjCAtCatchStmt(EmptyShell Empty) : Stmt(ObjCAtCatchStmtClass, Empty) { } - + const Stmt *getCatchBody() const { return SubExprs[BODY]; } Stmt *getCatchBody() { return SubExprs[BODY]; } void setCatchBody(Stmt *S) { SubExprs[BODY] = S; } - + const ObjCAtCatchStmt *getNextCatchStmt() const { return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]); } - ObjCAtCatchStmt *getNextCatchStmt() { + ObjCAtCatchStmt *getNextCatchStmt() { return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]); } void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; } - - const ParmVarDecl *getCatchParamDecl() const { - return ExceptionDecl; + + const ParmVarDecl *getCatchParamDecl() const { + return ExceptionDecl; } - ParmVarDecl *getCatchParamDecl() { - return ExceptionDecl; + ParmVarDecl *getCatchParamDecl() { + return ExceptionDecl; } void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; } - + SourceLocation getAtCatchLoc() const { return AtCatchLoc; } void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - - virtual SourceRange getSourceRange() const { - return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd()); + + virtual SourceRange getSourceRange() const { + return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd()); } bool hasEllipsis() const { return getCatchParamDecl() == 0; } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtCatchStmtClass; } static bool classof(const ObjCAtCatchStmt *) { return true; } - + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - -/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement + +/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement class ObjCAtFinallyStmt : public Stmt { Stmt *AtFinallyStmt; - SourceLocation AtFinallyLoc; + SourceLocation AtFinallyLoc; public: ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt) - : Stmt(ObjCAtFinallyStmtClass), + : Stmt(ObjCAtFinallyStmtClass), AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {} - explicit ObjCAtFinallyStmt(EmptyShell Empty) : + explicit ObjCAtFinallyStmt(EmptyShell Empty) : Stmt(ObjCAtFinallyStmtClass, Empty) { } - + const Stmt *getFinallyBody() const { return AtFinallyStmt; } Stmt *getFinallyBody() { return AtFinallyStmt; } void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } - - virtual SourceRange getSourceRange() const { - return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); + + virtual SourceRange getSourceRange() const { + return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); } - + SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtFinallyStmtClass; } static bool classof(const ObjCAtFinallyStmt *) { return true; } - + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - -/// ObjCAtTryStmt - This represent objective-c's over-all + +/// ObjCAtTryStmt - This represent objective-c's over-all /// @try ... @catch ... @finally statement. class ObjCAtTryStmt : public Stmt { private: enum { TRY, CATCH, FINALLY, END_EXPR }; - Stmt* SubStmts[END_EXPR]; - - SourceLocation AtTryLoc; + Stmt* SubStmts[END_EXPR]; + + SourceLocation AtTryLoc; public: - ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, - Stmt *atCatchStmt, + ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt *atCatchStmt, Stmt *atFinallyStmt) : Stmt(ObjCAtTryStmtClass) { SubStmts[TRY] = atTryStmt; @@ -174,41 +174,41 @@ public: SubStmts[FINALLY] = atFinallyStmt; AtTryLoc = atTryLoc; } - explicit ObjCAtTryStmt(EmptyShell Empty) : + explicit ObjCAtTryStmt(EmptyShell Empty) : Stmt(ObjCAtTryStmtClass, Empty) { } - + SourceLocation getAtTryLoc() const { return AtTryLoc; } void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } - + const Stmt *getTryBody() const { return SubStmts[TRY]; } Stmt *getTryBody() { return SubStmts[TRY]; } void setTryBody(Stmt *S) { SubStmts[TRY] = S; } - - const ObjCAtCatchStmt *getCatchStmts() const { - return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); + + const ObjCAtCatchStmt *getCatchStmts() const { + return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); } - ObjCAtCatchStmt *getCatchStmts() { - return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); + ObjCAtCatchStmt *getCatchStmts() { + return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); } void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; } - - const ObjCAtFinallyStmt *getFinallyStmt() const { - return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); + + const ObjCAtFinallyStmt *getFinallyStmt() const { + return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); } - ObjCAtFinallyStmt *getFinallyStmt() { - return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); + ObjCAtFinallyStmt *getFinallyStmt() { + return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); } void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; } - virtual SourceRange getSourceRange() const { - return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd()); + virtual SourceRange getSourceRange() const { + return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd()); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtTryStmtClass; } static bool classof(const ObjCAtTryStmt *) { return true; } - + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; @@ -223,7 +223,7 @@ private: enum { SYNC_EXPR, SYNC_BODY, END_EXPR }; Stmt* SubStmts[END_EXPR]; SourceLocation AtSynchronizedLoc; - + public: ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, Stmt *synchBody) @@ -232,41 +232,41 @@ public: SubStmts[SYNC_BODY] = synchBody; AtSynchronizedLoc = atSynchronizedLoc; } - explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : + explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : Stmt(ObjCAtSynchronizedStmtClass, Empty) { } - + SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; } - + const CompoundStmt *getSynchBody() const { return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); } - CompoundStmt *getSynchBody() { - return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + CompoundStmt *getSynchBody() { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); } void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } - - const Expr *getSynchExpr() const { - return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + + const Expr *getSynchExpr() const { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); } - Expr *getSynchExpr() { - return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + Expr *getSynchExpr() { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); } void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } - - virtual SourceRange getSourceRange() const { - return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd()); + + virtual SourceRange getSourceRange() const { + return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd()); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtSynchronizedStmtClass; } static bool classof(const ObjCAtSynchronizedStmt *) { return true; } - + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; - + /// ObjCAtThrowStmt - This represents objective-c's @throw statement. class ObjCAtThrowStmt : public Stmt { Stmt *Throw; @@ -276,28 +276,28 @@ public: : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) { AtThrowLoc = atThrowLoc; } - explicit ObjCAtThrowStmt(EmptyShell Empty) : + explicit ObjCAtThrowStmt(EmptyShell Empty) : Stmt(ObjCAtThrowStmtClass, Empty) { } - + const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); } Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } void setThrowExpr(Stmt *S) { Throw = S; } - + SourceLocation getThrowLoc() { return AtThrowLoc; } void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } - + virtual SourceRange getSourceRange() const { if (Throw) - return SourceRange(AtThrowLoc, Throw->getLocEnd()); - else + return SourceRange(AtThrowLoc, Throw->getLocEnd()); + else return SourceRange(AtThrowLoc); } - + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtThrowStmtClass; } static bool classof(const ObjCAtThrowStmt *) { return true; } - + virtual child_iterator child_begin(); virtual child_iterator child_end(); }; diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 4f4066ab8602..3a525507dad3 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -20,17 +20,17 @@ #include "clang/AST/StmtObjC.h" namespace clang { - + #define DISPATCH(NAME, CLASS) \ return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S)) - + /// StmtVisitor - This class implements a simple visitor for Stmt subclasses. /// Since Expr derives from Stmt, this also includes support for visiting Exprs. template<typename ImplClass, typename RetTy=void> class StmtVisitor { public: RetTy Visit(Stmt *S) { - + // If we have a binary expr, dispatch to the subcode of the binop. A smart // optimizer (e.g. LLVM) will fold this comparison into the switch stmt // below. @@ -53,7 +53,7 @@ public: case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator); case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator); case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator); - + case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator); case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator); case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator); @@ -101,7 +101,7 @@ public: case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator); } } - + // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. switch (S->getStmtClass()) { default: assert(0 && "Unknown stmt kind!"); @@ -110,7 +110,7 @@ public: #include "clang/AST/StmtNodes.def" } } - + // If the implementation chooses not to implement a certain visit method, fall // back on VisitExpr or whatever else is the superclass. #define STMT(CLASS, PARENT) \ @@ -127,7 +127,7 @@ public: BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) BINOP_FALLBACK(Shr) - + BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) @@ -148,7 +148,7 @@ public: CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign) CAO_FALLBACK(XorAssign) #undef CAO_FALLBACK - + // If the implementation doesn't implement unary operator methods, fall back // on VisitUnaryOperator. #define UNARYOP_FALLBACK(NAME) \ @@ -158,13 +158,13 @@ public: UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec) UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref) - + UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf) #undef UNARYOP_FALLBACK - + // Base case, ignore it. :) RetTy VisitStmt(Stmt *Node) { return RetTy(); } }; diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 511934c1dbf5..66ff34cf1e31 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -26,9 +26,11 @@ namespace clang { class DependentTemplateName; class IdentifierInfo; class NestedNameSpecifier; -class PrintingPolicy; +struct PrintingPolicy; class QualifiedTemplateName; +class NamedDecl; class TemplateDecl; +class OverloadedFunctionDecl; /// \brief Represents a C++ template name within the type system. /// @@ -58,7 +60,8 @@ class TemplateDecl; /// specifier in the typedef. "apply" is a nested template, and can /// only be understood in the context of class TemplateName { - typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *, + typedef llvm::PointerUnion4<TemplateDecl *, OverloadedFunctionDecl *, + QualifiedTemplateName *, DependentTemplateName *> StorageType; StorageType Storage; @@ -70,17 +73,32 @@ class TemplateName { public: TemplateName() : Storage() { } explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } + explicit TemplateName(OverloadedFunctionDecl *FunctionTemplates) + : Storage(FunctionTemplates) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } + /// \brief Determine whether this template name is NULL. + bool isNull() const { return Storage.isNull(); } + /// \brief Retrieve the the underlying template declaration that /// this template name refers to, if known. /// /// \returns The template declaration that this template name refers /// to, if any. If the template name does not refer to a specific - /// declaration because it is a dependent name, returns NULL. + /// declaration because it is a dependent name, or if it refers to a + /// set of function templates, returns NULL. TemplateDecl *getAsTemplateDecl() const; + /// \brief Retrieve the the underlying, overloaded function template + // declarations that this template name refers to, if known. + /// + /// \returns The set of overloaded function templates that this template + /// name refers to, if known. If the template name does not refer to a + /// specific set of function templates because it is a dependent name or + /// refers to a single template, returns NULL. + OverloadedFunctionDecl *getAsOverloadedFunctionDecl() const; + /// \brief Retrieve the underlying qualified template name /// structure, if any. QualifiedTemplateName *getAsQualifiedTemplateName() const { @@ -119,8 +137,8 @@ public: void *getAsVoidPointer() const { return Storage.getOpaqueValue(); } /// \brief Build a template name from a void pointer. - static TemplateName getFromVoidPointer(void *Ptr) { - return TemplateName(Ptr); + static TemplateName getFromVoidPointer(void *Ptr) { + return TemplateName(Ptr); } }; @@ -145,15 +163,21 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// this name with DependentTemplateName). llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; - /// \brief The template declaration that this qualified name refers - /// to. - TemplateDecl *Template; + /// \brief The template declaration or set of overloaded function templates + /// that this qualified name refers to. + NamedDecl *Template; friend class ASTContext; QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) - : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { } + : Qualifier(NNS, TemplateKeyword? 1 : 0), + Template(reinterpret_cast<NamedDecl *>(Template)) { } + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + OverloadedFunctionDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), + Template(reinterpret_cast<NamedDecl *>(Template)) { } public: /// \brief Return the nested name specifier that qualifies this name. @@ -163,16 +187,26 @@ public: /// keyword. bool hasTemplateKeyword() const { return Qualifier.getInt(); } + /// \brief The template declaration or set of overloaded functions that + /// that qualified name refers to. + NamedDecl *getDecl() const { return Template; } + /// \brief The template declaration to which this qualified name - /// refers. - TemplateDecl *getTemplateDecl() const { return Template; } + /// refers, or NULL if this qualified name refers to a set of overloaded + /// function templates. + TemplateDecl *getTemplateDecl() const; + + /// \brief The set of overloaded function tempaltes to which this qualified + /// name refers, or NULL if this qualified name refers to a single + /// template declaration. + OverloadedFunctionDecl *getOverloadedFunctionDecl() const; void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + Profile(ID, getQualifier(), hasTemplateKeyword(), getDecl()); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, - bool TemplateKeyword, TemplateDecl *Template) { + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + bool TemplateKeyword, NamedDecl *Template) { ID.AddPointer(NNS); ID.AddBoolean(TemplateKeyword); ID.AddPointer(Template); @@ -183,7 +217,7 @@ public: /// resolved prior to template instantiation. /// /// This kind of template name refers to a dependent template name, -/// including its nested name specifier. For example, +/// including its nested name specifier (if any). For example, /// DependentTemplateName can refer to "MetaFun::template apply", /// where "MetaFun::" is the nested name specifier and "apply" is the /// template name referenced. The "template" keyword is implied. @@ -205,11 +239,11 @@ class DependentTemplateName : public llvm::FoldingSetNode { friend class ASTContext; - DependentTemplateName(NestedNameSpecifier *Qualifier, + DependentTemplateName(NestedNameSpecifier *Qualifier, const IdentifierInfo *Name) : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { } - DependentTemplateName(NestedNameSpecifier *Qualifier, + DependentTemplateName(NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, TemplateName Canon) : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { } @@ -226,7 +260,7 @@ public: Profile(ID, getQualifier(), getName()); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, const IdentifierInfo *Name) { ID.AddPointer(NNS); ID.AddPointer(Name); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index a00c0c4ff1c4..89776b91fe4a 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -19,6 +19,7 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/type_traits.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" @@ -29,7 +30,13 @@ using llvm::cast; using llvm::cast_or_null; using llvm::dyn_cast; using llvm::dyn_cast_or_null; -namespace clang { class Type; } +namespace clang { + enum { + TypeAlignmentInBits = 3, + TypeAlignment = 1 << TypeAlignmentInBits + }; + class Type; class ExtQuals; +} namespace llvm { template <typename T> @@ -41,7 +48,16 @@ namespace llvm { static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); } - enum { NumLowBitsAvailable = 3 }; + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; + }; + template<> + class PointerLikeTypeTraits< ::clang::ExtQuals*> { + public: + static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } + static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { + return static_cast< ::clang::ExtQuals*>(P); + } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; } @@ -66,54 +82,359 @@ namespace clang { class StmtIteratorBase; class TemplateArgument; class QualifiedNameType; - class PrintingPolicy; + struct PrintingPolicy; // Provide forward declarations for all of the *Type classes #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" -/// QualType - For efficiency, we don't store CVR-qualified types as nodes on -/// their own: instead each reference to a type stores the qualifiers. This -/// greatly reduces the number of nodes we need to allocate for types (for -/// example we only need one for 'int', 'const int', 'volatile int', -/// 'const volatile int', etc). -/// -/// As an added efficiency bonus, instead of making this a pair, we just store -/// the three bits we care about in the low bits of the pointer. To handle the -/// packing/unpacking, we make QualType be a simple wrapper class that acts like -/// a smart pointer. -class QualType { - llvm::PointerIntPair<Type*, 3> Value; +/// Qualifiers - The collection of all-type qualifiers we support. +/// Clang supports five independent qualifiers: +/// * C99: const, volatile, and restrict +/// * Embedded C (TR18037): address spaces +/// * Objective C: the GC attributes (none, weak, or strong) +class Qualifiers { public: - enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. + enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, Restrict = 0x2, Volatile = 0x4, - CVRFlags = Const|Restrict|Volatile + CVRMask = Const | Volatile | Restrict }; - - enum GCAttrTypes { + + enum GC { GCNone = 0, Weak, Strong }; - + + enum { + /// The maximum supported address space number. + /// 24 bits should be enough for anyone. + MaxAddressSpace = 0xffffffu, + + /// The width of the "fast" qualifier mask. + FastWidth = 2, + + /// The fast qualifier mask. + FastMask = (1 << FastWidth) - 1 + }; + + Qualifiers() : Mask(0) {} + + static Qualifiers fromFastMask(unsigned Mask) { + Qualifiers Qs; + Qs.addFastQualifiers(Mask); + return Qs; + } + + static Qualifiers fromCVRMask(unsigned CVR) { + Qualifiers Qs; + Qs.addCVRQualifiers(CVR); + return Qs; + } + + // Deserialize qualifiers from an opaque representation. + static Qualifiers fromOpaqueValue(unsigned opaque) { + Qualifiers Qs; + Qs.Mask = opaque; + return Qs; + } + + // Serialize these qualifiers into an opaque representation. + unsigned getAsOpaqueValue() const { + return Mask; + } + + bool hasConst() const { return Mask & Const; } + void setConst(bool flag) { + Mask = (Mask & ~Const) | (flag ? Const : 0); + } + void removeConst() { Mask &= ~Const; } + void addConst() { Mask |= Const; } + + bool hasVolatile() const { return Mask & Volatile; } + void setVolatile(bool flag) { + Mask = (Mask & ~Volatile) | (flag ? Volatile : 0); + } + void removeVolatile() { Mask &= ~Volatile; } + void addVolatile() { Mask |= Volatile; } + + bool hasRestrict() const { return Mask & Restrict; } + void setRestrict(bool flag) { + Mask = (Mask & ~Restrict) | (flag ? Restrict : 0); + } + void removeRestrict() { Mask &= ~Restrict; } + void addRestrict() { Mask |= Restrict; } + + bool hasCVRQualifiers() const { return getCVRQualifiers(); } + unsigned getCVRQualifiers() const { return Mask & CVRMask; } + void setCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask = (Mask & ~CVRMask) | mask; + } + void removeCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask &= ~mask; + } + void removeCVRQualifiers() { + removeCVRQualifiers(CVRMask); + } + void addCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask |= mask; + } + + bool hasObjCGCAttr() const { return Mask & GCAttrMask; } + GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } + void setObjCGCAttr(GC type) { + Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); + } + void removeObjCGCAttr() { setObjCGCAttr(GCNone); } + void addObjCGCAttr(GC type) { + assert(type); + setObjCGCAttr(type); + } + + bool hasAddressSpace() const { return Mask & AddressSpaceMask; } + unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } + void setAddressSpace(unsigned space) { + assert(space <= MaxAddressSpace); + Mask = (Mask & ~AddressSpaceMask) + | (((uint32_t) space) << AddressSpaceShift); + } + void removeAddressSpace() { setAddressSpace(0); } + void addAddressSpace(unsigned space) { + assert(space); + setAddressSpace(space); + } + + // Fast qualifiers are those that can be allocated directly + // on a QualType object. + bool hasFastQualifiers() const { return getFastQualifiers(); } + unsigned getFastQualifiers() const { return Mask & FastMask; } + void setFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask = (Mask & ~FastMask) | mask; + } + void removeFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask &= ~mask; + } + void removeFastQualifiers() { + removeFastQualifiers(FastMask); + } + void addFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask |= mask; + } + + /// hasNonFastQualifiers - Return true if the set contains any + /// qualifiers which require an ExtQuals node to be allocated. + bool hasNonFastQualifiers() const { return Mask & ~FastMask; } + Qualifiers getNonFastQualifiers() const { + Qualifiers Quals = *this; + Quals.setFastQualifiers(0); + return Quals; + } + + /// hasQualifiers - Return true if the set contains any qualifiers. + bool hasQualifiers() const { return Mask; } + bool empty() const { return !Mask; } + + /// \brief Add the qualifiers from the given set to this set. + void addQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-or it in. + if (!(Q.Mask & ~CVRMask)) + Mask |= Q.Mask; + else { + Mask |= (Q.Mask & CVRMask); + if (Q.hasAddressSpace()) + addAddressSpace(Q.getAddressSpace()); + if (Q.hasObjCGCAttr()) + addObjCGCAttr(Q.getObjCGCAttr()); + } + } + + bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } + bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } + + operator bool() const { return hasQualifiers(); } + + Qualifiers &operator+=(Qualifiers R) { + addQualifiers(R); + return *this; + } + + // Union two qualifier sets. If an enumerated qualifier appears + // in both sets, use the one from the right. + friend Qualifiers operator+(Qualifiers L, Qualifiers R) { + L += R; + return L; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const { + std::string Buffer; + getAsStringInternal(Buffer, Policy); + return Buffer; + } + void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Mask); + } + +private: + + // bits: |0 1 2|3 .. 4|5 .. 31| + // |C R V|GCAttr|AddrSpace| + uint32_t Mask; + + static const uint32_t GCAttrMask = 0x18; + static const uint32_t GCAttrShift = 3; + static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask); + static const uint32_t AddressSpaceShift = 5; +}; + + +/// ExtQuals - We can encode up to three bits in the low bits of a +/// type pointer, but there are many more type qualifiers that we want +/// to be able to apply to an arbitrary type. Therefore we have this +/// struct, intended to be heap-allocated and used by QualType to +/// store qualifiers. +/// +/// The current design tags the 'const' and 'restrict' qualifiers in +/// two low bits on the QualType pointer; a third bit records whether +/// the pointer is an ExtQuals node. 'const' was chosen because it is +/// orders of magnitude more common than the other two qualifiers, in +/// both library and user code. It's relatively rare to see +/// 'restrict' in user code, but many standard C headers are saturated +/// with 'restrict' declarations, so that representing them efficiently +/// is a critical goal of this representation. +class ExtQuals : public llvm::FoldingSetNode { + // NOTE: changing the fast qualifiers should be straightforward as + // long as you don't make 'const' non-fast. + // 1. Qualifiers: + // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). + // Fast qualifiers must occupy the low-order bits. + // b) Update Qualifiers::FastWidth and FastMask. + // 2. QualType: + // a) Update is{Volatile,Restrict}Qualified(), defined inline. + // b) Update remove{Volatile,Restrict}, defined near the end of + // this header. + // 3. ASTContext: + // a) Update get{Volatile,Restrict}Type. + + /// Context - the context to which this set belongs. We save this + /// here so that QualifierCollector can use it to reapply extended + /// qualifiers to an arbitrary type without requiring a context to + /// be pushed through every single API dealing with qualifiers. + ASTContext& Context; + + /// BaseType - the underlying type that this qualifies + const Type *BaseType; + + /// Quals - the immutable set of qualifiers applied by this + /// node; always contains extended qualifiers. + Qualifiers Quals; + +public: + ExtQuals(ASTContext& Context, const Type *Base, Qualifiers Quals) + : Context(Context), BaseType(Base), Quals(Quals) + { + assert(Quals.hasNonFastQualifiers() + && "ExtQuals created with no fast qualifiers"); + assert(!Quals.hasFastQualifiers() + && "ExtQuals created with fast qualifiers"); + } + + Qualifiers getQualifiers() const { return Quals; } + + bool hasVolatile() const { return Quals.hasVolatile(); } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + + ASTContext &getContext() const { return Context; } + +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getBaseType(), Quals); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const Type *BaseType, + Qualifiers Quals) { + assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); + ID.AddPointer(BaseType); + Quals.Profile(ID); + } +}; + + +/// QualType - For efficiency, we don't store CV-qualified types as nodes on +/// their own: instead each reference to a type stores the qualifiers. This +/// greatly reduces the number of nodes we need to allocate for types (for +/// example we only need one for 'int', 'const int', 'volatile int', +/// 'const volatile int', etc). +/// +/// As an added efficiency bonus, instead of making this a pair, we +/// just store the two bits we care about in the low bits of the +/// pointer. To handle the packing/unpacking, we make QualType be a +/// simple wrapper class that acts like a smart pointer. A third bit +/// indicates whether there are extended qualifiers present, in which +/// case the pointer points to a special structure. +class QualType { + // Thankfully, these are efficiently composable. + llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>, + Qualifiers::FastWidth> Value; + + bool hasExtQuals() const { + return Value.getPointer().is<const ExtQuals*>(); + } + + const ExtQuals *getExtQualsUnsafe() const { + return Value.getPointer().get<const ExtQuals*>(); + } + + const Type *getTypePtrUnsafe() const { + return Value.getPointer().get<const Type*>(); + } + + friend class QualifierCollector; +public: QualType() {} - + QualType(const Type *Ptr, unsigned Quals) - : Value(const_cast<Type*>(Ptr), Quals) {} + : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + + unsigned getFastQualifiers() const { return Value.getInt(); } + void setFastQualifiers(unsigned Quals) { Value.setInt(Quals); } + + /// Retrieves a pointer to the underlying (unqualified) type. + /// This should really return a const Type, but it's not worth + /// changing all the users right now. + Type *getTypePtr() const { + if (hasNonFastQualifiers()) + return const_cast<Type*>(getExtQualsUnsafe()->getBaseType()); + return const_cast<Type*>(getTypePtrUnsafe()); + } - unsigned getCVRQualifiers() const { return Value.getInt(); } - void setCVRQualifiers(unsigned Quals) { Value.setInt(Quals); } - Type *getTypePtr() const { return Value.getPointer(); } - void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(void *Ptr) { QualType T; T.Value.setFromOpaqueValue(Ptr); return T; } - + Type &operator*() const { return *getTypePtr(); } @@ -121,65 +442,125 @@ public: Type *operator->() const { return getTypePtr(); } - + /// isNull - Return true if this QualType doesn't point to a type yet. bool isNull() const { - return getTypePtr() == 0; + return Value.getPointer().isNull(); } bool isConstQualified() const { - return (getCVRQualifiers() & Const) ? true : false; + return (getFastQualifiers() & Qualifiers::Const); + } + bool isRestrictQualified() const { + return (getFastQualifiers() & Qualifiers::Restrict); } bool isVolatileQualified() const { - return (getCVRQualifiers() & Volatile) ? true : false; + return (hasNonFastQualifiers() && getExtQualsUnsafe()->hasVolatile()); } - bool isRestrictQualified() const { - return (getCVRQualifiers() & Restrict) ? true : false; + + // Determines whether this type has any direct qualifiers. + bool hasQualifiers() const { + return getFastQualifiers() || hasNonFastQualifiers(); + } + + bool hasNonFastQualifiers() const { + return hasExtQuals(); + } + + // Retrieves the set of qualifiers belonging to this type. + Qualifiers getQualifiers() const { + Qualifiers Quals; + if (hasNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getFastQualifiers()); + return Quals; } - bool isConstant(ASTContext& Ctx) const; - - /// addConst/addVolatile/addRestrict - add the specified type qual to this - /// QualType. - void addConst() { Value.setInt(Value.getInt() | Const); } - void addVolatile() { Value.setInt(Value.getInt() | Volatile); } - void addRestrict() { Value.setInt(Value.getInt() | Restrict); } + // Retrieves the CVR qualifiers of this type. + unsigned getCVRQualifiers() const { + unsigned CVR = getFastQualifiers(); + if (isVolatileQualified()) CVR |= Qualifiers::Volatile; + return CVR; + } - void removeConst() { Value.setInt(Value.getInt() & ~Const); } - void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); } - void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); } + bool isConstant(ASTContext& Ctx) const { + return QualType::isConstant(*this, Ctx); + } - QualType getQualifiedType(unsigned TQs) const { - return QualType(getTypePtr(), TQs); + // Don't promise in the API that anything besides 'const' can be + // easily added. + + /// addConst - add the specified type qualifier to this QualType. + void addConst() { + addFastQualifiers(Qualifiers::Const); + } + QualType withConst() const { + return withFastQualifiers(Qualifiers::Const); } - QualType getWithAdditionalQualifiers(unsigned TQs) const { - return QualType(getTypePtr(), TQs|getCVRQualifiers()); + + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } + + void removeConst(); + void removeVolatile(); + void removeRestrict(); + void removeCVRQualifiers(unsigned Mask); + + void removeFastQualifiers() { Value.setInt(0); } + void removeFastQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); + Value.setInt(Value.getInt() & ~Mask); + } + + // Creates a type with the given qualifiers in addition to any + // qualifiers already on this type. + QualType withFastQualifiers(unsigned TQs) const { + QualType T = *this; + T.addFastQualifiers(TQs); + return T; + } + + // Creates a type with exactly the given fast qualifiers, removing + // any existing fast qualifiers. + QualType withExactFastQualifiers(unsigned TQs) const { + return withoutFastQualifiers().withFastQualifiers(TQs); + } + + // Removes fast qualifiers, but leaves any extended qualifiers in place. + QualType withoutFastQualifiers() const { + QualType T = *this; + T.removeFastQualifiers(); + return T; } - QualType withConst() const { return getWithAdditionalQualifiers(Const); } - QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);} - QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);} - - QualType getUnqualifiedType() const; + QualType getUnqualifiedType() const { return QualType(getTypePtr(), 0); } + bool isMoreQualifiedThan(QualType Other) const; bool isAtLeastAsQualifiedAs(QualType Other) const; QualType getNonReferenceType() const; - + /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. - QualType getDesugaredType(bool ForDisplay = false) const; + /// + /// Qualifiers are left in place. + QualType getDesugaredType() const { + return QualType::getDesugaredType(*this); + } /// operator==/!= - Indicate whether the specified types and qualifiers are /// identical. - bool operator==(const QualType &RHS) const { - return Value == RHS.Value; + friend bool operator==(const QualType &LHS, const QualType &RHS) { + return LHS.Value == RHS.Value; } - bool operator!=(const QualType &RHS) const { - return Value != RHS.Value; + friend bool operator!=(const QualType &LHS, const QualType &RHS) { + return LHS.Value != RHS.Value; } std::string getAsString() const; @@ -190,31 +571,40 @@ public: } void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; - + void dump(const char *s) const; void dump() const; - + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(getAsOpaquePtr()); } -public: - /// getAddressSpace - Return the address space of this type. inline unsigned getAddressSpace() const; - + /// GCAttrTypesAttr - Returns gc attribute of this type. - inline QualType::GCAttrTypes getObjCGCAttr() const; + inline Qualifiers::GC getObjCGCAttr() const; /// isObjCGCWeak true when Type is objc's weak. bool isObjCGCWeak() const { - return getObjCGCAttr() == Weak; + return getObjCGCAttr() == Qualifiers::Weak; } /// isObjCGCStrong true when Type is objc's strong. bool isObjCGCStrong() const { - return getObjCGCAttr() == Strong; + return getObjCGCAttr() == Qualifiers::Strong; } + + /// getNoReturnAttr - Returns true if the type has the noreturn attribute, + /// false otherwise. + bool getNoReturnAttr() const; + +private: + // These methods are implemented in a separate translation unit; + // "static"-ize them to avoid creating temporary QualTypes in the + // caller. + static bool isConstant(QualType T, ASTContext& Ctx); + static QualType getDesugaredType(QualType T); }; } // end clang. @@ -230,7 +620,7 @@ template<> struct simplify_type<const ::clang::QualType> { }; template<> struct simplify_type< ::clang::QualType> : public simplify_type<const ::clang::QualType> {}; - + // Teach SmallPtrSet that QualType is "basically a pointer". template<> class PointerLikeTypeTraits<clang::QualType> { @@ -241,9 +631,10 @@ public: static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } - // CVR qualifiers go in low bits. + // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; + } // end namespace llvm namespace clang { @@ -281,7 +672,10 @@ public: #include "clang/AST/TypeNodes.def" TagFirst = Record, TagLast = Enum }; - + +protected: + enum { TypeClassBitSize = 6 }; + private: QualType CanonicalType; @@ -291,7 +685,7 @@ private: /// TypeClass bitfield - Enum that specifies what subclass this belongs to. /// Note that this should stay at the end of the ivars for Type so that /// subclasses can pack their bitfields into the same word. - unsigned TC : 5; + unsigned TC : TypeClassBitSize; Type(const Type&); // DO NOT IMPLEMENT. void operator=(const Type&); // DO NOT IMPLEMENT. @@ -304,15 +698,15 @@ protected: virtual ~Type() {} virtual void Destroy(ASTContext& C); friend class ASTContext; - + public: TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); } - + bool isCanonical() const { return CanonicalType.getTypePtr() == this; } - /// Types are partitioned into 3 broad categories (C99 6.2.5p1): + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. - + /// \brief Determines whether the type describes an object in memory. /// /// Note that this definition of object type corresponds to the C++ @@ -324,7 +718,7 @@ public: /// isIncompleteType - Return true if this is an incomplete type. /// A type that can describe objects, but which lacks information needed to /// determine its size (e.g. void, or a fwd declared struct). Clients of this - /// routine will need to determine if the size is actually required. + /// routine will need to determine if the size is actually required. bool isIncompleteType() const; /// isIncompleteOrObjectType - Return true if this is an incomplete or object @@ -339,13 +733,13 @@ public: /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array /// types that have a non-constant expression. This does not include "[]". bool isVariablyModifiedType() const; - + /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. /// isSpecificBuiltinType - Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; - + /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) @@ -354,7 +748,7 @@ public: bool isCharType() const; bool isWideCharType() const; bool isIntegralType() const; - + /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). @@ -368,13 +762,14 @@ public: bool isDerivedType() const; // C99 6.2.5p20 bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) bool isAggregateType() const; - + // Type Predicates: Check to see if this type is structurally the specified // type, ignoring typedefs and qualifiers. bool isFunctionType() const; - bool isFunctionNoProtoType() const { return getAsFunctionNoProtoType() != 0; } - bool isFunctionProtoType() const { return getAsFunctionProtoType() != 0; } + bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); } + bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } bool isPointerType() const; + bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isBlockPointerType() const; bool isVoidPointerType() const; bool isReferenceType() const; @@ -389,21 +784,27 @@ public: bool isVariableArrayType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; - bool isClassType() const; - bool isStructureType() const; + bool isClassType() const; + bool isStructureType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object. + // FIXME: change this to 'raw' interface type, so we can used 'interface' type + // for the common case. bool isObjCInterfaceType() const; // NSString or NSString<foo> bool isObjCQualifiedInterfaceType() const; // NSString<foo> bool isObjCQualifiedIdType() const; // id<foo> + bool isObjCQualifiedClassType() const; // Class<foo> + bool isObjCIdType() const; // id + bool isObjCClassType() const; // Class + bool isObjCBuiltinType() const; // 'id' or 'Class' bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t /// isDependentType - Whether this type is a dependent type, meaning - /// that its definition somehow depends on a template parameter + /// that its definition somehow depends on a template parameter /// (C++ [temp.dep.type]). bool isDependentType() const { return Dependent; } bool isOverloadableType() const; @@ -416,41 +817,29 @@ public: /// hasObjCPointerRepresentation - Whether this type can represent /// an objective pointer type for the purpose of GC'ability - bool hasObjCPointerRepresentation() const; + bool hasObjCPointerRepresentation() const; // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. - const BuiltinType *getAsBuiltinType() const; - const FunctionType *getAsFunctionType() const; - const FunctionNoProtoType *getAsFunctionNoProtoType() const; - const FunctionProtoType *getAsFunctionProtoType() const; - const PointerType *getAsPointerType() const; - const BlockPointerType *getAsBlockPointerType() const; - const ReferenceType *getAsReferenceType() const; - const LValueReferenceType *getAsLValueReferenceType() const; - const RValueReferenceType *getAsRValueReferenceType() const; - const MemberPointerType *getAsMemberPointerType() const; - const TagType *getAsTagType() const; - const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; /// NOTE: getAs*ArrayType are methods on ASTContext. - const TypedefType *getAsTypedefType() const; const RecordType *getAsUnionType() const; - const EnumType *getAsEnumType() const; - const VectorType *getAsVectorType() const; // GCC vector type. - const ComplexType *getAsComplexType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. - const ExtVectorType *getAsExtVectorType() const; // Extended vector type. - const ObjCObjectPointerType *getAsObjCObjectPointerType() const; - const ObjCInterfaceType *getAsObjCInterfaceType() const; - const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; + // The following is a convenience method that returns an ObjCObjectPointerType + // for object declared using an interface. + const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; - const TemplateTypeParmType *getAsTemplateTypeParmType() const; + const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const; + const CXXRecordDecl *getCXXRecordDeclForPointerType() const; + + // Member-template getAs<specific type>'. This scheme will eventually + // replace the specific getAsXXXX methods above. + // + // There are some specializations of this member template listed + // immediately following this class. + template <typename T> const T *getAs() const; - const TemplateSpecializationType * - getAsTemplateSpecializationType() const; - /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC /// interface, return the interface type, otherwise return null. const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; @@ -459,15 +848,16 @@ public: /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. const Type *getArrayElementTypeNoTypeQual() const; - - /// getDesugaredType - Return the specified type with any "sugar" removed from - /// the type. This takes off typedefs, typeof's etc. If the outer level of - /// the type is already concrete, it returns it unmodified. This is similar - /// to getting the canonical type, but it doesn't remove *all* typedefs. For - /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is - /// concrete. - QualType getDesugaredType(bool ForDisplay = false) const; - + + /// getPointeeType - If this is a pointer, ObjC object pointer, or block + /// pointer, this returns the respective pointee. + QualType getPointeeType() const; + + /// getUnqualifiedDesugaredType() - Return the specified type with + /// any "sugar" removed from the type, removing any typedefs, + /// typeofs, etc., as well as any qualifiers. + const Type *getUnqualifiedDesugaredType() const; + /// More type predicates useful for type checking/promotion bool isPromotableIntegerType() const; // C99 6.3.1.1p2 @@ -492,56 +882,27 @@ public: /// set of type specifiers. bool isSpecifierType() const; + const char *getTypeClassName() const; + QualType getCanonicalTypeInternal() const { return CanonicalType; } void dump() const; - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const = 0; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const = 0; static bool classof(const Type *) { return true; } }; -/// ExtQualType - TR18037 (C embedded extensions) 6.2.5p26 -/// This supports all kinds of type attributes; including, -/// address space qualified types, objective-c's __weak and -/// __strong attributes. -/// -class ExtQualType : public Type, public llvm::FoldingSetNode { - /// BaseType - This is the underlying type that this qualifies. All CVR - /// qualifiers are stored on the QualType that references this type, so we - /// can't have any here. - Type *BaseType; - - /// Address Space ID - The address space ID this type is qualified with. - unsigned AddressSpace; - /// GC __weak/__strong attributes - QualType::GCAttrTypes GCAttrType; - - ExtQualType(Type *Base, QualType CanonicalPtr, unsigned AddrSpace, - QualType::GCAttrTypes gcAttr) : - Type(ExtQual, CanonicalPtr, Base->isDependentType()), BaseType(Base), - AddressSpace(AddrSpace), GCAttrType(gcAttr) { - assert(!isa<ExtQualType>(BaseType) && - "Cannot have ExtQualType of ExtQualType"); - } - friend class ASTContext; // ASTContext creates these. -public: - Type *getBaseType() const { return BaseType; } - QualType::GCAttrTypes getObjCGCAttr() const { return GCAttrType; } - unsigned getAddressSpace() const { return AddressSpace; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), AddressSpace, GCAttrType); - } - static void Profile(llvm::FoldingSetNodeID &ID, Type *Base, - unsigned AddrSpace, QualType::GCAttrTypes gcAttr) { - ID.AddPointer(Base); - ID.AddInteger(AddrSpace); - ID.AddInteger(gcAttr); - } - - static bool classof(const Type *T) { return T->getTypeClass() == ExtQual; } - static bool classof(const ExtQualType *) { return true; } -}; +template <> inline const TypedefType *Type::getAs() const { + return dyn_cast<TypedefType>(this); +} + +// We can do canonical leaf types faster, because we don't have to +// worry about preserving child type decoration. +#define TYPE(Class, Base) +#define LEAF_TYPE(Class) \ +template <> inline const Class##Type *Type::getAs() const { \ + return dyn_cast<Class##Type>(CanonicalType); \ +} +#include "clang/AST/TypeNodes.def" /// BuiltinType - This class is used for builtin types like 'int'. Builtin @@ -550,16 +911,18 @@ class BuiltinType : public Type { public: enum Kind { Void, - + Bool, // This is bool and/or _Bool. Char_U, // This is 'char' for targets where char is unsigned. UChar, // This is explicitly qualified unsigned char. + Char16, // This is 'char16_t' for C++. + Char32, // This is 'char32_t' for C++. UShort, UInt, ULong, ULongLong, UInt128, // __uint128_t - + Char_S, // This is 'char' for targets where char is signed. SChar, // This is explicitly qualified signed char. WChar, // This is 'wchar_t' for C++. @@ -568,29 +931,35 @@ public: Long, LongLong, Int128, // __int128_t - + Float, Double, LongDouble, 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. - - UndeducedAuto // In C++0x, this represents the type of an auto variable + + UndeducedAuto, // In C++0x, this represents the type of an auto variable // that has not been deduced yet. + ObjCId, // This represents the ObjC 'id' type. + ObjCClass // This represents the ObjC 'Class' type. }; private: Kind TypeKind; public: - BuiltinType(Kind K) - : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)), + BuiltinType(Kind K) + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)), TypeKind(K) {} - + Kind getKind() const { return TypeKind; } const char *getName(const LangOptions &LO) const; - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } static bool classof(const BuiltinType *) { return true; } }; @@ -605,13 +974,17 @@ private: public: FixedWidthIntType(unsigned W, bool S) : Type(FixedWidthInt, QualType(), false), Width(W), Signed(S) {} - + unsigned getWidth() const { return Width; } bool isSigned() const { return Signed; } const char *getName() const; - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + static bool classof(const Type *T) { return T->getTypeClass() == FixedWidthInt; } static bool classof(const FixedWidthIntType *) { return true; } }; @@ -622,22 +995,26 @@ public: class ComplexType : public Type, public llvm::FoldingSetNode { QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) : - Type(Complex, CanonicalPtr, Element->isDependentType()), + Type(Complex, CanonicalPtr, Element->isDependentType()), ElementType(Element) { } friend class ASTContext; // ASTContext creates these. public: QualType getElementType() const { return ElementType; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { ID.AddPointer(Element.getAsOpaquePtr()); } - + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } static bool classof(const ComplexType *) { return true; } }; @@ -652,18 +1029,22 @@ class PointerType : public Type, public llvm::FoldingSetNode { } friend class ASTContext; // ASTContext creates these. public: - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + QualType getPointeeType() const { return PointeeType; } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } - + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } static bool classof(const PointerType *) { return true; } }; @@ -675,26 +1056,30 @@ public: class BlockPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; // Block is some kind of pointer type BlockPointerType(QualType Pointee, QualType CanonicalCls) : - Type(BlockPointer, CanonicalCls, Pointee->isDependentType()), + Type(BlockPointer, CanonicalCls, Pointee->isDependentType()), PointeeType(Pointee) { } friend class ASTContext; // ASTContext creates these. public: - + // Get the pointee type. Pointee is required to always be a function type. QualType getPointeeType() const { return PointeeType; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } - - static bool classof(const Type *T) { - return T->getTypeClass() == BlockPointer; + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; } static bool classof(const BlockPointerType *) { return true; } }; @@ -734,7 +1119,11 @@ class LValueReferenceType : public ReferenceType { } friend class ASTContext; // ASTContext creates these public: - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference; @@ -750,7 +1139,11 @@ class RValueReferenceType : public ReferenceType { } friend class ASTContext; // ASTContext creates these public: - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == RValueReference; @@ -778,7 +1171,11 @@ public: const Type *getClass() const { return Class; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), getClass()); @@ -809,15 +1206,15 @@ public: private: /// ElementType - The element type of the array. QualType ElementType; - + // NOTE: VC++ treats enums as signed, avoid using the ArraySizeModifier enum /// NOTE: These fields are packed into the bitfields space in the Type class. unsigned SizeModifier : 2; - + /// IndexTypeQuals - Capture qualifiers in declarations like: /// 'int X[static restrict 4]'. For function parameters only. unsigned IndexTypeQuals : 3; - + protected: // C++ [temp.dep.type]p1: // A type is dependent if it is... @@ -835,10 +1232,15 @@ public: ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(SizeModifier); } - unsigned getIndexTypeQualifier() const { return IndexTypeQuals; } - + Qualifiers getIndexTypeQualifiers() const { + return Qualifiers::fromCVRMask(IndexTypeQuals); + } + unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; } + static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || + T->getTypeClass() == ConstantArrayWithExpr || + T->getTypeClass() == ConstantArrayWithoutExpr || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || T->getTypeClass() == DependentSizedArray; @@ -846,23 +1248,33 @@ public: static bool classof(const ArrayType *) { return true; } }; -/// ConstantArrayType - This class represents C arrays with a specified constant -/// size. For example 'int A[100]' has ConstantArrayType where the element type -/// is 'int' and the size is 100. +/// ConstantArrayType - This class represents the canonical version of +/// C arrays with a specified constant size. For example, the canonical +/// type for 'int A[4 + 4*100]' is a ConstantArrayType where the element +/// type is 'int' and the size is 404. class ConstantArrayType : public ArrayType { llvm::APInt Size; // Allows us to unique the type. - + ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) - : ArrayType(ConstantArray, et, can, sm, tq), Size(size) {} + : ArrayType(ConstantArray, et, can, sm, tq), + Size(size) {} +protected: + ConstantArrayType(TypeClass tc, QualType et, QualType can, + const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) + : ArrayType(tc, et, can, sm, tq), Size(size) {} friend class ASTContext; // ASTContext creates these. public: const llvm::APInt &getSize() const { return Size; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getSize(), - getSizeModifier(), getIndexTypeQualifier()); + Profile(ID, getElementType(), getSize(), + getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, @@ -872,35 +1284,115 @@ public: ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray; + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == ConstantArrayWithExpr || + T->getTypeClass() == ConstantArrayWithoutExpr; } static bool classof(const ConstantArrayType *) { return true; } }; +/// ConstantArrayWithExprType - This class represents C arrays with a +/// constant size specified by means of an integer constant expression. +/// For example 'int A[sizeof(int)]' has ConstantArrayWithExprType where +/// the element type is 'int' and the size expression is 'sizeof(int)'. +/// These types are non-canonical. +class ConstantArrayWithExprType : public ConstantArrayType { + /// SizeExpr - The ICE occurring in the concrete syntax. + Expr *SizeExpr; + /// Brackets - The left and right array brackets. + SourceRange Brackets; + + ConstantArrayWithExprType(QualType et, QualType can, + const llvm::APInt &size, Expr *e, + ArraySizeModifier sm, unsigned tq, + SourceRange brackets) + : ConstantArrayType(ConstantArrayWithExpr, et, can, size, sm, tq), + SizeExpr(e), Brackets(brackets) {} + friend class ASTContext; // ASTContext creates these. + virtual void Destroy(ASTContext& C); + +public: + Expr *getSizeExpr() const { return SizeExpr; } + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArrayWithExpr; + } + static bool classof(const ConstantArrayWithExprType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + assert(0 && "Cannot unique ConstantArrayWithExprTypes."); + } +}; + +/// ConstantArrayWithoutExprType - This class represents C arrays with a +/// constant size that was not specified by an integer constant expression, +/// but inferred by static semantics. +/// For example 'int A[] = { 0, 1, 2 }' has ConstantArrayWithoutExprType. +/// These types are non-canonical: the corresponding canonical type, +/// having the size specified in an APInt object, is a ConstantArrayType. +class ConstantArrayWithoutExprType : public ConstantArrayType { + + ConstantArrayWithoutExprType(QualType et, QualType can, + const llvm::APInt &size, + ArraySizeModifier sm, unsigned tq) + : ConstantArrayType(ConstantArrayWithoutExpr, et, can, size, sm, tq) {} + friend class ASTContext; // ASTContext creates these. + +public: + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArrayWithoutExpr; + } + static bool classof(const ConstantArrayWithoutExprType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + assert(0 && "Cannot unique ConstantArrayWithoutExprTypes."); + } +}; + /// IncompleteArrayType - This class represents C arrays with an unspecified /// size. For example 'int A[]' has an IncompleteArrayType where the element /// type is 'int' and the size is unspecified. class IncompleteArrayType : public ArrayType { + IncompleteArrayType(QualType et, QualType can, - ArraySizeModifier sm, unsigned tq) + ArraySizeModifier sm, unsigned tq) : ArrayType(IncompleteArray, et, can, sm, tq) {} friend class ASTContext; // ASTContext creates these. public: + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } - static bool classof(const Type *T) { - return T->getTypeClass() == IncompleteArray; + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; } static bool classof(const IncompleteArrayType *) { return true; } - + friend class StmtIteratorBase; - + void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getSizeModifier(), getIndexTypeQualifier()); + Profile(ID, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers()); } - + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); @@ -925,32 +1417,43 @@ public: /// } /// class VariableArrayType : public ArrayType { - /// SizeExpr - An assignment expression. VLA's are only permitted within - /// a function block. + /// SizeExpr - An assignment expression. VLA's are only permitted within + /// a function block. Stmt *SizeExpr; - + /// Brackets - The left and right array brackets. + SourceRange Brackets; + VariableArrayType(QualType et, QualType can, Expr *e, - ArraySizeModifier sm, unsigned tq) - : ArrayType(VariableArray, et, can, sm, tq), SizeExpr((Stmt*) e) {} + ArraySizeModifier sm, unsigned tq, + SourceRange brackets) + : ArrayType(VariableArray, et, can, sm, tq), + SizeExpr((Stmt*) e), Brackets(brackets) {} friend class ASTContext; // ASTContext creates these. virtual void Destroy(ASTContext& C); public: - Expr *getSizeExpr() const { + Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == VariableArray; + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == VariableArray; } static bool classof(const VariableArrayType *) { return true; } - + friend class StmtIteratorBase; - + void Profile(llvm::FoldingSetNodeID &ID) { assert(0 && "Cannnot unique VariableArrayTypes."); } @@ -959,7 +1462,7 @@ public: /// DependentSizedArrayType - This type represents an array type in /// C++ whose size is a value-dependent expression. For example: /// @code -/// template<typename T, int Size> +/// template<typename T, int Size> /// class array { /// T data[Size]; /// }; @@ -968,35 +1471,54 @@ public: /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { + ASTContext &Context; + /// SizeExpr - An assignment expression that will instantiate to the /// size of the array. Stmt *SizeExpr; - - DependentSizedArrayType(QualType et, QualType can, Expr *e, - ArraySizeModifier sm, unsigned tq) - : ArrayType(DependentSizedArray, et, can, sm, tq), SizeExpr((Stmt*) e) {} + /// Brackets - The left and right array brackets. + SourceRange Brackets; + + DependentSizedArrayType(ASTContext &Context, QualType et, QualType can, + Expr *e, ArraySizeModifier sm, unsigned tq, + SourceRange brackets) + : ArrayType(DependentSizedArray, et, can, sm, tq), + Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {} friend class ASTContext; // ASTContext creates these. virtual void Destroy(ASTContext& C); public: - Expr *getSizeExpr() const { + Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentSizedArray; + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedArray; } static bool classof(const DependentSizedArrayType *) { return true; } - + friend class StmtIteratorBase; - + + void Profile(llvm::FoldingSetNodeID &ID) { - assert(0 && "Cannnot unique DependentSizedArrayTypes."); + Profile(ID, Context, getElementType(), + getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + QualType ET, ArraySizeModifier SizeMod, + unsigned TypeQuals, Expr *E); }; /// DependentSizedExtVectorType - This type represent an extended vector type @@ -1007,71 +1529,88 @@ public: /// typedef T __attribute__((ext_vector_type(Size))) type; /// } /// @endcode -class DependentSizedExtVectorType : public Type { +class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { + ASTContext &Context; Expr *SizeExpr; /// ElementType - The element type of the array. QualType ElementType; SourceLocation loc; - - DependentSizedExtVectorType(QualType ElementType, QualType can, - Expr *SizeExpr, SourceLocation loc) - : Type (DependentSizedExtVector, can, true), - SizeExpr(SizeExpr), ElementType(ElementType), loc(loc) {} + + DependentSizedExtVectorType(ASTContext &Context, QualType ElementType, + QualType can, Expr *SizeExpr, SourceLocation loc) + : Type (DependentSizedExtVector, can, true), + Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), + loc(loc) {} friend class ASTContext; virtual void Destroy(ASTContext& C); public: - const Expr *getSizeExpr() const { return SizeExpr; } + Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return loc; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == DependentSizedExtVector; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedExtVector; } - static bool classof(const DependentSizedExtVectorType *) { return true; } + static bool classof(const DependentSizedExtVectorType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + QualType ElementType, Expr *SizeExpr); }; - + /// VectorType - GCC generic vector type. This type is created using -/// __attribute__((vector_size(n)), where "n" specifies the vector size in -/// bytes. Since the constructor takes the number of vector elements, the +/// __attribute__((vector_size(n)), where "n" specifies the vector size in +/// bytes. Since the constructor takes the number of vector elements, the /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { protected: /// ElementType - The element type of the vector. QualType ElementType; - + /// NumElements - The number of elements in the vector. unsigned NumElements; - + VectorType(QualType vecType, unsigned nElements, QualType canonType) : - Type(Vector, canonType, vecType->isDependentType()), - ElementType(vecType), NumElements(nElements) {} - VectorType(TypeClass tc, QualType vecType, unsigned nElements, - QualType canonType) - : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), - NumElements(nElements) {} + Type(Vector, canonType, vecType->isDependentType()), + ElementType(vecType), NumElements(nElements) {} + VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType) + : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), + NumElements(nElements) {} friend class ASTContext; // ASTContext creates these. public: - + QualType getElementType() const { return ElementType; } - unsigned getNumElements() const { return NumElements; } + unsigned getNumElements() const { return NumElements; } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass()); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); } - static bool classof(const Type *T) { - return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; + static bool classof(const Type *T) { + return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } static bool classof(const VectorType *) { return true; } }; @@ -1083,7 +1622,7 @@ public: /// points, colors, and textures (modeled after OpenGL Shading Language). class ExtVectorType : public VectorType { ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : - VectorType(ExtVector, vecType, nElements, canonType) {} + VectorType(ExtVector, vecType, nElements, canonType) {} friend class ASTContext; // ASTContext creates these. public: static int getPointAccessorIdx(char c) { @@ -1122,21 +1661,25 @@ public: case 'f': return 15; } } - + static int getAccessorIdx(char c) { if (int idx = getPointAccessorIdx(c)+1) return idx-1; return getNumericAccessorIdx(c); } - + bool isAccessorWithinNumElements(char c) const { if (int idx = getAccessorIdx(c)+1) return unsigned(idx-1) < NumElements; return false; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } - static bool classof(const Type *T) { - return T->getTypeClass() == ExtVector; + static bool classof(const Type *T) { + return T->getTypeClass() == ExtVector; } static bool classof(const ExtVectorType *) { return true; } }; @@ -1157,21 +1700,26 @@ class FunctionType : public Type { /// cv-qualifier-seq, [...], are part of the function type. /// unsigned TypeQuals : 3; - + + /// NoReturn - Indicates if the function type is attribute noreturn. + unsigned NoReturn : 1; + // The type returned by the function. QualType ResultType; protected: FunctionType(TypeClass tc, QualType res, bool SubclassInfo, - unsigned typeQuals, QualType Canonical, bool Dependent) + unsigned typeQuals, QualType Canonical, bool Dependent, + bool noReturn = false) : Type(tc, Canonical, Dependent), - SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {} + SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn), + ResultType(res) {} bool getSubClassData() const { return SubClassData; } unsigned getTypeQuals() const { return TypeQuals; } public: - + QualType getResultType() const { return ResultType; } + bool getNoReturnAttr() const { return NoReturn; } - static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; @@ -1182,22 +1730,29 @@ public: /// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { - FunctionNoProtoType(QualType Result, QualType Canonical) - : FunctionType(FunctionNoProto, Result, false, 0, Canonical, - /*Dependent=*/false) {} + FunctionNoProtoType(QualType Result, QualType Canonical, + bool NoReturn = false) + : FunctionType(FunctionNoProto, Result, false, 0, Canonical, + /*Dependent=*/false, NoReturn) {} friend class ASTContext; // ASTContext creates these. public: // No additional state past what FunctionType provides. - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType()); + Profile(ID, getResultType(), getNoReturnAttr()); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) { + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, + bool NoReturn) { + ID.AddInteger(NoReturn); ID.AddPointer(ResultType.getAsOpaquePtr()); } - + static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } @@ -1223,10 +1778,10 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs, bool isVariadic, unsigned typeQuals, bool hasExs, bool hasAnyExs, const QualType *ExArray, - unsigned numExs, QualType Canonical) + unsigned numExs, QualType Canonical, bool NoReturn) : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, - (Result->isDependentType() || - hasAnyDependentType(ArgArray, numArgs))), + (Result->isDependentType() || + hasAnyDependentType(ArgArray, numArgs)), NoReturn), NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs), AnyExceptionSpec(hasAnyExs) { // Fill in the trailing argument array. @@ -1273,14 +1828,14 @@ public: assert(i < NumExceptions && "Invalid exception number!"); return exception_begin()[i]; } - bool hasEmptyExceptionSpec() const { - return hasExceptionSpec() && !hasAnyExceptionSpec() && + bool hasEmptyExceptionSpec() const { + return hasExceptionSpec() && !hasAnyExceptionSpec() && getNumExceptions() == 0; } bool isVariadic() const { return getSubClassData(); } unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } - + typedef const QualType *arg_type_iterator; arg_type_iterator arg_type_begin() const { return reinterpret_cast<const QualType *>(this+1); @@ -1296,7 +1851,11 @@ public: return exception_begin() + NumExceptions; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; @@ -1308,22 +1867,23 @@ public: arg_type_iterator ArgTys, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, - unsigned NumExceptions, exception_iterator Exs); + unsigned NumExceptions, exception_iterator Exs, + bool NoReturn); }; class TypedefType : public Type { TypedefDecl *Decl; protected: - TypedefType(TypeClass tc, TypedefDecl *D, QualType can) + TypedefType(TypeClass tc, TypedefDecl *D, QualType can) : Type(tc, can, can->isDependentType()), Decl(D) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } friend class ASTContext; // ASTContext creates these. public: - + TypedefDecl *getDecl() const { return Decl; } - + /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to /// potentially looking through *all* consecutive typedefs. This returns the /// sum of the type qualifiers, so if you have: @@ -1331,8 +1891,12 @@ public: /// typedef volatile A B; /// looking through the typedefs for B will give you "const volatile A". QualType LookThroughTypedefs() const; - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + bool isSugared() const { return true; } + QualType desugar() const; + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } static bool classof(const TypedefType *) { return true; } @@ -1341,29 +1905,66 @@ public: /// TypeOfExprType (GCC extension). class TypeOfExprType : public Type { Expr *TOExpr; - TypeOfExprType(Expr *E, QualType can); + +protected: + TypeOfExprType(Expr *E, QualType can = QualType()); friend class ASTContext; // ASTContext creates these. public: Expr *getUnderlyingExpr() const { return TOExpr; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + /// \brief Remove a single level of sugar. + QualType desugar() const; + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } static bool classof(const TypeOfExprType *) { return true; } }; +/// Subclass of TypeOfExprType that is used for canonical, dependent +/// typeof(expr) types. +class DependentTypeOfExprType + : public TypeOfExprType, public llvm::FoldingSetNode { + ASTContext &Context; + +public: + DependentTypeOfExprType(ASTContext &Context, Expr *E) + : TypeOfExprType(E), Context(Context) { } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + Expr *E); +}; + /// TypeOfType (GCC extension). class TypeOfType : public Type { QualType TOType; - TypeOfType(QualType T, QualType can) + TypeOfType(QualType T, QualType can) : Type(TypeOf, can, T->isDependentType()), TOType(T) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } friend class ASTContext; // ASTContext creates these. public: QualType getUnderlyingType() const { return TOType; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getUnderlyingType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } static bool classof(const TypeOfType *) { return true; } @@ -1372,18 +1973,51 @@ public: /// DecltypeType (C++0x) class DecltypeType : public Type { Expr *E; - DecltypeType(Expr *E, QualType can); + + // FIXME: We could get rid of UnderlyingType if we wanted to: We would have to + // Move getDesugaredType to ASTContext so that it can call getDecltypeForExpr + // from it. + QualType UnderlyingType; + +protected: + DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); friend class ASTContext; // ASTContext creates these. public: Expr *getUnderlyingExpr() const { return E; } - - virtual void getAsStringInternal(std::string &InnerString, + QualType getUnderlyingType() const { return UnderlyingType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getUnderlyingType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return !isDependentType(); } + + 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; } }; - + +/// Subclass of DecltypeType that is used for canonical, dependent +/// C++0x decltype types. +class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { + ASTContext &Context; + +public: + DependentDecltypeType(ASTContext &Context, Expr *E); + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + Expr *E); +}; + 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 @@ -1397,17 +2031,18 @@ class TagType : public Type { protected: TagType(TypeClass TC, TagDecl *D, QualType can); -public: +public: TagDecl *getDecl() const { return decl.getPointer(); } - + /// @brief Determines whether this type is in the process of being - /// defined. + /// defined. bool isBeingDefined() const { return decl.getInt(); } - void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); } + void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; - static bool classof(const Type *T) { + static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } static bool classof(const TagType *) { return true; } @@ -1425,20 +2060,23 @@ protected: : TagType(TC, reinterpret_cast<TagDecl*>(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: - + RecordDecl *getDecl() const { return reinterpret_cast<RecordDecl*>(TagType::getDecl()); } - - // FIXME: This predicate is a helper to QualType/Type. It needs to + + // FIXME: This predicate is a helper to QualType/Type. It needs to // recursively check all fields for const-ness. If any field is declared - // const, it needs to return false. + // const, it needs to return false. bool hasConstFields() const { return false; } // FIXME: RecordType needs to check when it is created that all fields are in // the same address space, and return that. unsigned getAddressSpace() const { return 0; } - + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + static bool classof(const TagType *T); static bool classof(const Type *T) { return isa<TagType>(T) && classof(cast<TagType>(T)); @@ -1453,11 +2091,14 @@ class EnumType : public TagType { : TagType(Enum, reinterpret_cast<TagDecl*>(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: - + EnumDecl *getDecl() const { return reinterpret_cast<EnumDecl*>(TagType::getDecl()); } - + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + static bool classof(const TagType *T); static bool classof(const Type *T) { return isa<TagType>(T) && classof(cast<TagType>(T)); @@ -1465,18 +2106,83 @@ public: static bool classof(const EnumType *) { return true; } }; +/// ElaboratedType - A non-canonical type used to represents uses of +/// elaborated type specifiers in C++. For example: +/// +/// void foo(union MyUnion); +/// ^^^^^^^^^^^^^ +/// +/// At the moment, for efficiency we do not create elaborated types in +/// C, since outside of typedefs all references to structs would +/// necessarily be elaborated. +class ElaboratedType : public Type, public llvm::FoldingSetNode { +public: + enum TagKind { + TK_struct, + TK_union, + TK_class, + TK_enum + }; + +private: + /// The tag that was used in this elaborated type specifier. + TagKind Tag; + + /// The underlying type. + QualType UnderlyingType; + + explicit ElaboratedType(QualType Ty, TagKind Tag, QualType Canon) + : Type(Elaborated, Canon, Canon->isDependentType()), + Tag(Tag), UnderlyingType(Ty) { } + friend class ASTContext; // ASTContext creates these. + +public: + TagKind getTagKind() const { return Tag; } + QualType getUnderlyingType() const { return UnderlyingType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getUnderlyingType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + static const char *getNameForTagKind(TagKind Kind) { + switch (Kind) { + default: assert(0 && "Unknown TagKind!"); + case TK_struct: return "struct"; + case TK_union: return "union"; + case TK_class: return "class"; + case TK_enum: return "enum"; + } + } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getUnderlyingType(), getTagKind()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, TagKind Tag) { + ID.AddPointer(T.getAsOpaquePtr()); + ID.AddInteger(Tag); + } + + static bool classof(const ElaboratedType*) { return true; } + static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } +}; + class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { unsigned Depth : 15; unsigned Index : 16; unsigned ParameterPack : 1; IdentifierInfo *Name; - TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N, - QualType Canon) + TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N, + QualType Canon) : Type(TemplateTypeParm, Canon, /*Dependent=*/true), Depth(D), Index(I), ParameterPack(PP), Name(N) { } - TemplateTypeParmType(unsigned D, unsigned I, bool PP) + TemplateTypeParmType(unsigned D, unsigned I, bool PP) : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true), Depth(D), Index(I), ParameterPack(PP), Name(0) { } @@ -1487,15 +2193,19 @@ public: unsigned getIndex() const { return Index; } bool isParameterPack() const { return ParameterPack; } IdentifierInfo *getName() const { return Name; } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Depth, Index, ParameterPack, Name); } - static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, - unsigned Index, bool ParameterPack, + static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, + unsigned Index, bool ParameterPack, IdentifierInfo *Name) { ID.AddInteger(Depth); ID.AddInteger(Index); @@ -1503,8 +2213,8 @@ public: ID.AddPointer(Name); } - static bool classof(const Type *T) { - return T->getTypeClass() == TemplateTypeParm; + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; } static bool classof(const TemplateTypeParmType *T) { return true; } }; @@ -1518,23 +2228,27 @@ public: /// type will point to some other type node that represents the /// instantiation or class template specialization. For example, a /// class template specialization type of @c vector<int> will refer to -/// a tag type for the instantiation +/// a tag type for the instantiation /// @c std::vector<int, std::allocator<int>>. /// /// Other template specialization types, for which the template name /// is dependent, may be canonical types. These types are always /// dependent. -class TemplateSpecializationType +class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { - /// \brief The name of the template being specialized. + // FIXME: Currently needed for profiling expressions; can we avoid this? + ASTContext &Context; + + /// \brief The name of the template being specialized. TemplateName Template; /// \brief - The number of template arguments named in this class /// template specialization. unsigned NumArgs; - TemplateSpecializationType(TemplateName T, + TemplateSpecializationType(ASTContext &Context, + TemplateName T, const TemplateArgument *Args, unsigned NumArgs, QualType Canon); @@ -1546,7 +2260,7 @@ public: /// \brief Determine whether any of the given template arguments are /// dependent. static bool anyDependentTemplateArguments(const TemplateArgument *Args, - unsigned NumArgs); + unsigned NumArgs); /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. @@ -1563,7 +2277,7 @@ public: TemplateName getTemplateName() const { return Template; } /// \brief Retrieve the template arguments. - const TemplateArgument *getArgs() const { + const TemplateArgument *getArgs() const { return reinterpret_cast<const TemplateArgument *>(this + 1); } @@ -1574,17 +2288,22 @@ public: /// \precondition @c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return !isDependentType(); } + QualType desugar() const { return getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Template, getArgs(), NumArgs); + Profile(ID, Template, getArgs(), NumArgs, Context); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - const TemplateArgument *Args, unsigned NumArgs); + const TemplateArgument *Args, unsigned NumArgs, + ASTContext &Context); - static bool classof(const Type *T) { - return T->getTypeClass() == TemplateSpecialization; + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateSpecialization; } static bool classof(const TemplateSpecializationType *T) { return true; } }; @@ -1617,7 +2336,14 @@ public: /// \brief Retrieve the type named by the qualified-id. QualType getNamedType() const { return NamedType; } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + /// \brief Remove a single level of sugar. + QualType desugar() const { return getNamedType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, NNS, NamedType); @@ -1629,8 +2355,8 @@ public: NamedType.Profile(ID); } - static bool classof(const Type *T) { - return T->getTypeClass() == QualifiedName; + static bool classof(const Type *T) { + return T->getTypeClass() == QualifiedName; } static bool classof(const QualifiedNameType *T) { return true; } }; @@ -1651,7 +2377,7 @@ class TypenameType : public Type, public llvm::FoldingSetNode { /// \brief The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; - typedef llvm::PointerUnion<const IdentifierInfo *, + typedef llvm::PointerUnion<const IdentifierInfo *, const TemplateSpecializationType *> NameType; /// \brief The type that this typename specifier refers to. @@ -1659,15 +2385,15 @@ class TypenameType : public Type, public llvm::FoldingSetNode { TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) - : Type(Typename, CanonType, true), NNS(NNS), Name(Name) { - assert(NNS->isDependent() && + : Type(Typename, CanonType, true), NNS(NNS), Name(Name) { + assert(NNS->isDependent() && "TypenameType requires a dependent nested-name-specifier"); } TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty, QualType CanonType) - : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) { - assert(NNS->isDependent() && + : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) { + assert(NNS->isDependent() && "TypenameType requires a dependent nested-name-specifier"); } @@ -1683,8 +2409,8 @@ public: /// This routine will return a non-NULL identifier pointer when the /// form of the original typename was terminated by an identifier, /// e.g., "typename T::type". - const IdentifierInfo *getIdentifier() const { - return Name.dyn_cast<const IdentifierInfo *>(); + const IdentifierInfo *getIdentifier() const { + return Name.dyn_cast<const IdentifierInfo *>(); } /// \brief Retrieve the type named by the typename specifier as a @@ -1693,7 +2419,11 @@ public: return Name.dyn_cast<const TemplateSpecializationType *>(); } - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, NNS, Name); @@ -1705,35 +2435,112 @@ public: ID.AddPointer(Name.getOpaqueValue()); } - static bool classof(const Type *T) { - return T->getTypeClass() == Typename; + static bool classof(const Type *T) { + return T->getTypeClass() == Typename; } static bool classof(const TypenameType *T) { return true; } }; +/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for +/// object oriented design. They basically correspond to C++ classes. There +/// are two kinds of interface types, normal interfaces like "NSString" and +/// qualified interfaces, which are qualified with a protocol list like +/// "NSString<NSCopyable, NSAmazing>". +class ObjCInterfaceType : public Type, public llvm::FoldingSetNode { + ObjCInterfaceDecl *Decl; + + // List of protocols for this protocol conforming object type + // List is sorted on protocol name. No protocol is enterred more than once. + llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; + + ObjCInterfaceType(ObjCInterfaceDecl *D, + ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCInterface, QualType(), /*Dependent=*/false), + Decl(D), Protocols(Protos, Protos+NumP) { } + friend class ASTContext; // ASTContext creates these. +public: + ObjCInterfaceDecl *getDecl() const { return Decl; } + + /// getNumProtocols - Return the number of qualifying protocols in this + /// interface type, or 0 if there are none. + unsigned getNumProtocols() const { return Protocols.size(); } + + /// qual_iterator and friends: this provides access to the (potentially empty) + /// list of protocols qualifying this interface. + typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; + qual_iterator qual_begin() const { return Protocols.begin(); } + qual_iterator qual_end() const { return Protocols.end(); } + bool qual_empty() const { return Protocols.size() == 0; } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **protocols, unsigned NumProtocols); + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCInterface; + } + static bool classof(const ObjCInterfaceType *) { return true; } +}; + /// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>', /// and 'Interface <p> *'. /// /// Duplicate protocols are removed and protocol list is canonicalized to be in /// alphabetical order. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { - ObjCInterfaceDecl *Decl; + QualType PointeeType; // A builtin or interface type. + // List of protocols for this protocol conforming object type // List is sorted on protocol name. No protocol is entered more than once. llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; - ObjCObjectPointerType(ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP) : + ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : Type(ObjCObjectPointer, QualType(), /*Dependent=*/false), - Decl(D), Protocols(Protos, Protos+NumP) { } + PointeeType(T), Protocols(Protos, Protos+NumP) { } friend class ASTContext; // ASTContext creates these. public: - ObjCInterfaceDecl *getDecl() const { return Decl; } - + // Get the pointee type. Pointee will either be: + // - a built-in type (for 'id' and 'Class'). + // - an interface type (for user-defined types). + // - a TypedefType whose canonical type is an interface (as in 'T' below). + // For example: typedef NSObject T; T *var; + QualType getPointeeType() const { return PointeeType; } + + const ObjCInterfaceType *getInterfaceType() const { + return PointeeType->getAs<ObjCInterfaceType>(); + } + /// getInterfaceDecl - returns an interface decl for user-defined types. + ObjCInterfaceDecl *getInterfaceDecl() const { + return getInterfaceType() ? getInterfaceType()->getDecl() : 0; + } + /// isObjCIdType - true for "id". + bool isObjCIdType() const { + return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + !Protocols.size(); + } + /// isObjCClassType - true for "Class". + bool isObjCClassType() const { + return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && + !Protocols.size(); + } /// isObjCQualifiedIdType - true for "id <p>". - bool isObjCQualifiedIdType() const { return Decl == 0 && Protocols.size(); } - + bool isObjCQualifiedIdType() const { + return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + Protocols.size(); + } + /// isObjCQualifiedClassType - true for "Class <p>". + bool isObjCQualifiedClassType() const { + return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && + Protocols.size(); + } /// qual_iterator and friends: this provides access to the (potentially empty) /// list of protocols qualifying this interface. typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; @@ -1746,156 +2553,198 @@ public: /// interface type, or 0 if there are none. unsigned getNumProtocols() const { return Protocols.size(); } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, ObjCProtocolDecl **protocols, unsigned NumProtocols); - virtual void getAsStringInternal(std::string &InnerString, + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCObjectPointer; + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObjectPointer; } static bool classof(const ObjCObjectPointerType *) { return true; } }; - -/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for -/// object oriented design. They basically correspond to C++ classes. There -/// are two kinds of interface types, normal interfaces like "NSString" and -/// qualified interfaces, which are qualified with a protocol list like -/// "NSString<NSCopyable, NSAmazing>". Qualified interface types are instances -/// of ObjCQualifiedInterfaceType, which is a subclass of ObjCInterfaceType. -class ObjCInterfaceType : public Type { - ObjCInterfaceDecl *Decl; -protected: - ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) : - Type(tc, QualType(), /*Dependent=*/false), Decl(D) { } - friend class ASTContext; // ASTContext creates these. -public: - - ObjCInterfaceDecl *getDecl() const { return Decl; } - - /// qual_iterator and friends: this provides access to the (potentially empty) - /// list of protocols qualifying this interface. If this is an instance of - /// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an - /// empty list if there are no qualifying protocols. - typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; - inline qual_iterator qual_begin() const; - inline qual_iterator qual_end() const; - bool qual_empty() const { return getTypeClass() != ObjCQualifiedInterface; } - - /// getNumProtocols - Return the number of qualifying protocols in this - /// interface type, or 0 if there are none. - inline unsigned getNumProtocols() const; - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCInterface || - T->getTypeClass() == ObjCQualifiedInterface; - } - static bool classof(const ObjCInterfaceType *) { return true; } -}; -/// ObjCQualifiedInterfaceType - This class represents interface types -/// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>. +/// \brief An ObjC Protocol list that qualifies a type. /// -/// Duplicate protocols are removed and protocol list is canonicalized to be in -/// alphabetical order. -class ObjCQualifiedInterfaceType : public ObjCInterfaceType, - public llvm::FoldingSetNode { - - // List of protocols for this protocol conforming object type - // List is sorted on protocol name. No protocol is enterred more than once. +/// This is used only for keeping detailed type source information, it should +/// not participate in the semantics of the type system. +/// The protocol list is not canonicalized. +class ObjCProtocolListType : public Type, public llvm::FoldingSetNode { + QualType BaseType; + + // List of protocols for this protocol conforming object type. llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; - ObjCQualifiedInterfaceType(ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP) : - ObjCInterfaceType(ObjCQualifiedInterface, D), - Protocols(Protos, Protos+NumP) { } + ObjCProtocolListType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCProtocolList, QualType(), /*Dependent=*/false), + BaseType(T), Protocols(Protos, Protos+NumP) { } friend class ASTContext; // ASTContext creates these. + public: - - unsigned getNumProtocols() const { - return Protocols.size(); - } + QualType getBaseType() const { return BaseType; } + + /// \brief Provides access to the list of protocols qualifying the base type. + typedef llvm::SmallVector<ObjCProtocolDecl*, 4>::const_iterator qual_iterator; qual_iterator qual_begin() const { return Protocols.begin(); } qual_iterator qual_end() const { return Protocols.end(); } - - virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; - + bool qual_empty() const { return Protocols.size() == 0; } + + /// \brief Return the number of qualifying protocols. + unsigned getNumProtocols() const { return Protocols.size(); } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, ObjCProtocolDecl **protocols, unsigned NumProtocols); - - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCQualifiedInterface; + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCProtocolList; } - static bool classof(const ObjCQualifiedInterfaceType *) { return true; } + static bool classof(const ObjCProtocolListType *) { return true; } }; - -inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_begin() const { - if (const ObjCQualifiedInterfaceType *QIT = - dyn_cast<ObjCQualifiedInterfaceType>(this)) - return QIT->qual_begin(); - return 0; + +/// A qualifier set is used to build a set of qualifiers. +class QualifierCollector : public Qualifiers { + ASTContext *Context; + +public: + QualifierCollector(Qualifiers Qs = Qualifiers()) + : Qualifiers(Qs), Context(0) {} + QualifierCollector(ASTContext &Context, Qualifiers Qs = Qualifiers()) + : Qualifiers(Qs), Context(&Context) {} + + void setContext(ASTContext &C) { Context = &C; } + + /// Collect any qualifiers on the given type and return an + /// unqualified type. + const Type *strip(QualType QT) { + addFastQualifiers(QT.getFastQualifiers()); + if (QT.hasNonFastQualifiers()) { + const ExtQuals *EQ = QT.getExtQualsUnsafe(); + Context = &EQ->getContext(); + addQualifiers(EQ->getQualifiers()); + return EQ->getBaseType(); + } + return QT.getTypePtrUnsafe(); + } + + /// Apply the collected qualifiers to the given type. + QualType apply(QualType QT) const; + + /// Apply the collected qualifiers to the given type. + QualType apply(const Type* T) const; + +}; + + +// Inline function definitions. + +inline void QualType::removeConst() { + removeFastQualifiers(Qualifiers::Const); } -inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_end() const { - if (const ObjCQualifiedInterfaceType *QIT = - dyn_cast<ObjCQualifiedInterfaceType>(this)) - return QIT->qual_end(); - return 0; + +inline void QualType::removeRestrict() { + removeFastQualifiers(Qualifiers::Restrict); } -/// getNumProtocols - Return the number of qualifying protocols in this -/// interface type, or 0 if there are none. -inline unsigned ObjCInterfaceType::getNumProtocols() const { - if (const ObjCQualifiedInterfaceType *QIT = - dyn_cast<ObjCQualifiedInterfaceType>(this)) - return QIT->getNumProtocols(); - return 0; +inline void QualType::removeVolatile() { + QualifierCollector Qc; + const Type *Ty = Qc.strip(*this); + if (Qc.hasVolatile()) { + Qc.removeVolatile(); + *this = Qc.apply(Ty); + } } -// Inline function definitions. +inline void QualType::removeCVRQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); + + // Fast path: we don't need to touch the slow qualifiers. + if (!(Mask & ~Qualifiers::FastMask)) { + removeFastQualifiers(Mask); + return; + } -/// getUnqualifiedType - Return the type without any qualifiers. -inline QualType QualType::getUnqualifiedType() const { - Type *TP = getTypePtr(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(TP)) - TP = EXTQT->getBaseType(); - return QualType(TP, 0); + QualifierCollector Qc; + const Type *Ty = Qc.strip(*this); + Qc.removeCVRQualifiers(Mask); + *this = Qc.apply(Ty); } /// getAddressSpace - Return the address space of this type. inline unsigned QualType::getAddressSpace() const { + if (hasNonFastQualifiers()) { + const ExtQuals *EQ = getExtQualsUnsafe(); + if (EQ->hasAddressSpace()) + return EQ->getAddressSpace(); + } + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (CT.hasNonFastQualifiers()) { + const ExtQuals *EQ = CT.getExtQualsUnsafe(); + if (EQ->hasAddressSpace()) + return EQ->getAddressSpace(); + } + if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) return AT->getElementType().getAddressSpace(); if (const RecordType *RT = dyn_cast<RecordType>(CT)) return RT->getAddressSpace(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT)) - return EXTQT->getAddressSpace(); return 0; } /// getObjCGCAttr - Return the gc attribute of this type. -inline QualType::GCAttrTypes QualType::getObjCGCAttr() const { +inline Qualifiers::GC QualType::getObjCGCAttr() const { + if (hasNonFastQualifiers()) { + const ExtQuals *EQ = getExtQualsUnsafe(); + if (EQ->hasObjCGCAttr()) + return EQ->getObjCGCAttr(); + } + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (CT.hasNonFastQualifiers()) { + const ExtQuals *EQ = CT.getExtQualsUnsafe(); + if (EQ->hasObjCGCAttr()) + return EQ->getObjCGCAttr(); + } + if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) return AT->getElementType().getObjCGCAttr(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT)) - return EXTQT->getObjCGCAttr(); - if (const PointerType *PT = CT->getAsPointerType()) - return PT->getPointeeType().getObjCGCAttr(); - return GCNone; + if (const ObjCObjectPointerType *PT = CT->getAs<ObjCObjectPointerType>()) + return PT->getPointeeType().getObjCGCAttr(); + // We most look at all pointer types, not just pointer to interface types. + if (const PointerType *PT = CT->getAs<PointerType>()) + return PT->getPointeeType().getObjCGCAttr(); + return Qualifiers::GCNone; +} + + /// getNoReturnAttr - Returns true if the type has the noreturn attribute, + /// false otherwise. +inline bool QualType::getNoReturnAttr() const { + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) { + if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>()) + return FT->getNoReturnAttr(); + } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>()) + return FT->getNoReturnAttr(); + + return false; } - + /// isMoreQualifiedThan - Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and /// "int". However, it is not more qualified than "const volatile /// int". inline bool QualType::isMoreQualifiedThan(QualType Other) const { + // FIXME: work on arbitrary qualifiers unsigned MyQuals = this->getCVRQualifiers(); unsigned OtherQuals = Other.getCVRQualifiers(); if (getAddressSpace() != Other.getAddressSpace()) @@ -1908,6 +2757,7 @@ inline bool QualType::isMoreQualifiedThan(QualType Other) const { /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const { + // FIXME: work on arbitrary qualifiers unsigned MyQuals = this->getCVRQualifiers(); unsigned OtherQuals = Other.getCVRQualifiers(); if (getAddressSpace() != Other.getAddressSpace()) @@ -1925,31 +2775,31 @@ inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const { /// analysis, the expression designates the object or function /// denoted by the reference, and the expression is an lvalue. inline QualType QualType::getNonReferenceType() const { - if (const ReferenceType *RefType = (*this)->getAsReferenceType()) + if (const ReferenceType *RefType = (*this)->getAs<ReferenceType>()) return RefType->getPointeeType(); else return *this; } -inline const TypedefType* Type::getAsTypedefType() const { - return dyn_cast<TypedefType>(this); -} inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { - if (const PointerType *PT = getAsPointerType()) - return PT->getPointeeType()->getAsObjCInterfaceType(); + if (const PointerType *PT = getAs<PointerType>()) + return PT->getPointeeType()->getAs<ObjCInterfaceType>(); return 0; } - + // NOTE: All of these methods use "getUnqualifiedType" to strip off address // space qualifiers if present. inline bool Type::isFunctionType() const { return isa<FunctionType>(CanonicalType.getUnqualifiedType()); } inline bool Type::isPointerType() const { - return isa<PointerType>(CanonicalType.getUnqualifiedType()); + return isa<PointerType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isAnyPointerType() const { + return isPointerType() || isObjCObjectPointerType(); } inline bool Type::isBlockPointerType() const { - return isa<BlockPointerType>(CanonicalType.getUnqualifiedType()); + return isa<BlockPointerType>(CanonicalType.getUnqualifiedType()); } inline bool Type::isReferenceType() const { return isa<ReferenceType>(CanonicalType.getUnqualifiedType()); @@ -1961,7 +2811,7 @@ inline bool Type::isRValueReferenceType() const { return isa<RValueReferenceType>(CanonicalType.getUnqualifiedType()); } inline bool Type::isFunctionPointerType() const { - if (const PointerType* T = getAsPointerType()) + if (const PointerType* T = getAs<PointerType>()) return T->getPointeeType()->isFunctionType(); else return false; @@ -1970,7 +2820,7 @@ inline bool Type::isMemberPointerType() const { return isa<MemberPointerType>(CanonicalType.getUnqualifiedType()); } inline bool Type::isMemberFunctionPointerType() const { - if (const MemberPointerType* T = getAsMemberPointerType()) + if (const MemberPointerType* T = getAs<MemberPointerType>()) return T->getPointeeType()->isFunctionType(); else return false; @@ -2008,21 +2858,35 @@ inline bool Type::isObjCObjectPointerType() const { inline bool Type::isObjCInterfaceType() const { return isa<ObjCInterfaceType>(CanonicalType.getUnqualifiedType()); } -inline bool Type::isObjCQualifiedInterfaceType() const { - return isa<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType()); -} inline bool Type::isObjCQualifiedIdType() const { - if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) return OPT->isObjCQualifiedIdType(); - } return false; } +inline bool Type::isObjCQualifiedClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedClassType(); + return false; +} +inline bool Type::isObjCIdType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCIdType(); + return false; +} +inline bool Type::isObjCClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCClassType(); + return false; +} +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType(); +} inline bool Type::isTemplateTypeParmType() const { return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType()); } inline bool Type::isSpecificBuiltinType(unsigned K) const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs<BuiltinType>()) if (BT->getKind() == (BuiltinType::Kind) K) return true; return false; @@ -2036,12 +2900,12 @@ inline bool Type::isOverloadableType() const { inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || - isObjCInterfaceType() || isObjCQualifiedIdType() || + isObjCInterfaceType() || isObjCObjectPointerType() || isObjCQualifiedInterfaceType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { - return (isObjCInterfaceType() || isObjCQualifiedIdType() || + return (isObjCInterfaceType() || isObjCObjectPointerType() || isObjCQualifiedInterfaceType()); } @@ -2054,6 +2918,21 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } +/// Member-template getAs<specific type>'. +template <typename T> const T *Type::getAs() const { + // If this is directly a T type, return it. + if (const T *Ty = dyn_cast<T>(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<T>(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<T>(getUnqualifiedDesugaredType()); +} + } // end namespace clang #endif diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h new file mode 100644 index 000000000000..a6184375e095 --- /dev/null +++ b/include/clang/AST/TypeLoc.h @@ -0,0 +1,538 @@ +//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- 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 the TypeLoc interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPELOC_H +#define LLVM_CLANG_AST_TYPELOC_H + +#include "clang/AST/Type.h" + +namespace clang { + class ParmVarDecl; + class TypeSpecLoc; + class DeclaratorInfo; + +/// \brief Base wrapper for a particular "section" of type source info. +/// +/// A client should use the TypeLoc subclasses through cast/dyn_cast in order to +/// get at the actual information. +class TypeLoc { +protected: + QualType Ty; + void *Data; + +public: + TypeLoc() : Data(0) { } + TypeLoc(QualType ty, void *opaqueData) : Ty(ty), Data(opaqueData) { } + + bool isNull() const { return Ty.isNull(); } + operator bool() const { return !isNull(); } + + /// \brief Returns the size of type source info data block for the given type. + static unsigned getFullDataSizeForType(QualType Ty); + + /// \brief Get the type for which this source info wrapper provides + /// information. + QualType getSourceType() const { return Ty; } + + /// \brief Get the pointer where source information is stored. + void *getOpaqueData() const { return Data; } + + SourceRange getSourceRange() const; + + /// \brief Find the TypeSpecLoc that is part of this TypeLoc. + TypeSpecLoc getTypeSpecLoc() const; + + /// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its + /// SourceRange. + SourceRange getTypeSpecRange() const; + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const; + + /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the + /// TypeLoc is a PointerLoc and next TypeLoc is for "int". + TypeLoc getNextTypeLoc() const; + + friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { + return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data; + } + + friend bool operator!=(const TypeLoc &LHS, const TypeLoc &RHS) { + return !(LHS == RHS); + } + + static bool classof(const TypeLoc *TL) { return true; } +}; + +/// \brief Base wrapper of type source info data for type-spec types. +class TypeSpecLoc : public TypeLoc { +public: + static bool classof(const TypeLoc *TL); + static bool classof(const TypeSpecLoc *TL) { return true; } +}; + +/// \brief Base wrapper of type source info data for types part of a declarator, +/// excluding type-spec types. +class DeclaratorLoc : public TypeLoc { +public: + /// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. + TypeSpecLoc getTypeSpecLoc() const; + + static bool classof(const TypeLoc *TL); + static bool classof(const DeclaratorLoc *TL) { return true; } +}; + +/// \brief The default wrapper for type-spec types that are not handled by +/// another specific wrapper. +class DefaultTypeSpecLoc : public TypeSpecLoc { + struct Info { + SourceLocation StartLoc; + }; + +public: + SourceLocation getStartLoc() const { + return static_cast<Info*>(Data)->StartLoc; + } + void setStartLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->StartLoc = Loc; + } + SourceRange getSourceRange() const { + return SourceRange(getStartLoc(), getStartLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { return getLocalDataSize(); } + + static bool classof(const TypeLoc *TL); + static bool classof(const DefaultTypeSpecLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for typedefs. +class TypedefLoc : public TypeSpecLoc { + struct Info { + SourceLocation NameLoc; + }; + +public: + SourceLocation getNameLoc() const { + return static_cast<Info*>(Data)->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->NameLoc = Loc; + } + SourceRange getSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + + TypedefDecl *getTypedefDecl() const { + return cast<TypedefType>(Ty)->getDecl(); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { return getLocalDataSize(); } + + static bool classof(const TypeLoc *TL); + static bool classof(const TypedefLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for ObjC interfaces. +class ObjCInterfaceLoc : public TypeSpecLoc { + struct Info { + SourceLocation NameLoc; + }; + +public: + SourceLocation getNameLoc() const { + return static_cast<Info*>(Data)->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->NameLoc = Loc; + } + SourceRange getSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + + ObjCInterfaceDecl *getIFaceDecl() const { + return cast<ObjCInterfaceType>(Ty)->getDecl(); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { return getLocalDataSize(); } + + static bool classof(const TypeLoc *TL); + static bool classof(const TypedefLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for ObjC protocol lists. +class ObjCProtocolListLoc : public TypeSpecLoc { + struct Info { + SourceLocation LAngleLoc, RAngleLoc; + }; + // SourceLocations are stored after Info, one for each Protocol. + SourceLocation *getProtocolLocArray() const { + return reinterpret_cast<SourceLocation*>(static_cast<Info*>(Data) + 1); + } + +public: + SourceLocation getLAngleLoc() const { + return static_cast<Info*>(Data)->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return static_cast<Info*>(Data)->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->RAngleLoc = Loc; + } + + unsigned getNumProtocols() const { + return cast<ObjCProtocolListType>(Ty)->getNumProtocols(); + } + + SourceLocation getProtocolLoc(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return getProtocolLocArray()[i]; + } + void setProtocolLoc(unsigned i, SourceLocation Loc) { + assert(i < getNumProtocols() && "Index is out of bounds!"); + getProtocolLocArray()[i] = Loc; + } + + ObjCProtocolDecl *getProtocol(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return *(cast<ObjCProtocolListType>(Ty)->qual_begin() + i); + } + + TypeLoc getBaseTypeLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<ObjCProtocolListType>(Ty)->getBaseType(), Next); + } + + SourceRange getSourceRange() const { + return SourceRange(getLAngleLoc(), getRAngleLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { + return sizeof(Info) + getNumProtocols() * sizeof(SourceLocation); + } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getBaseTypeLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const ObjCProtocolListLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for pointers. +class PointerLoc : public DeclaratorLoc { + struct Info { + SourceLocation StarLoc; + }; + +public: + SourceLocation getStarLoc() const { + return static_cast<Info*>(Data)->StarLoc; + } + void setStarLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<PointerType>(Ty)->getPointeeType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this PointerLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getPointeeLoc().getTypeSpecLoc(); + } + + SourceRange getSourceRange() const { + return SourceRange(getStarLoc(), getStarLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getPointeeLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const PointerLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for block pointers. +class BlockPointerLoc : public DeclaratorLoc { + struct Info { + SourceLocation CaretLoc; + }; + +public: + SourceLocation getCaretLoc() const { + return static_cast<Info*>(Data)->CaretLoc; + } + void setCaretLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->CaretLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<BlockPointerType>(Ty)->getPointeeType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this BlockPointerLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getPointeeLoc().getTypeSpecLoc(); + } + + SourceRange getSourceRange() const { + return SourceRange(getCaretLoc(), getCaretLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getPointeeLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const BlockPointerLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for member pointers. +class MemberPointerLoc : public DeclaratorLoc { + struct Info { + SourceLocation StarLoc; + }; + +public: + SourceLocation getStarLoc() const { + return static_cast<Info*>(Data)->StarLoc; + } + void setStarLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<MemberPointerType>(Ty)->getPointeeType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this MemberPointerLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getPointeeLoc().getTypeSpecLoc(); + } + + SourceRange getSourceRange() const { + return SourceRange(getStarLoc(), getStarLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getPointeeLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const MemberPointerLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for references. +class ReferenceLoc : public DeclaratorLoc { + struct Info { + SourceLocation AmpLoc; + }; + +public: + SourceLocation getAmpLoc() const { + return static_cast<Info*>(Data)->AmpLoc; + } + void setAmpLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->AmpLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<ReferenceType>(Ty)->getPointeeType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this ReferenceLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getPointeeLoc().getTypeSpecLoc(); + } + + SourceRange getSourceRange() const { + return SourceRange(getAmpLoc(), getAmpLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getPointeeLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const ReferenceLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for functions. +class FunctionLoc : public DeclaratorLoc { + struct Info { + SourceLocation LParenLoc, RParenLoc; + }; + // ParmVarDecls* are stored after Info, one for each argument. + ParmVarDecl **getParmArray() const { + return reinterpret_cast<ParmVarDecl**>(static_cast<Info*>(Data) + 1); + } + +public: + SourceLocation getLParenLoc() const { + return static_cast<Info*>(Data)->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return static_cast<Info*>(Data)->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->RParenLoc = Loc; + } + + unsigned getNumArgs() const { + if (isa<FunctionNoProtoType>(Ty)) + return 0; + return cast<FunctionProtoType>(Ty)->getNumArgs(); + } + ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; } + void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; } + + TypeLoc getArgLoc(unsigned i) const; + + TypeLoc getResultLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<FunctionType>(Ty)->getResultType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this FunctionLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getResultLoc().getTypeSpecLoc(); + } + SourceRange getSourceRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { + return sizeof(Info) + getNumArgs() * sizeof(ParmVarDecl*); + } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getResultLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const FunctionLoc *TL) { return true; } +}; + +/// \brief Wrapper for source info for arrays. +class ArrayLoc : public DeclaratorLoc { + struct Info { + SourceLocation LBracketLoc, RBracketLoc; + Expr *Size; + }; +public: + SourceLocation getLBracketLoc() const { + return static_cast<Info*>(Data)->LBracketLoc; + } + void setLBracketLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->LBracketLoc = Loc; + } + + SourceLocation getRBracketLoc() const { + return static_cast<Info*>(Data)->RBracketLoc; + } + void setRBracketLoc(SourceLocation Loc) { + static_cast<Info*>(Data)->RBracketLoc = Loc; + } + + Expr *getSizeExpr() const { + return static_cast<Info*>(Data)->Size; + } + void setSizeExpr(Expr *Size) { + static_cast<Info*>(Data)->Size = Size; + } + + TypeLoc getElementLoc() const { + void *Next = static_cast<char*>(Data) + getLocalDataSize(); + return TypeLoc(cast<ArrayType>(Ty)->getElementType(), Next); + } + + /// \brief Find the TypeSpecLoc that is part of this ArrayLoc. + TypeSpecLoc getTypeSpecLoc() const { + return getElementLoc().getTypeSpecLoc(); + } + SourceRange getSourceRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { return sizeof(Info); } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + getElementLoc().getFullDataSize(); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const ArrayLoc *TL) { return true; } +}; + +} + +#endif diff --git a/include/clang/AST/TypeLocNodes.def b/include/clang/AST/TypeLocNodes.def new file mode 100644 index 000000000000..107ea85479f9 --- /dev/null +++ b/include/clang/AST/TypeLocNodes.def @@ -0,0 +1,55 @@ +//===-- TypeLocNodes.def - Metadata about TypeLoc wrappers ------*- 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 the TypeLoc info database. Each node is +// enumerated by providing its name (e.g., "PointerLoc" or "ArrayLoc"), +// base class (e.g., "TypeSpecLoc" or "DeclaratorLoc"), and the Type subclass +// that the TypeLoc is associated with. +// +// TYPELOC(Class, Base, Type) - Description of the TypeLoc subclass. +// +// ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc. +// +// TYPESPEC_TYPELOC(Class, Type) - A TypeLoc referring to a type-spec type. +// +// DECLARATOR_TYPELOC(Class, Type) - A TypeLoc referring to a type part of +// a declarator, excluding type-spec types. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPELOC +# define ABSTRACT_TYPELOC(Class) TYPELOC(Class, TypeLoc, Type) +#endif + +#ifndef TYPESPEC_TYPELOC +# define TYPESPEC_TYPELOC(Class, Type) TYPELOC(Class, TypeSpecLoc, Type) +#endif + +#ifndef DECLARATOR_TYPELOC +# define DECLARATOR_TYPELOC(Class, Type) TYPELOC(Class, DeclaratorLoc, Type) +#endif + +TYPESPEC_TYPELOC(DefaultTypeSpecLoc, Type) +TYPESPEC_TYPELOC(TypedefLoc, TypedefType) +TYPESPEC_TYPELOC(ObjCInterfaceLoc, ObjCInterfaceType) +TYPESPEC_TYPELOC(ObjCProtocolListLoc, ObjCProtocolListType) +DECLARATOR_TYPELOC(PointerLoc, PointerType) +DECLARATOR_TYPELOC(BlockPointerLoc, BlockPointerType) +DECLARATOR_TYPELOC(MemberPointerLoc, MemberPointerType) +DECLARATOR_TYPELOC(ReferenceLoc, ReferenceType) +DECLARATOR_TYPELOC(FunctionLoc, FunctionType) +DECLARATOR_TYPELOC(ArrayLoc, ArrayType) +ABSTRACT_TYPELOC(DeclaratorLoc) +ABSTRACT_TYPELOC(TypeSpecLoc) + + +#undef DECLARATOR_TYPELOC +#undef TYPESPEC_TYPELOC +#undef ABSTRACT_TYPELOC +#undef TYPELOC diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h new file mode 100644 index 000000000000..df386cab6f42 --- /dev/null +++ b/include/clang/AST/TypeLocVisitor.h @@ -0,0 +1,58 @@ +//===--- TypeLocVisitor.h - Visitor for TypeLoc subclasses ------*- 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 the TypeLocVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_TYPELOCVISITOR_H +#define LLVM_CLANG_AST_TYPELOCVISITOR_H + +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeVisitor.h" + +namespace clang { + +#define DISPATCH(CLASS) \ + return static_cast<ImplClass*>(this)->Visit ## CLASS(cast<CLASS>(TyLoc)) + +template<typename ImplClass, typename RetTy=void> +class TypeLocVisitor { + class TypeDispatch : public TypeVisitor<TypeDispatch, RetTy> { + ImplClass *Impl; + TypeLoc TyLoc; + + public: + TypeDispatch(ImplClass *impl, TypeLoc &tyLoc) : Impl(impl), TyLoc(tyLoc) { } +#define ABSTRACT_TYPELOC(CLASS) +#define TYPELOC(CLASS, PARENT, TYPE) \ + RetTy Visit##TYPE(TYPE *) { \ + return Impl->Visit##CLASS(reinterpret_cast<CLASS&>(TyLoc)); \ + } +#include "clang/AST/TypeLocNodes.def" + }; + +public: + RetTy Visit(TypeLoc TyLoc) { + TypeDispatch TD(static_cast<ImplClass*>(this), TyLoc); + return TD.Visit(TyLoc.getSourceType().getTypePtr()); + } + +#define TYPELOC(CLASS, PARENT, TYPE) RetTy Visit##CLASS(CLASS TyLoc) { \ + DISPATCH(PARENT); \ +} +#include "clang/AST/TypeLocNodes.def" + + RetTy VisitTypeLoc(TypeLoc TyLoc) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_TYPELOCVISITOR_H diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 64a09d800270..6c6bd20e8528 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -31,6 +31,12 @@ // type that is always dependent. Clients that do not need to deal // with uninstantiated C++ templates can ignore these types. // +// There is a fifth macro, independent of the others. Most clients +// will not need to use it. +// +// LEAF_TYPE(Class) - A type that never has inner types. Clients +// which can operate on such types more efficiently may wish to do so. +// //===----------------------------------------------------------------------===// #ifndef ABSTRACT_TYPE @@ -45,7 +51,6 @@ # define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) #endif -TYPE(ExtQual, Type) TYPE(Builtin, Type) TYPE(FixedWidthInt, Type) TYPE(Complex, Type) @@ -57,6 +62,8 @@ TYPE(RValueReference, ReferenceType) TYPE(MemberPointer, Type) ABSTRACT_TYPE(Array, Type) TYPE(ConstantArray, ArrayType) +NON_CANONICAL_TYPE(ConstantArrayWithExpr, ConstantArrayType) +NON_CANONICAL_TYPE(ConstantArrayWithoutExpr, ConstantArrayType) TYPE(IncompleteArray, ArrayType) TYPE(VariableArray, ArrayType) DEPENDENT_TYPE(DependentSizedArray, ArrayType) @@ -73,13 +80,25 @@ NON_CANONICAL_TYPE(Decltype, Type) ABSTRACT_TYPE(Tag, Type) TYPE(Record, TagType) TYPE(Enum, TagType) +NON_CANONICAL_TYPE(Elaborated, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) TYPE(TemplateSpecialization, Type) NON_CANONICAL_TYPE(QualifiedName, Type) DEPENDENT_TYPE(Typename, Type) TYPE(ObjCInterface, Type) TYPE(ObjCObjectPointer, Type) -TYPE(ObjCQualifiedInterface, ObjCInterfaceType) +NON_CANONICAL_TYPE(ObjCProtocolList, Type) + +// These types are always leaves in the type hierarchy. +#ifdef LEAF_TYPE +LEAF_TYPE(Enum) +LEAF_TYPE(Builtin) +LEAF_TYPE(FixedWidthInt) +LEAF_TYPE(ObjCInterface) +LEAF_TYPE(ObjCObjectPointer) +LEAF_TYPE(TemplateTypeParm) +#undef LEAF_TYPE +#endif #undef DEPENDENT_TYPE #undef NON_CANONICAL_TYPE diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h index 4f60273d6809..652f4f70bd16 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -37,7 +37,7 @@ namespace llvm { template<> struct DenseMapInfo<clang::QualType> { static inline clang::QualType getEmptyKey() { return clang::QualType(); } - static inline clang::QualType getTombstoneKey() { + static inline clang::QualType getTombstoneKey() { using clang::QualType; return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); } @@ -51,11 +51,11 @@ namespace llvm { return LHS == RHS; } - static bool isPod() { + static bool isPod() { // QualType isn't *technically* a POD type. However, we can get // away with calling it a POD type since its copy constructor, // copy assignment operator, and destructor are all trivial. - return true; + return true; } }; } diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h index a02e39b3f34e..19f7f42a897a 100644 --- a/include/clang/AST/TypeVisitor.h +++ b/include/clang/AST/TypeVisitor.h @@ -17,10 +17,10 @@ #include "clang/AST/Type.h" namespace clang { - + #define DISPATCH(CLASS) \ return static_cast<ImplClass*>(this)->Visit ## CLASS(static_cast<CLASS*>(T)) - + template<typename ImplClass, typename RetTy=void> class TypeVisitor { public: @@ -28,15 +28,17 @@ public: // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. switch (T->getTypeClass()) { default: assert(0 && "Unknown type class!"); -#define ABSTRACT_TYPE(CLASS, PARENT) +#define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type); #include "clang/AST/TypeNodes.def" } } - + // If the implementation chooses not to implement a certain visit method, fall // back on superclass. -#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { DISPATCH(PARENT); } +#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { \ + DISPATCH(PARENT); \ +} #include "clang/AST/TypeNodes.def" // Base case, ignore it. :) diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index b41cd684e951..17f772da0c6d 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -23,7 +23,7 @@ namespace clang { class Stmt; class DeclRefExpr; class SourceManager; - + struct LiveVariables_ValueTypes { struct ObserverTy; @@ -35,77 +35,77 @@ struct LiveVariables_ValueTypes { // (so that we don't explore such expressions twice). We also want // to compute liveness information for block-level expressions, since these // act as "temporary" values. - + struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { ObserverTy* Observer; ValTy AlwaysLive; - + AnalysisDataTy() : Observer(NULL) {} }; - + //===-----------------------------------------------------===// // ObserverTy - Observer for uninitialized values queries. //===-----------------------------------------------------===// struct ObserverTy { virtual ~ObserverTy() {} - + /// ObserveStmt - A callback invoked right before invoking the /// liveness transfer function on the given statement. - virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD, + virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD, const ValTy& V) {} - + virtual void ObserverKill(DeclRefExpr* DR) {} }; }; class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, dataflow::backward_analysis_tag> { - - + + public: typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; - + LiveVariables(ASTContext& Ctx, CFG& cfg); - + /// IsLive - Return true if a variable is live at beginning of a /// specified block. bool isLive(const CFGBlock* B, const VarDecl* D) const; - + /// IsLive - Returns true if a variable is live at the beginning of the /// the statement. This query only works if liveness information /// has been recorded at the statement level (see runOnAllBlocks), and /// only returns liveness information for block-level expressions. bool isLive(const Stmt* S, const VarDecl* D) const; - + /// IsLive - Returns true the block-level expression "value" is live /// before the given block-level expression (see runOnAllBlocks). bool isLive(const Stmt* Loc, const Stmt* StmtVal) const; - + /// IsLive - Return true if a variable is live according to the /// provided livness bitvector. bool isLive(const ValTy& V, const VarDecl* D) const; - + /// dumpLiveness - Print to stderr the liveness information encoded /// by a specified bitvector. void dumpLiveness(const ValTy& V, SourceManager& M) const; - + /// dumpBlockLiveness - Print to stderr the liveness information /// associated with each basic block. void dumpBlockLiveness(SourceManager& M) const; - + /// getNumDecls - Return the number of variables (declarations) that /// whose liveness status is being tracked by the dataflow /// analysis. unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); } - + /// IntializeValues - This routine can perform extra initialization, but /// for LiveVariables this does nothing since all that logic is in - /// the constructor. + /// the constructor. void InitializeValues(const CFG& cfg) {} - + void runOnCFG(CFG& cfg); - + /// runOnAllBlocks - Propagate the dataflow values once for each block, /// starting from the current dataflow values. 'recordStmtValues' indicates /// whether the method should store dataflow values per each individual diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 7a9da03e4bd2..8a967c3f6edc 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -24,7 +24,7 @@ namespace clang { class Expr; class DeclRefExpr; class VarDecl; - + /// UninitializedValues_ValueTypes - Utility class to wrap type declarations /// for dataflow values and dataflow analysis state for the /// Unitialized Values analysis. @@ -32,39 +32,39 @@ class UninitializedValues_ValueTypes { public: struct ObserverTy; - - struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { + + struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {} virtual ~AnalysisDataTy() {}; - + ObserverTy* Observer; bool FullUninitTaint; }; - + typedef StmtDeclBitVector_Types::ValTy ValTy; - + //===--------------------------------------------------------------------===// // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized // value. //===--------------------------------------------------------------------===// - + struct ObserverTy { virtual ~ObserverTy(); - virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD, + virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD, DeclRefExpr* DR, VarDecl* VD) = 0; - }; + }; }; /// UninitializedValues - Objects of this class encapsulate dataflow analysis /// information regarding what variable declarations in a function are /// potentially unintialized. -class UninitializedValues : - public DataflowValues<UninitializedValues_ValueTypes> { +class UninitializedValues : + public DataflowValues<UninitializedValues_ValueTypes> { public: typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy; UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); } - + /// IntializeValues - Create initial dataflow values and meta data for /// a given CFG. This is intended to be called by the dataflow solver. void InitializeValues(const CFG& cfg); diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index 3ee733518595..114ae74b0c06 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define ANALYSISSTART diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h new file mode 100644 index 000000000000..e6f4cf961be0 --- /dev/null +++ b/include/clang/Analysis/CFG.h @@ -0,0 +1,451 @@ +//===--- CFG.h - Classes for representing and building CFGs------*- 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 the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CFG_H +#define LLVM_CLANG_CFG_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/Allocator.h" +#include "clang/Analysis/Support/BumpVector.h" +#include <cassert> + +namespace llvm { + class raw_ostream; +} +namespace clang { + class Stmt; + class Expr; + class CFG; + class PrinterHelper; + class LangOptions; + class ASTContext; + +/// CFGBlock - Represents a single basic block in a source-level CFG. +/// It consists of: +/// +/// (1) A set of statements/expressions (which may contain subexpressions). +/// (2) A "terminator" statement (not in the set of statements). +/// (3) A list of successors and predecessors. +/// +/// Terminator: The terminator represents the type of control-flow that occurs +/// at the end of the basic block. The terminator is a Stmt* referring to an +/// AST node that has control-flow: if-statements, breaks, loops, etc. +/// If the control-flow is conditional, the condition expression will appear +/// within the set of statements in the block (usually the last statement). +/// +/// Predecessors: the order in the set of predecessors is arbitrary. +/// +/// Successors: the order in the set of successors is NOT arbitrary. We +/// currently have the following orderings based on the terminator: +/// +/// Terminator Successor Ordering +/// ----------------------------------------------------- +/// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS +/// +class CFGBlock { + class StatementList { + typedef BumpVector<Stmt*> ImplTy; + ImplTy Impl; + public: + StatementList(BumpVectorContext &C) : Impl(C, 4) {} + + typedef std::reverse_iterator<ImplTy::iterator> iterator; + typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; + typedef ImplTy::iterator reverse_iterator; + typedef ImplTy::const_iterator const_reverse_iterator; + + void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); } + Stmt *front() const { return Impl.back(); } + Stmt *back() const { return Impl.front(); } + + iterator begin() { return Impl.rbegin(); } + iterator end() { return Impl.rend(); } + const_iterator begin() const { return Impl.rbegin(); } + const_iterator end() const { return Impl.rend(); } + reverse_iterator rbegin() { return Impl.begin(); } + reverse_iterator rend() { return Impl.end(); } + const_reverse_iterator rbegin() const { return Impl.begin(); } + const_reverse_iterator rend() const { return Impl.end(); } + + Stmt* operator[](size_t i) const { + assert(i < Impl.size()); + return Impl[Impl.size() - 1 - i]; + } + + size_t size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + }; + + /// Stmts - The set of statements in the basic block. + StatementList Stmts; + + /// Label - An (optional) label that prefixes the executable + /// statements in the block. When this variable is non-NULL, it is + /// either an instance of LabelStmt or SwitchCase. + Stmt *Label; + + /// Terminator - The terminator for a basic block that + /// indicates the type of control-flow that occurs between a block + /// and its successors. + Stmt *Terminator; + + /// LoopTarget - Some blocks are used to represent the "loop edge" to + /// the start of a loop from within the loop body. This Stmt* will be + /// refer to the loop statement for such blocks (and be null otherwise). + const Stmt *LoopTarget; + + /// BlockID - A numerical ID assigned to a CFGBlock during construction + /// of the CFG. + unsigned BlockID; + + /// Predecessors/Successors - Keep track of the predecessor / successor + /// CFG blocks. + typedef BumpVector<CFGBlock*> AdjacentBlocks; + AdjacentBlocks Preds; + AdjacentBlocks Succs; + +public: + explicit CFGBlock(unsigned blockid, BumpVectorContext &C) + : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + BlockID(blockid), Preds(C, 1), Succs(C, 1) {} + ~CFGBlock() {}; + + // Statement iterators + typedef StatementList::iterator iterator; + typedef StatementList::const_iterator const_iterator; + typedef StatementList::reverse_iterator reverse_iterator; + typedef StatementList::const_reverse_iterator const_reverse_iterator; + + Stmt* front() const { return Stmts.front(); } + Stmt* back() const { return Stmts.back(); } + + iterator begin() { return Stmts.begin(); } + iterator end() { return Stmts.end(); } + const_iterator begin() const { return Stmts.begin(); } + const_iterator end() const { return Stmts.end(); } + + reverse_iterator rbegin() { return Stmts.rbegin(); } + reverse_iterator rend() { return Stmts.rend(); } + const_reverse_iterator rbegin() const { return Stmts.rbegin(); } + const_reverse_iterator rend() const { return Stmts.rend(); } + + unsigned size() const { return Stmts.size(); } + bool empty() const { return Stmts.empty(); } + + Stmt* operator[](size_t i) const { return Stmts[i]; } + + + // CFG iterators + typedef AdjacentBlocks::iterator pred_iterator; + typedef AdjacentBlocks::const_iterator const_pred_iterator; + typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; + + typedef AdjacentBlocks::iterator succ_iterator; + typedef AdjacentBlocks::const_iterator const_succ_iterator; + typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + const_pred_iterator pred_begin() const { return Preds.begin(); } + const_pred_iterator pred_end() const { return Preds.end(); } + + pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); } + pred_reverse_iterator pred_rend() { return Preds.rend(); } + const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } + const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + const_succ_iterator succ_begin() const { return Succs.begin(); } + const_succ_iterator succ_end() const { return Succs.end(); } + + succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); } + succ_reverse_iterator succ_rend() { return Succs.rend(); } + const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } + const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } + + unsigned succ_size() const { return Succs.size(); } + bool succ_empty() const { return Succs.empty(); } + + unsigned pred_size() const { return Preds.size(); } + bool pred_empty() const { return Preds.empty(); } + + // Manipulation of block contents + + void setTerminator(Stmt* Statement) { Terminator = Statement; } + void setLabel(Stmt* Statement) { Label = Statement; } + void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + + Stmt* getTerminator() { return Terminator; } + const Stmt* getTerminator() const { return Terminator; } + + Stmt* getTerminatorCondition(); + + const Stmt* getTerminatorCondition() const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(); + } + + const Stmt *getLoopTarget() const { return LoopTarget; } + + bool hasBinaryBranchTerminator() const; + + Stmt* getLabel() { return Label; } + const Stmt* getLabel() const { return Label; } + + void reverseStmts(); + + unsigned getBlockID() const { return BlockID; } + + void dump(const CFG *cfg, const LangOptions &LO) const; + void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; + void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const; + + void addSuccessor(CFGBlock* Block, BumpVectorContext &C) { + if (Block) + Block->Preds.push_back(this, C); + Succs.push_back(Block, C); + } + + void appendStmt(Stmt* Statement, BumpVectorContext &C) { + Stmts.push_back(Statement, C); + } +}; + + +/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// control-flow of a Stmt. The Stmt can represent an entire function body, +/// or a single expression. A CFG will always contain one empty block that +/// represents the Exit point of the CFG. A CFG will also contain a designated +/// Entry block. The CFG solely represents control-flow; it consists of +/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG +/// was constructed from. +class CFG { +public: + //===--------------------------------------------------------------------===// + // CFG Construction & Manipulation. + //===--------------------------------------------------------------------===// + + /// buildCFG - Builds a CFG from an AST. The responsibility to free the + /// constructed CFG belongs to the caller. + static CFG* buildCFG(Stmt* AST, ASTContext *C); + + /// createBlock - Create a new block in the CFG. The CFG owns the block; + /// the caller should not directly free it. + CFGBlock* createBlock(); + + /// setEntry - Set the entry block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// entry block has no predecessors and contains no statements. + void setEntry(CFGBlock *B) { Entry = B; } + + /// setIndirectGotoBlock - Set the block used for indirect goto jumps. + /// This is typically used only during CFG construction. + void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; } + + //===--------------------------------------------------------------------===// + // Block Iterators + //===--------------------------------------------------------------------===// + + typedef BumpVector<CFGBlock*> CFGBlockListTy; + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + CFGBlock& front() { return *Blocks.front(); } + CFGBlock& back() { return *Blocks.back(); } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + const_iterator begin() const { return Blocks.begin(); } + const_iterator end() const { return Blocks.end(); } + + reverse_iterator rbegin() { return Blocks.rbegin(); } + reverse_iterator rend() { return Blocks.rend(); } + const_reverse_iterator rbegin() const { return Blocks.rbegin(); } + const_reverse_iterator rend() const { return Blocks.rend(); } + + CFGBlock& getEntry() { return *Entry; } + const CFGBlock& getEntry() const { return *Entry; } + CFGBlock& getExit() { return *Exit; } + const CFGBlock& getExit() const { return *Exit; } + + CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; } + + //===--------------------------------------------------------------------===// + // Member templates useful for various batch operations over CFGs. + //===--------------------------------------------------------------------===// + + template <typename CALLBACK> + void VisitBlockStmts(CALLBACK& O) const { + for (const_iterator I=begin(), E=end(); I != E; ++I) + for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); + BI != BE; ++BI) + O(*BI); + } + + //===--------------------------------------------------------------------===// + // CFG Introspection. + //===--------------------------------------------------------------------===// + + struct BlkExprNumTy { + const signed Idx; + explicit BlkExprNumTy(signed idx) : Idx(idx) {} + explicit BlkExprNumTy() : Idx(-1) {} + operator bool() const { return Idx >= 0; } + operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } + }; + + bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + BlkExprNumTy getBlkExprNum(const Stmt* S); + unsigned getNumBlkExprs(); + + /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which + /// start at 0). + unsigned getNumBlockIDs() const { return NumBlockIDs; } + + //===--------------------------------------------------------------------===// + // CFG Debugging: Pretty-Printing and Visualization. + //===--------------------------------------------------------------------===// + + void viewCFG(const LangOptions &LO) const; + void print(llvm::raw_ostream& OS, const LangOptions &LO) const; + void dump(const LangOptions &LO) const; + + //===--------------------------------------------------------------------===// + // Internal: constructors and data. + //===--------------------------------------------------------------------===// + + CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), + BlkExprMap(NULL), Blocks(BlkBVC, 10) {}; + + ~CFG(); + + llvm::BumpPtrAllocator& getAllocator() { + return BlkBVC.getAllocator(); + } + + BumpVectorContext &getBumpVectorContext() { + return BlkBVC; + } + +private: + CFGBlock* Entry; + CFGBlock* Exit; + CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch + // for indirect gotos + unsigned NumBlockIDs; + + // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. + // It represents a map from Expr* to integers to record the set of + // block-level expressions and their "statement number" in the CFG. + void* BlkExprMap; + + BumpVectorContext BlkBVC; + + CFGBlockListTy Blocks; + +}; +} // end namespace clang + +//===----------------------------------------------------------------------===// +// GraphTraits specializations for CFG basic block graphs (source-level CFGs) +//===----------------------------------------------------------------------===// + +namespace llvm { + +// Traits for: CFGBlock + +template <> struct GraphTraits<clang::CFGBlock* > { + typedef clang::CFGBlock NodeType; + typedef clang::CFGBlock::succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<const clang::CFGBlock* > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(const clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +// Traits for: CFG + +template <> struct GraphTraits<clang::CFG* > + : public GraphTraits<clang::CFGBlock* > { + + typedef clang::CFG::iterator nodes_iterator; + + static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits< const clang::CFG* > + : public GraphTraits< const clang::CFGBlock* > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFG*> > + : public GraphTraits<Inverse<const clang::CFGBlock*> > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();} + static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h new file mode 100644 index 000000000000..fabeea38d597 --- /dev/null +++ b/include/clang/Analysis/CallGraph.h @@ -0,0 +1,147 @@ +//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the CallGraph and CallGraphNode classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH +#define LLVM_CLANG_ANALYSIS_CALLGRAPH + +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Entity.h" +#include "clang/Index/Program.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/STLExtras.h" +#include <vector> +#include <map> + +namespace clang { + +class CallGraphNode { + idx::Entity F; + typedef std::pair<idx::ASTLocation, CallGraphNode*> CallRecord; + std::vector<CallRecord> CalledFunctions; + +public: + CallGraphNode(idx::Entity f) : F(f) {} + + typedef std::vector<CallRecord>::iterator iterator; + typedef std::vector<CallRecord>::const_iterator const_iterator; + + iterator begin() { return CalledFunctions.begin(); } + iterator end() { return CalledFunctions.end(); } + const_iterator begin() const { return CalledFunctions.begin(); } + const_iterator end() const { return CalledFunctions.end(); } + + void addCallee(idx::ASTLocation L, CallGraphNode *Node) { + CalledFunctions.push_back(std::make_pair(L, Node)); + } + + bool hasCallee() const { return begin() != end(); } + + std::string getName() const { return F.getPrintableName(); } + + Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); } +}; + +class CallGraph { + /// Program manages all Entities. + idx::Program Prog; + + typedef std::map<idx::Entity, CallGraphNode *> FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// CallerCtx maps a caller to its ASTContext. + llvm::DenseMap<CallGraphNode *, ASTContext *> CallerCtx; + + /// Root node is the 'main' function or 0. + CallGraphNode *Root; + + /// ExternalCallingNode has edges to all external functions. + CallGraphNode *ExternalCallingNode; + +public: + CallGraph(); + ~CallGraph(); + + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + CallGraphNode *getRoot() { return Root; } + + CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; } + + void addTU(ASTUnit &AST); + + idx::Program &getProgram() { return Prog; } + + CallGraphNode *getOrInsertFunction(idx::Entity F); + + Decl *getDecl(CallGraphNode *Node); + + void print(llvm::raw_ostream &os); + void dump(); + + void ViewCallGraph() const; +}; + +} // end clang namespace + +namespace llvm { + +template <> struct GraphTraits<clang::CallGraph> { + typedef clang::CallGraph GraphType; + typedef clang::CallGraphNode NodeType; + + typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy; + typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun; + + typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType; + + static NodeType *getEntryNode(GraphType *CG) { + return CG->getExternalCallingNode(); + } + + static ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static ChildIteratorType child_end(NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + + typedef std::pair<clang::idx::Entity, NodeType*> PairTy; + typedef std::pointer_to_unary_function<PairTy, NodeType*> DerefFun; + + typedef mapped_iterator<GraphType::const_iterator, DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(const GraphType &CG) { + return map_iterator(CG.begin(), DerefFun(CGDeref)); + } + static nodes_iterator nodes_end(const GraphType &CG) { + return map_iterator(CG.end(), DerefFun(CGDeref)); + } + + static NodeType *CGNDeref(CGNPairTy P) { return P.second; } + + static NodeType *CGDeref(PairTy P) { return P.second; } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 38612593368b..f505bca9519c 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER #define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "llvm/ADT/SmallPtrSet.h" #include "functional" // STL @@ -24,7 +24,7 @@ namespace clang { //===----------------------------------------------------------------------===// /// DataflowWorkListTy - Data structure representing the worklist used for /// dataflow algorithms. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// class DataflowWorkListTy { typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; @@ -33,15 +33,15 @@ public: /// enqueue - Add a block to the worklist. Blocks already on the /// worklist are not added a second time. void enqueue(const CFGBlock* B) { wlist.insert(B); } - + /// dequeue - Remove a block from the worklist. const CFGBlock* dequeue() { assert (!wlist.empty()); const CFGBlock* B = *wlist.begin(); wlist.erase(B); - return B; + return B; } - + /// isEmpty - Return true if the worklist is empty. bool isEmpty() const { return wlist.empty(); } }; @@ -59,22 +59,22 @@ template <> struct ItrTraits<forward_analysis_tag> { typedef CFGBlock::const_pred_iterator PrevBItr; typedef CFGBlock::const_succ_iterator NextBItr; typedef CFGBlock::const_iterator StmtItr; - + static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); } static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); } - - static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); } static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); } - + static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); } static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); } - + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { - return BlockEdge(Prev, B); + return BlockEdge(Prev, B, 0); } - + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { - return BlockEdge(B, Next); + return BlockEdge(B, Next, 0); } }; @@ -82,22 +82,22 @@ template <> struct ItrTraits<backward_analysis_tag> { typedef CFGBlock::const_succ_iterator PrevBItr; typedef CFGBlock::const_pred_iterator NextBItr; typedef CFGBlock::const_reverse_iterator StmtItr; - - static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); } + + static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); } static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); } - - static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); } static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); } - + static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); } - static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } - + static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { - return BlockEdge(B, Prev); + return BlockEdge(B, Prev, 0); } - + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { - return BlockEdge(Next, B); + return BlockEdge(Next, B, 0); } }; } // end namespace dataflow @@ -105,7 +105,7 @@ template <> struct ItrTraits<backward_analysis_tag> { //===----------------------------------------------------------------------===// /// DataflowSolverTy - Generic dataflow solver. //===----------------------------------------------------------------------===// - + template <typename _DFValuesTy, // Usually a subclass of DataflowValues typename _TransferFuncsTy, typename _MergeOperatorTy, @@ -120,7 +120,7 @@ public: typedef _DFValuesTy DFValuesTy; typedef _TransferFuncsTy TransferFuncsTy; typedef _MergeOperatorTy MergeOperatorTy; - + typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; typedef typename _DFValuesTy::ValTy ValTy; typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy; @@ -130,24 +130,24 @@ public: typedef typename ItrTraits::NextBItr NextBItr; typedef typename ItrTraits::PrevBItr PrevBItr; typedef typename ItrTraits::StmtItr StmtItr; - + //===----------------------------------------------------===// // External interface: constructing and running the solver. //===----------------------------------------------------===// - + public: DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {} - ~DataflowSolver() {} - + ~DataflowSolver() {} + /// runOnCFG - Computes dataflow values for all blocks in a CFG. void runOnCFG(CFG& cfg, bool recordStmtValues = false) { // Set initial dataflow values and boundary conditions. - D.InitializeValues(cfg); + D.InitializeValues(cfg); // Solve the dataflow equations. This will populate D.EdgeDataMap // with dataflow values. SolveDataflowEquations(cfg, recordStmtValues); } - + /// runOnBlock - Computes dataflow values for a given block. This /// should usually be invoked only after previously computing /// dataflow values using runOnCFG, as runOnBlock is intended to @@ -162,10 +162,10 @@ public: ProcessBlock(B, recordStmtValues, AnalysisDirTag()); } } - + void runOnBlock(const CFGBlock& B, bool recordStmtValues) { runOnBlock(&B, recordStmtValues); - } + } void runOnBlock(CFG::iterator& I, bool recordStmtValues) { runOnBlock(*I, recordStmtValues); } @@ -177,81 +177,87 @@ public: for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) runOnBlock(I, recordStmtValues); } - + //===----------------------------------------------------===// // Internal solver logic. //===----------------------------------------------------===// - + private: - + /// SolveDataflowEquations - Perform the actual worklist algorithm /// to compute dataflow values. void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) { // Enqueue all blocks to ensure the dataflow values are computed // for every block. Not all blocks are guaranteed to reach the exit block. for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) - WorkList.enqueue(&*I); - + WorkList.enqueue(&**I); + while (!WorkList.isEmpty()) { const CFGBlock* B = WorkList.dequeue(); - ProcessMerge(cfg,B); + ProcessMerge(cfg, B); ProcessBlock(B, recordStmtValues, AnalysisDirTag()); - UpdateEdges(cfg,B,TF.getVal()); + UpdateEdges(cfg, B, TF.getVal()); } - } - + } + void ProcessMerge(CFG& cfg, const CFGBlock* B) { - ValTy& V = TF.getVal(); + ValTy& V = TF.getVal(); TF.SetTopValue(V); // Merge dataflow values from all predecessors of this block. MergeOperatorTy Merge; - + EdgeDataMapTy& M = D.getEdgeDataMap(); bool firstMerge = true; - + for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){ + CFGBlock *PrevBlk = *I; + + if (!PrevBlk) + continue; + typename EdgeDataMapTy::iterator EI = - M.find(ItrTraits::PrevEdge(B, *I)); + M.find(ItrTraits::PrevEdge(B, PrevBlk)); if (EI != M.end()) { if (firstMerge) { firstMerge = false; V.copyValues(EI->second); } - else Merge(V,EI->second); + else + Merge(V, EI->second); } } - + // Set the data for the block. D.getBlockDataMap()[B].copyValues(V); - } + } /// ProcessBlock - Process the transfer functions for a given block. void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::forward_analysis_tag) { - + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); - - TF.VisitTerminator(const_cast<CFGBlock*>(B)); + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); } - + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::backward_analysis_tag) { - + TF.VisitTerminator(const_cast<CFGBlock*>(B)); for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); } - + void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { if (record) D.getStmtDataMap()[S] = TF.getVal(); - TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); } - + void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){ TF.BlockStmt_Visit(const_cast<Stmt*>(S)); if (record) D.getStmtDataMap()[S] = TF.getVal(); @@ -263,14 +269,15 @@ private: // forward/backward analysis respectively) void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) { for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) - UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I); + if (CFGBlock *NextBlk = *I) + UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk); } - + /// UpdateEdgeValue - Update the value associated with a given edge. void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) { EdgeDataMapTy& M = D.getEdgeDataMap(); typename EdgeDataMapTy::iterator I = M.find(E); - + if (I == M.end()) { // First computed value for this edge? M[E].copyValues(V); WorkList.enqueue(TargetBlock); @@ -280,7 +287,7 @@ private: WorkList.enqueue(TargetBlock); } } - + private: DFValuesTy& D; DataflowWorkListTy WorkList; diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h index d6427a5cab47..648fe33ab0d4 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowValues.h +++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -16,7 +16,7 @@ #ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES #define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" #include "llvm/ADT/DenseMap.h" @@ -24,7 +24,7 @@ /// Dataflow Directional Tag Classes. These are used for tag dispatching /// within the dataflow solver/transfer functions to determine what direction /// a dataflow analysis flows. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace clang { namespace dataflow { @@ -34,19 +34,19 @@ namespace dataflow { //===----------------------------------------------------------------------===// /// DataflowValues. Container class to store dataflow values for a CFG. -//===----------------------------------------------------------------------===// - +//===----------------------------------------------------------------------===// + template <typename ValueTypes, typename _AnalysisDirTag = dataflow::forward_analysis_tag > class DataflowValues { //===--------------------------------------------------------------------===// // Type declarations. - //===--------------------------------------------------------------------===// + //===--------------------------------------------------------------------===// public: typedef typename ValueTypes::ValTy ValTy; - typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; + typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; typedef _AnalysisDirTag AnalysisDirTag; typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; @@ -60,15 +60,15 @@ public: /// isForwardAnalysis - Returns true if the dataflow values are computed /// from a forward analysis. bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } - + /// isBackwardAnalysis - Returns true if the dataflow values are computed /// from a backward analysis. bool isBackwardAnalysis() { return !isForwardAnalysis(); } - + private: bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } - bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } - + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + //===--------------------------------------------------------------------===// // Initialization and accessors methods. //===--------------------------------------------------------------------===// @@ -76,10 +76,10 @@ private: public: DataflowValues() : StmtDataMap(NULL) {} ~DataflowValues() { delete StmtDataMap; } - + /// InitializeValues - Invoked by the solver to initialize state needed for /// dataflow analysis. This method is usually specialized by subclasses. - void InitializeValues(const CFG& cfg) {}; + void InitializeValues(const CFG& cfg) {}; /// getEdgeData - Retrieves the dataflow values associated with a @@ -89,28 +89,28 @@ public: assert (I != EdgeDataMap.end() && "No data associated with Edge."); return I->second; } - + const ValTy& getEdgeData(const BlockEdge& E) const { return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); - } + } - /// getBlockData - Retrieves the dataflow values associated with a + /// getBlockData - Retrieves the dataflow values associated with a /// specified CFGBlock. If the dataflow analysis is a forward analysis, /// this data is associated with the END of the block. If the analysis - /// is a backwards analysis, it is associated with the ENTRY of the block. + /// is a backwards analysis, it is associated with the ENTRY of the block. ValTy& getBlockData(const CFGBlock* B) { typename BlockDataMapTy::iterator I = BlockDataMap.find(B); assert (I != BlockDataMap.end() && "No data associated with block."); return I->second; } - + const ValTy& getBlockData(const CFGBlock* B) const { return const_cast<DataflowValues*>(this)->getBlockData(B); } - - /// getStmtData - Retrieves the dataflow values associated with a + + /// getStmtData - Retrieves the dataflow values associated with a /// specified Stmt. If the dataflow analysis is a forward analysis, - /// this data corresponds to the point immediately before a Stmt. + /// this data corresponds to the point immediately before a Stmt. /// If the analysis is a backwards analysis, it is associated with /// the point after a Stmt. This data is only computed for block-level /// expressions, and only when requested when the analysis is executed. @@ -120,11 +120,11 @@ public: assert (I != StmtDataMap->end() && "No data associated with statement."); return I->second; } - + const ValTy& getStmtData(const Stmt* S) const { return const_cast<DataflowValues*>(this)->getStmtData(S); } - + /// getEdgeDataMap - Retrieves the internal map between CFG edges and /// dataflow values. Usually used by a dataflow solver to compute /// values for blocks. @@ -138,35 +138,35 @@ public: /// to the dataflow values at the end of the block. BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } - + /// getStmtDataMap - Retrieves the internal map between Stmts and /// dataflow values. StmtDataMapTy& getStmtDataMap() { if (!StmtDataMap) StmtDataMap = new StmtDataMapTy(); return *StmtDataMap; } - + const StmtDataMapTy& getStmtDataMap() const { return const_cast<DataflowValues*>(this)->getStmtDataMap(); } - /// getAnalysisData - Retrieves the meta data associated with a - /// dataflow analysis for analyzing a particular CFG. + /// getAnalysisData - Retrieves the meta data associated with a + /// dataflow analysis for analyzing a particular CFG. /// This is typically consumed by transfer function code (via the solver). /// This can also be used by subclasses to interpret the dataflow values. AnalysisDataTy& getAnalysisData() { return AnalysisData; } const AnalysisDataTy& getAnalysisData() const { return AnalysisData; } - + //===--------------------------------------------------------------------===// // Internal data. //===--------------------------------------------------------------------===// - + protected: EdgeDataMapTy EdgeDataMap; BlockDataMapTy BlockDataMap; StmtDataMapTy* StmtDataMap; AnalysisDataTy AnalysisData; -}; +}; } // end namespace clang #endif diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h index 9ff3f52f89aa..1da15fbae6c4 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -31,23 +31,29 @@ class BugReporter; class ObjCImplementationDecl; class LangOptions; class GRExprEngine; - -void CheckDeadStores(LiveVariables& L, BugReporter& BR); - + +void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, + BugReporter& BR); + void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, bool FullUninitTaint=false); - + GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); - -void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, + const LangOptions& lopts); + +void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L, BugReporter& BR); - -void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); -void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR); - -void RegisterAppleChecks(GRExprEngine& Eng); - + +void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, + BugReporter& BR); + +void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR); + +void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D); + +void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR); + + } // end namespace clang #endif diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h index 994b35e5efda..a08afe2bb90b 100644 --- a/include/clang/Analysis/PathDiagnostic.h +++ b/include/clang/Analysis/PathDiagnostic.h @@ -17,6 +17,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/FoldingSet.h" #include <vector> #include <deque> @@ -24,12 +25,17 @@ #include <algorithm> namespace clang { - + +class Stmt; +class Decl; +class Preprocessor; + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// class PathDiagnostic; + class Stmt; class Decl; class Preprocessor; @@ -38,21 +44,18 @@ class PathDiagnosticClient : public DiagnosticClient { public: PathDiagnosticClient() {} virtual ~PathDiagnosticClient() {} - virtual void SetPreprocessor(Preprocessor *PP) {} - virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info); - virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0; - - enum PathGenerationScheme { Minimal, Extensive }; - virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + + enum PathGenerationScheme { Minimal, Extensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } virtual bool useVerboseDescription() const { return true; } -}; - +}; + //===----------------------------------------------------------------------===// // Path-sensitive diagnostics. //===----------------------------------------------------------------------===// @@ -60,11 +63,11 @@ public: class PathDiagnosticRange : public SourceRange { public: const bool isPoint; - + PathDiagnosticRange(const SourceRange &R, bool isP = false) : SourceRange(R), isPoint(isP) {} }; - + class PathDiagnosticLocation { private: enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; @@ -75,27 +78,27 @@ private: public: PathDiagnosticLocation() : K(SingleLocK), S(0), D(0), SM(0) {} - + PathDiagnosticLocation(FullSourceLoc L) : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} - + PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) : K(StmtK), S(s), D(0), SM(&sm) {} - + PathDiagnosticLocation(SourceRange r, const SourceManager &sm) : K(RangeK), R(r), S(0), D(0), SM(&sm) {} - + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) : K(DeclK), S(0), D(d), SM(&sm) {} - + bool operator==(const PathDiagnosticLocation &X) const { return K == X.K && R == X.R && S == X.S && D == X.D; } - + bool operator!=(const PathDiagnosticLocation &X) const { return K != X.K || R != X.R || S != X.S || D != X.D;; } - + PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { K = X.K; R = X.R; @@ -104,27 +107,29 @@ public: SM = X.SM; return *this; } - + bool isValid() const { return SM != 0; } - + const SourceManager& getSourceManager() const { assert(isValid());return *SM;} - + FullSourceLoc asLocation() const; PathDiagnosticRange asRange() const; const Stmt *asStmt() const { assert(isValid()); return S; } const Decl *asDecl() const { assert(isValid()); return D; } - + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } - + void invalidate() { *this = PathDiagnosticLocation(); } - + void flatten(); - + const SourceManager& getManager() const { assert(isValid()); return *SM; } + + void Profile(llvm::FoldingSetNodeID &ID) const; }; class PathDiagnosticLocationPair { @@ -134,19 +139,24 @@ public: PathDiagnosticLocationPair(const PathDiagnosticLocation &start, const PathDiagnosticLocation &end) : Start(start), End(end) {} - + const PathDiagnosticLocation &getStart() const { return Start; } const PathDiagnosticLocation &getEnd() const { return End; } - + void flatten() { Start.flatten(); End.flatten(); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Start.Profile(ID); + End.Profile(ID); + } }; //===----------------------------------------------------------------------===// // Path "pieces" for path-sensitive diagnostics. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// class PathDiagnosticPiece { public: @@ -159,7 +169,7 @@ private: const Kind kind; const DisplayHint Hint; std::vector<SourceRange> ranges; - + // Do not implement: PathDiagnosticPiece(); PathDiagnosticPiece(const PathDiagnosticPiece &P); @@ -167,42 +177,42 @@ private: protected: PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below); - + PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below); PathDiagnosticPiece(Kind k, DisplayHint hint = Below); - + public: virtual ~PathDiagnosticPiece(); - + const std::string& getString() const { return str; } - + /// getDisplayHint - Return a hint indicating where the diagnostic should /// be displayed by the PathDiagnosticClient. DisplayHint getDisplayHint() const { return Hint; } - + virtual PathDiagnosticLocation getLocation() const = 0; virtual void flattenLocations() = 0; - + Kind getKind() const { return kind; } - + void addRange(SourceRange R) { ranges.push_back(R); } - + void addRange(SourceLocation B, SourceLocation E) { ranges.push_back(SourceRange(B,E)); } - + void addCodeModificationHint(const CodeModificationHint& Hint) { CodeModificationHints.push_back(Hint); } - + typedef const SourceRange* range_iterator; - + range_iterator ranges_begin() const { return ranges.empty() ? NULL : &ranges[0]; } - - range_iterator ranges_end() const { + + range_iterator ranges_end() const { return ranges_begin() + ranges.size(); } @@ -213,15 +223,17 @@ public: } code_modifications_iterator code_modifications_end() const { - return CodeModificationHints.empty()? 0 + return CodeModificationHints.empty()? 0 : &CodeModificationHints[0] + CodeModificationHints.size(); } static inline bool classof(const PathDiagnosticPiece* P) { return true; } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + class PathDiagnosticSpotPiece : public PathDiagnosticPiece { private: PathDiagnosticLocation Pos; @@ -234,30 +246,32 @@ public: assert(Pos.asLocation().isValid() && "PathDiagnosticSpotPiece's must have a valid location."); if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); - } + } PathDiagnosticLocation getLocation() const { return Pos; } virtual void flattenLocations() { Pos.flatten(); } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { public: PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const std::string& s, bool addPosRange = true) : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} - + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s, bool addPosRange = true) : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} - + ~PathDiagnosticEventPiece(); static inline bool classof(const PathDiagnosticPiece* P) { return P->getKind() == Event; } }; - + class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { std::vector<PathDiagnosticLocationPair> LPairs; public: @@ -267,40 +281,40 @@ public: : PathDiagnosticPiece(s, ControlFlow) { LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); } - + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos, const char* s) : PathDiagnosticPiece(s, ControlFlow) { LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); } - + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos) : PathDiagnosticPiece(ControlFlow) { LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); } - + ~PathDiagnosticControlFlowPiece(); - + PathDiagnosticLocation getStartLocation() const { assert(!LPairs.empty() && "PathDiagnosticControlFlowPiece needs at least one location."); return LPairs[0].getStart(); } - + PathDiagnosticLocation getEndLocation() const { assert(!LPairs.empty() && "PathDiagnosticControlFlowPiece needs at least one location."); return LPairs[0].getEnd(); } - + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } - + virtual PathDiagnosticLocation getLocation() const { return getStartLocation(); } - + typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; iterator begin() { return LPairs.begin(); } iterator end() { return LPairs.end(); } @@ -308,7 +322,7 @@ public: virtual void flattenLocations() { for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); } - + typedef std::vector<PathDiagnosticLocationPair>::const_iterator const_iterator; const_iterator begin() const { return LPairs.begin(); } @@ -317,171 +331,177 @@ public: static inline bool classof(const PathDiagnosticPiece* P) { return P->getKind() == ControlFlow; } -}; + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { std::vector<PathDiagnosticPiece*> SubPieces; public: PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) : PathDiagnosticSpotPiece(pos, "", Macro) {} - + ~PathDiagnosticMacroPiece(); - + bool containsEvent() const; void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } - + typedef std::vector<PathDiagnosticPiece*>::iterator iterator; iterator begin() { return SubPieces.begin(); } iterator end() { return SubPieces.end(); } - + virtual void flattenLocations() { PathDiagnosticSpotPiece::flattenLocations(); for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); } - + typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator; const_iterator begin() const { return SubPieces.begin(); } const_iterator end() const { return SubPieces.end(); } - + static inline bool classof(const PathDiagnosticPiece* P) { return P->getKind() == Macro; } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; }; /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, /// each which represent the pieces of the path. -class PathDiagnostic { +class PathDiagnostic : public llvm::FoldingSetNode { std::deque<PathDiagnosticPiece*> path; unsigned Size; std::string BugType; std::string Desc; std::string Category; std::deque<std::string> OtherDesc; - -public: + +public: PathDiagnostic(); - + PathDiagnostic(const char* bugtype, const char* desc, const char* category); - - PathDiagnostic(const std::string& bugtype, const std::string& desc, + + PathDiagnostic(const std::string& bugtype, const std::string& desc, const std::string& category); - + ~PathDiagnostic(); - + const std::string& getDescription() const { return Desc; } const std::string& getBugType() const { return BugType; } - const std::string& getCategory() const { return Category; } - + const std::string& getCategory() const { return Category; } + typedef std::deque<std::string>::const_iterator meta_iterator; meta_iterator meta_begin() const { return OtherDesc.begin(); } meta_iterator meta_end() const { return OtherDesc.end(); } void addMeta(const std::string& s) { OtherDesc.push_back(s); } void addMeta(const char* s) { OtherDesc.push_back(s); } - + PathDiagnosticLocation getLocation() const { assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); return rbegin()->getLocation(); } - + void push_front(PathDiagnosticPiece* piece) { + assert(piece); path.push_front(piece); ++Size; } - + void push_back(PathDiagnosticPiece* piece) { + assert(piece); path.push_back(piece); ++Size; } - + PathDiagnosticPiece* back() { return path.back(); } - + const PathDiagnosticPiece* back() const { return path.back(); } - + unsigned size() const { return Size; } bool empty() const { return Size == 0; } - + void resetPath(bool deletePieces = true); - + class iterator { - public: + public: typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy; - + typedef PathDiagnosticPiece value_type; typedef value_type& reference; typedef value_type* pointer; typedef ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; - + private: ImplTy I; - + public: iterator(const ImplTy& i) : I(i) {} - + bool operator==(const iterator& X) const { return I == X.I; } bool operator!=(const iterator& X) const { return I != X.I; } - + PathDiagnosticPiece& operator*() const { return **I; } PathDiagnosticPiece* operator->() const { return *I; } - + iterator& operator++() { ++I; return *this; } iterator& operator--() { --I; return *this; } }; - + class const_iterator { - public: + public: typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy; - + typedef const PathDiagnosticPiece value_type; typedef value_type& reference; typedef value_type* pointer; typedef ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; - + private: ImplTy I; - + public: const_iterator(const ImplTy& i) : I(i) {} - + bool operator==(const const_iterator& X) const { return I == X.I; } bool operator!=(const const_iterator& X) const { return I != X.I; } - + reference operator*() const { return **I; } pointer operator->() const { return *I; } - + const_iterator& operator++() { ++I; return *this; } const_iterator& operator--() { --I; return *this; } }; - + typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - + // forward iterator creation methods. - + iterator begin() { return path.begin(); } iterator end() { return path.end(); } - + const_iterator begin() const { return path.begin(); } const_iterator end() const { return path.end(); } - + // reverse iterator creation methods. reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin());} - + void flattenLocations() { for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); } -}; - + void Profile(llvm::FoldingSetNodeID &ID) const; +}; } //end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h new file mode 100644 index 000000000000..ffe282d3caa3 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -0,0 +1,167 @@ +//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- 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 AnalysisContext, a class that manages the analysis context +// data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class Decl; +class Stmt; +class CFG; +class LiveVariables; +class ParentMap; +class ImplicitParamDecl; + +/// AnalysisContext contains the context data for the function or method under +/// analysis. +class AnalysisContext { + const Decl *D; + + // AnalysisContext owns the following data. + CFG *cfg; + LiveVariables *liveness; + ParentMap *PM; + +public: + AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {} + ~AnalysisContext(); + + const Decl *getDecl() { return D; } + Stmt *getBody(); + CFG *getCFG(); + ParentMap &getParentMap(); + LiveVariables *getLiveVariables(); + + /// Return the ImplicitParamDecl* associated with 'self' if this + /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. + const ImplicitParamDecl *getSelfDecl() const; +}; + +class AnalysisContextManager { + typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; + ContextMap Contexts; +public: + ~AnalysisContextManager(); + + AnalysisContext *getContext(const Decl *D); +}; + +class LocationContext : public llvm::FoldingSetNode { +public: + enum ContextKind { StackFrame, Scope }; + +private: + ContextKind Kind; + AnalysisContext *Ctx; + const LocationContext *Parent; + +protected: + LocationContext(ContextKind k, AnalysisContext *ctx, + const LocationContext *parent) + : Kind(k), Ctx(ctx), Parent(parent) {} + +public: + ContextKind getKind() const { return Kind; } + + AnalysisContext *getAnalysisContext() const { return Ctx; } + + const LocationContext *getParent() const { return Parent; } + + const Decl *getDecl() const { return getAnalysisContext()->getDecl(); } + + CFG *getCFG() const { return getAnalysisContext()->getCFG(); } + + LiveVariables *getLiveVariables() const { + return getAnalysisContext()->getLiveVariables(); + } + + ParentMap &getParentMap() const { + return getAnalysisContext()->getParentMap(); + } + + const ImplicitParamDecl *getSelfDecl() const { + return Ctx->getSelfDecl(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Kind, Ctx, Parent); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ContextKind k, + AnalysisContext *ctx, const LocationContext *parent); + + static bool classof(const LocationContext*) { return true; } +}; + +class StackFrameContext : public LocationContext { + const Stmt *CallSite; + +public: + StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(StackFrame, ctx, parent), CallSite(s) {} + + Stmt const *getCallSite() const { return CallSite; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), CallSite); + } + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s); + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == StackFrame; + } +}; + +class ScopeContext : public LocationContext { + const Stmt *Enter; + +public: + ScopeContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(Scope, ctx, parent), Enter(s) {} + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), Enter); + } + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s); + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == Scope; + } +}; + +class LocationContextManager { + llvm::FoldingSet<LocationContext> Contexts; + +public: + StackFrameContext *getStackFrame(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s); + + ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s); +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h new file mode 100644 index 000000000000..e97f80576a8b --- /dev/null +++ b/include/clang/Analysis/PathSensitive/AnalysisManager.h @@ -0,0 +1,140 @@ +//== AnalysisManager.h - Path sensitive analysis data manager ------*- 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 the AnalysisManager class that manages the data and policy +// for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H +#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/PathDiagnostic.h" + +namespace clang { + +class AnalysisManager : public BugReporterData { + AnalysisContextManager AnaCtxMgr; + LocationContextManager LocCtxMgr; + + ASTContext &Ctx; + Diagnostic &Diags; + const LangOptions &LangInfo; + + llvm::OwningPtr<PathDiagnosticClient> PD; + + // Configurable components creators. + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + + bool DisplayedFunction; + bool VisualizeEGDot; + bool VisualizeEGUbi; + bool PurgeDead; + + /// EargerlyAssume - A flag indicating how the engine should handle + // expressions such as: 'x = (y != 0)'. When this flag is true then + // the subexpression 'y != 0' will be eagerly assumed to be true or false, + // thus evaluating it to the integers 0 or 1 respectively. The upside + // is that this can increase analysis precision until we have a better way + // to lazily evaluate such logic. The downside is that it eagerly + // bifurcates paths. + bool EagerlyAssume; + bool TrimGraph; + +public: + AnalysisManager(ASTContext &ctx, Diagnostic &diags, + const LangOptions &lang, PathDiagnosticClient *pd, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + bool displayProgress, bool vizdot, bool vizubi, + bool purge, bool eager, bool trim) + + : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + AScope(ScopeDecl), DisplayedFunction(!displayProgress), + VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), + EagerlyAssume(eager), TrimGraph(trim) {} + + StoreManagerCreator getStoreManagerCreator() { + return CreateStoreMgr; + }; + + ConstraintManagerCreator getConstraintManagerCreator() { + return CreateConstraintMgr; + } + + virtual ASTContext &getASTContext() { + return Ctx; + } + + virtual SourceManager &getSourceManager() { + return getASTContext().getSourceManager(); + } + + virtual Diagnostic &getDiagnostic() { + return Diags; + } + + const LangOptions &getLangOptions() const { + return LangInfo; + } + + virtual PathDiagnosticClient *getPathDiagnosticClient() { + return PD.get(); + } + + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } + + bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } + + bool shouldVisualize() const { + return VisualizeEGDot || VisualizeEGUbi; + } + + bool shouldTrimGraph() const { return TrimGraph; } + + bool shouldPurgeDead() const { return PurgeDead; } + + bool shouldEagerlyAssume() const { return EagerlyAssume; } + + void DisplayFunction(Decl *D); + + CFG *getCFG(Decl const *D) { + return AnaCtxMgr.getContext(D)->getCFG(); + } + + LiveVariables *getLiveVariables(Decl const *D) { + return AnaCtxMgr.getContext(D)->getLiveVariables(); + } + + ParentMap &getParentMap(Decl const *D) { + return AnaCtxMgr.getContext(D)->getParentMap(); + } + + // Get the top level stack frame. + StackFrameContext *getStackFrame(Decl const *D) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(Decl const *D, + LocationContext const *Parent, + Stmt const *S) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S); + } +}; + +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h index b694e9b29940..12f0ce2d50b7 100644 --- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine +// of APSInt objects and symbolic constraints used by GRExprEngine // and related classes. // //===----------------------------------------------------------------------===// @@ -24,25 +24,43 @@ #include "llvm/ADT/ImmutableList.h" namespace clang { - + + class GRState; + class CompoundValData : public llvm::FoldingSetNode { QualType T; llvm::ImmutableList<SVal> L; public: - CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) {} typedef llvm::ImmutableList<SVal>::iterator iterator; iterator begin() const { return L.begin(); } - iterator end() const { return L.end(); } - + iterator end() const { return L.end(); } + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, llvm::ImmutableList<SVal> L); void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } }; +class LazyCompoundValData : public llvm::FoldingSetNode { + const GRState *state; + const TypedRegion *region; +public: + LazyCompoundValData(const GRState *st, const TypedRegion *r) + : state(st), region(r) {} + + const GRState *getState() const { return state; } + const TypedRegion *getRegion() const { return region; } + + static void Profile(llvm::FoldingSetNodeID& ID, const GRState *state, + const TypedRegion *region); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, state, region); } +}; + class BasicValueFactory { typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > APSIntSetTy; @@ -56,44 +74,54 @@ class BasicValueFactory { llvm::ImmutableList<SVal>::Factory SValListFactory; llvm::FoldingSet<CompoundValData> CompoundValDataSet; + llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet; public: - BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) + BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), SValListFactory(Alloc) {} ~BasicValueFactory(); - ASTContext& getContext() const { return Ctx; } + ASTContext& getContext() const { return Ctx; } const llvm::APSInt& getValue(const llvm::APSInt& X); const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); const llvm::APSInt& getValue(uint64_t X, QualType T); - + /// Convert - Create a new persistent APSInt with the same value as 'From' /// but with the bitwidth and signedness of 'To'. - const llvm::APSInt& Convert(const llvm::APSInt& To, + const llvm::APSInt &Convert(const llvm::APSInt& To, const llvm::APSInt& From) { - + if (To.isUnsigned() == From.isUnsigned() && To.getBitWidth() == From.getBitWidth()) return From; + + return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned()); + } + + const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + unsigned bitwidth = Ctx.getTypeSize(T); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); - return getValue(From.getSExtValue(), - To.getBitWidth(), - To.isUnsigned()); + if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), bitwidth, isUnsigned); } const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; return getValue(X, T); } - + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); } - + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); } @@ -103,44 +131,51 @@ public: bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); } - + inline const llvm::APSInt& getMinValue(QualType T) { assert(T->isIntegerType() || Loc::IsLocType(T)); bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); } - + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { llvm::APSInt X = V; ++X; return getValue(X); } - + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { llvm::APSInt X = V; --X; return getValue(X); } - + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } + inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); } - + inline const llvm::APSInt& getTruthValue(bool b) { return getTruthValue(b, Ctx.IntTy); } - - const CompoundValData* getCompoundValData(QualType T, + + const CompoundValData *getCompoundValData(QualType T, llvm::ImmutableList<SVal> Vals); - + + const LazyCompoundValData *getLazyCompoundValData(const GRState *state, + const TypedRegion *region); + llvm::ImmutableList<SVal> getEmptySValList() { return SValListFactory.GetEmptyList(); } - + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { return SValListFactory.Add(X, L); } @@ -148,13 +183,13 @@ public: const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt& V1, const llvm::APSInt& V2); - + const std::pair<SVal, uintptr_t>& getPersistentSValWithData(const SVal& V, uintptr_t Data); - + const std::pair<SVal, SVal>& - getPersistentSValPair(const SVal& V1, const SVal& V2); - + getPersistentSValPair(const SVal& V1, const SVal& V2); + const SVal* getPersistentSVal(SVal X); }; diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index 90fd9d8ebf45..1434fce811d1 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -27,7 +27,7 @@ #include <list> namespace clang { - + class PathDiagnostic; class PathDiagnosticPiece; class PathDiagnosticClient; @@ -40,7 +40,7 @@ class GRState; class Stmt; class BugType; class ParentMap; - + //===----------------------------------------------------------------------===// // Interface for individual bug reports. //===----------------------------------------------------------------------===// @@ -48,22 +48,22 @@ class ParentMap; class BugReporterVisitor { public: virtual ~BugReporterVisitor(); - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, - const ExplodedNode<GRState>* PrevN, + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BRC) = 0; - + virtual bool isOwnedByReporterContext() { return true; } }; - + // FIXME: Combine this with RangedBugReport and remove RangedBugReport. class BugReport : public BugReporterVisitor { protected: BugType& BT; std::string ShortDescription; std::string Description; - const ExplodedNode<GRState> *EndNode; + const ExplodedNode *EndNode; SourceRange R; - + protected: friend class BugReporter; friend class BugReportEquivClass; @@ -71,79 +71,78 @@ protected: virtual void Profile(llvm::FoldingSetNodeID& hash) const { hash.AddInteger(getLocation().getRawEncoding()); } - + public: class NodeResolver { public: virtual ~NodeResolver() {} - virtual const ExplodedNode<GRState>* - getOriginalNode(const ExplodedNode<GRState>* N) = 0; + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode* N) = 0; }; - - BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n) + + BugReport(BugType& bt, const char* desc, const ExplodedNode *n) : BT(bt), Description(desc), EndNode(n) {} - + BugReport(BugType& bt, const char* shortDesc, const char* desc, - const ExplodedNode<GRState> *n) + const ExplodedNode *n) : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} virtual ~BugReport(); - + virtual bool isOwnedByReporterContext() { return false; } const BugType& getBugType() const { return BT; } BugType& getBugType() { return BT; } - + // FIXME: Perhaps this should be moved into a subclass? - const ExplodedNode<GRState>* getEndNode() const { return EndNode; } - + const ExplodedNode* getEndNode() const { return EndNode; } + // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint // object. // FIXME: If we do need it, we can probably just make it private to // BugReporter. - Stmt* getStmt(BugReporter& BR) const; - + const Stmt* getStmt() const; + const std::string& getDescription() const { return Description; } const std::string& getShortDescription() const { return ShortDescription.empty() ? Description : ShortDescription; } - + // FIXME: Is this needed? virtual std::pair<const char**,const char**> getExtraDescriptiveText() { return std::make_pair((const char**)0,(const char**)0); } - + // FIXME: Perhaps move this into a subclass. virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode<GRState>* N); - + const ExplodedNode* N); + /// getLocation - Return the "definitive" location of the reported bug. /// While a bug can span an entire path, usually there is a specific /// location that can be used to identify where the key issue occured. /// This location is used by clients rendering diagnostics. virtual SourceLocation getLocation() const; - + /// getRanges - Returns the source ranges associated with this bug. - virtual void getRanges(BugReporter& BR,const SourceRange*& beg, - const SourceRange*& end); + virtual void getRanges(const SourceRange*& beg, const SourceRange*& end); - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, - const ExplodedNode<GRState>* PrevN, + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BR); - + virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode<GRState>* N) {} + const ExplodedNode* N) {} }; //===----------------------------------------------------------------------===// // BugTypes (collections of related reports). //===----------------------------------------------------------------------===// - + class BugReportEquivClass : public llvm::FoldingSetNode { // List of *owned* BugReport objects. std::list<BugReport*> Reports; - + friend class BugReporter; void AddReport(BugReport* R) { Reports.push_back(R); } public: @@ -165,7 +164,7 @@ public: BugReport* operator*() const { return *impl; } BugReport* operator->() const { return *impl; } }; - + class const_iterator { std::list<BugReport*>::const_iterator impl; public: @@ -176,64 +175,70 @@ public: const BugReport* operator*() const { return *impl; } const BugReport* operator->() const { return *impl; } }; - + iterator begin() { return iterator(Reports.begin()); } iterator end() { return iterator(Reports.end()); } - + const_iterator begin() const { return const_iterator(Reports.begin()); } const_iterator end() const { return const_iterator(Reports.end()); } }; - + class BugType { private: const std::string Name; const std::string Category; llvm::FoldingSet<BugReportEquivClass> EQClasses; friend class BugReporter; + bool SuppressonSink; public: - BugType(const char *name, const char* cat) : Name(name), Category(cat) {} + BugType(const char *name, const char* cat) + : Name(name), Category(cat), SuppressonSink(false) {} virtual ~BugType(); - + // FIXME: Should these be made strings as well? const std::string& getName() const { return Name; } const std::string& getCategory() const { return Category; } - - virtual void FlushReports(BugReporter& BR); - void AddReport(BugReport* BR); + /// isSuppressOnSink - Returns true if bug reports associated with this bug + /// type should be suppressed if the end node of the report is post-dominated + /// by a sink node. + bool isSuppressOnSink() const { return SuppressonSink; } + void setSuppressOnSink(bool x) { SuppressonSink = x; } + + virtual void FlushReports(BugReporter& BR); + typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator; iterator begin() { return EQClasses.begin(); } iterator end() { return EQClasses.end(); } - + typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator; const_iterator begin() const { return EQClasses.begin(); } const_iterator end() const { return EQClasses.end(); } }; - + //===----------------------------------------------------------------------===// // Specialized subclasses of BugReport. //===----------------------------------------------------------------------===// - + // FIXME: Collapse this with the default BugReport class. class RangedBugReport : public BugReport { std::vector<SourceRange> Ranges; public: - RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n) + RangedBugReport(BugType& D, const char* description, ExplodedNode *n) : BugReport(D, description, n) {} - + RangedBugReport(BugType& D, const char *shortDescription, - const char *description, ExplodedNode<GRState> *n) + const char *description, ExplodedNode *n) : BugReport(D, shortDescription, description, n) {} - + ~RangedBugReport(); // FIXME: Move this out of line. void addRange(SourceRange R) { Ranges.push_back(R); } - + // FIXME: Move this out of line. - void getRanges(BugReporter& BR,const SourceRange*& beg, - const SourceRange*& end) { - + void getRanges(const SourceRange*& beg, const SourceRange*& end) { + if (Ranges.empty()) { beg = NULL; end = NULL; @@ -244,7 +249,36 @@ public: } } }; - + +class EnhancedBugReport : public RangedBugReport { +public: + typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data, + const ExplodedNode *N); + +private: + typedef std::vector<std::pair<VisitorCreator, const void*> > Creators; + Creators creators; + +public: + EnhancedBugReport(BugType& D, const char* description, ExplodedNode *n) + : RangedBugReport(D, description, n) {} + + EnhancedBugReport(BugType& D, const char *shortDescription, + const char *description, ExplodedNode *n) + : RangedBugReport(D, shortDescription, description, n) {} + + ~EnhancedBugReport() {} + + void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) { + for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I) + I->first(BRC, I->second, N); + } + + void addVisitorCreator(VisitorCreator creator, const void *data) { + creators.push_back(std::make_pair(creator, data)); + } +}; + //===----------------------------------------------------------------------===// // BugReporter and friends. //===----------------------------------------------------------------------===// @@ -252,15 +286,12 @@ public: class BugReporterData { public: virtual ~BugReporterData(); - virtual Diagnostic& getDiagnostic() = 0; - virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; - virtual ASTContext& getContext() = 0; + virtual Diagnostic& getDiagnostic() = 0; + virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; + virtual ASTContext& getASTContext() = 0; virtual SourceManager& getSourceManager() = 0; - virtual CFG* getCFG() = 0; - virtual ParentMap& getParentMap() = 0; - virtual LiveVariables* getLiveVariables() = 0; }; - + class BugReporter { public: enum Kind { BaseBRKind, GRBugReporterKind }; @@ -270,9 +301,9 @@ private: BugTypesTy::Factory F; BugTypesTy BugTypes; - const Kind kind; + const Kind kind; BugReporterData& D; - + void FlushReport(BugReportEquivClass& EQ); protected: @@ -281,40 +312,34 @@ protected: public: BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} virtual ~BugReporter(); - + void FlushReports(); - + Kind getKind() const { return kind; } - + Diagnostic& getDiagnostic() { return D.getDiagnostic(); } - + PathDiagnosticClient* getPathDiagnosticClient() { return D.getPathDiagnosticClient(); } - + typedef BugTypesTy::iterator iterator; iterator begin() { return BugTypes.begin(); } iterator end() { return BugTypes.end(); } - - ASTContext& getContext() { return D.getContext(); } - + + ASTContext& getContext() { return D.getASTContext(); } + SourceManager& getSourceManager() { return D.getSourceManager(); } - - CFG* getCFG() { return D.getCFG(); } - - ParentMap& getParentMap() { return D.getParentMap(); } - - LiveVariables* getLiveVariables() { return D.getLiveVariables(); } - + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReportEquivClass& EQ) {} void Register(BugType *BT); - + void EmitReport(BugReport *R); - + void EmitBasicReport(const char* BugName, const char* BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); @@ -322,28 +347,28 @@ public: void EmitBasicReport(const char* BugName, const char* BugCategory, const char* BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - - + + void EmitBasicReport(const char* BugName, const char* BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugStr, Loc, 0, 0); } - + void EmitBasicReport(const char* BugName, const char* BugCategory, const char* BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); } - + void EmitBasicReport(const char* BugName, const char* BugStr, SourceLocation Loc, SourceRange R) { EmitBasicReport(BugName, BugStr, Loc, &R, 1); } - + void EmitBasicReport(const char* BugName, const char* Category, const char* BugStr, SourceLocation Loc, SourceRange R) { EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); } - + static bool classof(const BugReporter* R) { return true; } }; @@ -351,95 +376,87 @@ public: class GRBugReporter : public BugReporter { GRExprEngine& Eng; llvm::SmallSet<SymbolRef, 10> NotableSymbols; -public: +public: GRBugReporter(BugReporterData& d, GRExprEngine& eng) : BugReporter(d, GRBugReporterKind), Eng(eng) {} - + virtual ~GRBugReporter(); - + /// getEngine - Return the analysis engine used to analyze a given /// function or method. - GRExprEngine& getEngine() { return Eng; } + GRExprEngine &getEngine() { return Eng; } /// getGraph - Get the exploded graph created by the analysis engine /// for the analyzed method or function. - ExplodedGraph<GRState>& getGraph(); - + ExplodedGraph &getGraph(); + /// getStateManager - Return the state manager used by the analysis /// engine. - GRStateManager& getStateManager(); - + GRStateManager &getStateManager(); + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReportEquivClass& R); void addNotableSymbol(SymbolRef Sym) { NotableSymbols.insert(Sym); } - + bool isNotable(SymbolRef Sym) const { return (bool) NotableSymbols.count(Sym); } - + /// classof - Used by isa<>, cast<>, and dyn_cast<>. static bool classof(const BugReporter* R) { return R->getKind() == GRBugReporterKind; } }; - + class BugReporterContext { GRBugReporter &BR; std::vector<BugReporterVisitor*> Callbacks; public: BugReporterContext(GRBugReporter& br) : BR(br) {} virtual ~BugReporterContext(); - + void addVisitor(BugReporterVisitor* visitor) { if (visitor) Callbacks.push_back(visitor); } - + typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator; visitor_iterator visitor_begin() { return Callbacks.begin(); } - visitor_iterator visitor_end() { return Callbacks.end(); } - - GRBugReporter& getBugReporter() { return BR; } - - ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); } - + visitor_iterator visitor_end() { return Callbacks.end(); } + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph &getGraph() { return BR.getGraph(); } + void addNotableSymbol(SymbolRef Sym) { // FIXME: For now forward to GRBugReporter. BR.addNotableSymbol(Sym); } - + bool isNotable(SymbolRef Sym) const { // FIXME: For now forward to GRBugReporter. return BR.isNotable(Sym); } - + GRStateManager& getStateManager() { return BR.getStateManager(); } - + ValueManager& getValueManager() { return getStateManager().getValueManager(); } - + ASTContext& getASTContext() { return BR.getContext(); } - + SourceManager& getSourceManager() { return BR.getSourceManager(); } - - const Decl& getCodeDecl() { - return getStateManager().getCodeDecl(); - } - - const CFG& getCFG() { - return *BR.getCFG(); - } - - virtual BugReport::NodeResolver& getNodeResolver() = 0; + + virtual BugReport::NodeResolver& getNodeResolver() = 0; }; class DiagBugReport : public RangedBugReport { @@ -448,19 +465,37 @@ class DiagBugReport : public RangedBugReport { public: DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : RangedBugReport(D, desc, 0), L(l) {} - + virtual ~DiagBugReport() {} - + // FIXME: Move out-of-line (virtual function). SourceLocation getLocation() const { return L; } - - void addString(const std::string& s) { Strs.push_back(s); } - + + void addString(const std::string& s) { Strs.push_back(s); } + typedef std::list<std::string>::const_iterator str_iterator; str_iterator str_begin() const { return Strs.begin(); } str_iterator str_end() const { return Strs.end(); } }; +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// + +namespace bugreporter { + +const Stmt *GetDerefExpr(const ExplodedNode *N); +const Stmt *GetReceiverExpr(const ExplodedNode *N); +const Stmt *GetDenomExpr(const ExplodedNode *N); +const Stmt *GetCalleeExpr(const ExplodedNode *N); +const Stmt *GetRetValExpr(const ExplodedNode *N); + +void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt, + const ExplodedNode* N); + +} // end namespace clang::bugreporter + +//===----------------------------------------------------------------------===// + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h new file mode 100644 index 000000000000..4e00d69cdba1 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -0,0 +1,122 @@ +//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating +// domain-specific checks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKER +#define LLVM_CLANG_ANALYSIS_CHECKER +#include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" + +//===----------------------------------------------------------------------===// +// Checker interface. +//===----------------------------------------------------------------------===// + +namespace clang { + class GRExprEngine; + +class CheckerContext { + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; + GRExprEngine &Eng; + ExplodedNode *Pred; + SaveAndRestore<bool> OldSink; + SaveAndRestore<const void*> OldTag; + SaveAndRestore<ProgramPoint::Kind> OldPointKind; + SaveOr OldHasGen; + +public: + CheckerContext(ExplodedNodeSet &dst, + GRStmtNodeBuilder &builder, + GRExprEngine &eng, + ExplodedNode *pred, + const void *tag, bool preVisit) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + OldSink(B.BuildSinks), OldTag(B.Tag), + OldPointKind(B.PointKind), OldHasGen(B.HasGeneratedNode) { + //assert(Dst.empty()); // This is a fake assertion. + // See GRExprEngine::CheckerVisit(), CurrSet is repeatedly used. + B.Tag = tag; + if (preVisit) + B.PointKind = ProgramPoint::PreStmtKind; + } + + ~CheckerContext() { + if (!B.BuildSinks && !B.HasGeneratedNode) + Dst.Add(Pred); + } + + ConstraintManager &getConstraintManager() { + return Eng.getConstraintManager(); + } + ExplodedNodeSet &getNodeSet() { return Dst; } + GRStmtNodeBuilder &getNodeBuilder() { return B; } + ExplodedNode *&getPredecessor() { return Pred; } + const GRState *getState() { return B.GetState(Pred); } + + ASTContext &getASTContext() { + return Eng.getContext(); + } + + ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { + return GenerateNode(S, getState(), markAsSink); + } + + ExplodedNode *GenerateNode(const Stmt* S, const GRState *state, + bool markAsSink = false) { + ExplodedNode *node = B.generateNode(S, state, Pred); + + if (markAsSink && node) + node->markAsSink(); + + return node; + } + + void addTransition(ExplodedNode *node) { + Dst.Add(node); + } + + void EmitReport(BugReport *R) { + Eng.getBugReporter().EmitReport(R); + } +}; + +class Checker { +private: + friend class GRExprEngine; + + void GR_Visit(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, + const Stmt *stmt, + ExplodedNode *Pred, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit); + assert(isPrevisit && "Only previsit supported for now."); + _PreVisit(C, stmt); + } + +public: + virtual ~Checker() {} + virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0; + virtual const void *getTag() = 0; +}; + +} // end clang namespace + +#endif + diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def new file mode 100644 index 000000000000..ff6528dae8f5 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def @@ -0,0 +1,18 @@ +//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AST nodes accepted by the CheckerVisitor class. +// +//===---------------------------------------------------------------------===// + +PREVISIT(CallExpr) +PREVISIT(ObjCMessageExpr) +PREVISIT(BinaryOperator) + +#undef PREVISIT diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Analysis/PathSensitive/CheckerVisitor.h new file mode 100644 index 000000000000..e74f49c9a761 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.h @@ -0,0 +1,59 @@ +//== CheckerVisitor.h - Abstract visitor for checkers ------------*- 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 CheckerVisitor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#include "clang/Analysis/PathSensitive/Checker.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// Checker visitor interface. Used by subclasses of Checker to specify their +// own checker visitor logic. +//===----------------------------------------------------------------------===// + +/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +template<typename ImplClass> +class CheckerVisitor : public Checker { +public: + virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) { + PreVisit(C, stmt); + } + + void PreVisit(CheckerContext &C, const Stmt *S) { + switch (S->getStmtClass()) { + default: + assert(false && "Unsupport statement."); + return; + case Stmt::CompoundAssignOperatorClass: + static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C, + static_cast<const BinaryOperator*>(S)); + break; +#define PREVISIT(NAME) \ +case Stmt::NAME ## Class:\ +static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\ +break; +#include "clang/Analysis/PathSensitive/CheckerVisitor.def" + } + } + +#define PREVISIT(NAME) \ +void PreVisit ## NAME(CheckerContext &C, const NAME* S) {} +#include "clang/Analysis/PathSensitive/CheckerVisitor.def" +}; + +} // end clang namespace + +#endif + diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h index 689bebb450f4..37a14083ac55 100644 --- a/include/clang/Analysis/PathSensitive/ConstraintManager.h +++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h @@ -30,26 +30,32 @@ class SVal; class ConstraintManager { public: virtual ~ConstraintManager(); - virtual const GRState *Assume(const GRState *state, SVal Cond, + virtual const GRState *Assume(const GRState *state, DefinedSVal Cond, bool Assumption) = 0; - virtual const GRState *AssumeInBound(const GRState *state, SVal Idx, - SVal UpperBound, bool Assumption) = 0; + virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, + DefinedSVal UpperBound, bool Assumption) = 0; + + std::pair<const GRState*, const GRState*> AssumeDual(const GRState *state, + DefinedSVal Cond) { + return std::make_pair(Assume(state, Cond, true), + Assume(state, Cond, false)); + } virtual const llvm::APSInt* getSymVal(const GRState *state, SymbolRef sym) const = 0; - virtual bool isEqual(const GRState *state, SymbolRef sym, + virtual bool isEqual(const GRState *state, SymbolRef sym, const llvm::APSInt& V) const = 0; virtual const GRState *RemoveDeadBindings(const GRState *state, SymbolReaper& SymReaper) = 0; - virtual void print(const GRState *state, llvm::raw_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) {} - + /// canReasonAbout - Not all ConstraintManagers can accurately reason about /// all SVal values. This method returns true if the ConstraintManager can /// reasonably handle a given SVal value. This is typically queried by diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h index 6f8a12642769..6d5c5678e59b 100644 --- a/include/clang/Analysis/PathSensitive/Environment.h +++ b/include/clang/Analysis/PathSensitive/Environment.h @@ -26,125 +26,78 @@ namespace clang { +class AnalysisContext; class EnvironmentManager; class ValueManager; class LiveVariables; + class Environment { private: friend class EnvironmentManager; - + // Type definitions. typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy; // Data. - BindingsTy SubExprBindings; - BindingsTy BlkExprBindings; - - Environment(BindingsTy seb, BindingsTy beb) - : SubExprBindings(seb), BlkExprBindings(beb) {} - + BindingsTy ExprBindings; + AnalysisContext *ACtx; + + Environment(BindingsTy eb, AnalysisContext *aCtx) + : ExprBindings(eb), ACtx(aCtx) {} + public: - - typedef BindingsTy::iterator seb_iterator; - seb_iterator seb_begin() const { return SubExprBindings.begin(); } - seb_iterator seb_end() const { return SubExprBindings.end(); } - - typedef BindingsTy::iterator beb_iterator; - beb_iterator beb_begin() const { return BlkExprBindings.begin(); } - beb_iterator beb_end() const { return BlkExprBindings.end(); } - - SVal LookupSubExpr(const Stmt* E) const { - const SVal* X = SubExprBindings.lookup(cast<Expr>(E)); - return X ? *X : UnknownVal(); - } - - SVal LookupBlkExpr(const Stmt* E) const { - const SVal* X = BlkExprBindings.lookup(E); - return X ? *X : UnknownVal(); - } - + typedef BindingsTy::iterator iterator; + iterator begin() const { return ExprBindings.begin(); } + iterator end() const { return ExprBindings.end(); } + SVal LookupExpr(const Stmt* E) const { - const SVal* X = SubExprBindings.lookup(E); - if (X) return *X; - X = BlkExprBindings.lookup(E); + const SVal* X = ExprBindings.lookup(E); return X ? *X : UnknownVal(); } - + SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const; - SVal GetBlkExprSVal(const Stmt* Ex, ValueManager& ValMgr) const; - + + AnalysisContext &getAnalysisContext() const { return *ACtx; } + /// Profile - Profile the contents of an Environment object for use /// in a FoldingSet. static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { - E->SubExprBindings.Profile(ID); - E->BlkExprBindings.Profile(ID); + E->ExprBindings.Profile(ID); } - + /// Profile - Used to profile the contents of this object for inclusion /// in a FoldingSet. void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, this); } - + bool operator==(const Environment& RHS) const { - return SubExprBindings == RHS.SubExprBindings && - BlkExprBindings == RHS.BlkExprBindings; + return ExprBindings == RHS.ExprBindings; } }; - + class EnvironmentManager { private: typedef Environment::BindingsTy::Factory FactoryTy; FactoryTy F; - + public: - EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} ~EnvironmentManager() {} - /// RemoveBlkExpr - Return a new environment object with the same bindings as - /// the provided environment except with any bindings for the provided Stmt* - /// removed. This method only removes bindings for block-level expressions. - /// Using this method on a non-block level expression will return the - /// same environment object. - Environment RemoveBlkExpr(const Environment& Env, const Stmt* E) { - return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E)); - } - - Environment RemoveSubExpr(const Environment& Env, const Stmt* E) { - return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings); + Environment getInitialEnvironment(AnalysisContext *ACtx) { + return Environment(F.GetEmptyMap(), ACtx); } - - Environment AddBlkExpr(const Environment& Env, const Stmt *E, SVal V) { - return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V)); - } - - Environment AddSubExpr(const Environment& Env, const Stmt *E, SVal V) { - return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings); - } - - /// RemoveSubExprBindings - Return a new environment object with - /// the same bindings as the provided environment except with all the - /// subexpression bindings removed. - Environment RemoveSubExprBindings(const Environment& Env) { - return Environment(F.GetEmptyMap(), Env.BlkExprBindings); - } - - Environment getInitialEnvironment() { - return Environment(F.GetEmptyMap(), F.GetEmptyMap()); - } - - Environment BindExpr(const Environment& Env, const Stmt* E, SVal V, - bool isBlkExpr, bool Invalidate); - Environment - RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper, - GRStateManager& StateMgr, const GRState *state, - llvm::SmallVectorImpl<const MemRegion*>& DRoots); + Environment BindExpr(Environment Env, const Stmt *S, SVal V, + bool Invalidate); + Environment RemoveDeadBindings(Environment Env, const Stmt *S, + SymbolReaper &SymReaper, const GRState *ST, + llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); }; - + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index 8494d935650d..a7bbdf939f87 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH #include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/FoldingSet.h" @@ -25,193 +26,158 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/Support/Casting.h" +#include "clang/Analysis/Support/BumpVector.h" namespace clang { -class GRCoreEngineImpl; -class ExplodedNodeImpl; +class GRState; class CFG; class ASTContext; - -class GRStmtNodeBuilderImpl; -class GRBranchNodeBuilderImpl; -class GRIndirectGotoNodeBuilderImpl; -class GRSwitchNodeBuilderImpl; -class GREndPathNodebuilderImpl; +class ExplodedGraph; //===----------------------------------------------------------------------===// // ExplodedGraph "implementation" classes. These classes are not typed to // contain a specific kind of state. Typed-specialized versions are defined // on top of these classes. //===----------------------------------------------------------------------===// - -class ExplodedNodeImpl : public llvm::FoldingSetNode { -protected: - friend class ExplodedGraphImpl; - friend class GRCoreEngineImpl; - friend class GRStmtNodeBuilderImpl; - friend class GRBranchNodeBuilderImpl; - friend class GRIndirectGotoNodeBuilderImpl; - friend class GRSwitchNodeBuilderImpl; - friend class GREndPathNodeBuilderImpl; - + +class ExplodedNode : public llvm::FoldingSetNode { + friend class ExplodedGraph; + friend class GRCoreEngine; + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + class NodeGroup { enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; uintptr_t P; - + unsigned getKind() const { return P & 0x1; } - + void* getPtr() const { assert (!getFlag()); return reinterpret_cast<void*>(P & ~Mask); } - ExplodedNodeImpl* getNode() const { - return reinterpret_cast<ExplodedNodeImpl*>(getPtr()); + ExplodedNode *getNode() const { + return reinterpret_cast<ExplodedNode*>(getPtr()); } - + public: NodeGroup() : P(0) {} - - ~NodeGroup(); - - ExplodedNodeImpl** begin() const; - - ExplodedNodeImpl** end() const; - + + ExplodedNode **begin() const; + + ExplodedNode **end() const; + unsigned size() const; - - bool empty() const { return size() == 0; } - - void addNode(ExplodedNodeImpl* N); - + + bool empty() const { return (P & ~Mask) == 0; } + + void addNode(ExplodedNode* N, ExplodedGraph &G); + void setFlag() { - assert (P == 0); + assert(P == 0); P = AuxFlag; } - + bool getFlag() const { return P & AuxFlag ? true : false; } - }; - + }; + /// Location - The program location (within a function body) associated /// with this node. const ProgramPoint Location; - + /// State - The state associated with this node. - const void* State; - + const GRState* State; + /// Preds - The predecessors of this node. NodeGroup Preds; - + /// Succs - The successors of this node. NodeGroup Succs; - - /// Construct a ExplodedNodeImpl with the provided location and state. - explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state) - : Location(loc), State(state) {} - - /// addPredeccessor - Adds a predecessor to the current node, and - /// in tandem add this node as a successor of the other node. - void addPredecessor(ExplodedNodeImpl* V); - + public: - + + explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) + : Location(loc), State(state) {} + /// getLocation - Returns the edge associated with the given node. ProgramPoint getLocation() const { return Location; } - - template <typename T> - const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } - - unsigned succ_size() const { return Succs.size(); } - unsigned pred_size() const { return Preds.size(); } - bool succ_empty() const { return Succs.empty(); } - bool pred_empty() const { return Preds.empty(); } - - bool isSink() const { return Succs.getFlag(); } - void markAsSink() { Succs.setFlag(); } - - // For debugging. - -public: - - class Auditor { - public: - virtual ~Auditor(); - virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0; - }; - - static void SetAuditor(Auditor* A); -}; - -template <typename StateTy> -struct GRTrait { - static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) { - St->Profile(ID); + const LocationContext *getLocationContext() const { + return getLocation().getLocationContext(); } -}; + const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } -template <typename StateTy> -class ExplodedNode : public ExplodedNodeImpl { -public: - /// Construct a ExplodedNodeImpl with the given node ID, program edge, - /// and state. - explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St) - : ExplodedNodeImpl(loc, St) {} - - /// getState - Returns the state associated with the node. - inline const StateTy* getState() const { - return static_cast<const StateTy*>(State); + CFG &getCFG() const { return *getLocationContext()->getCFG(); } + + ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} + + LiveVariables &getLiveVariables() const { + return *getLocationContext()->getLiveVariables(); } - - // Profiling (for FoldingSet). - - static inline void Profile(llvm::FoldingSetNodeID& ID, - const ProgramPoint& Loc, - const StateTy* state) { + + const GRState* getState() const { return State; } + + template <typename T> + const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint& Loc, const GRState* state) { ID.Add(Loc); - GRTrait<StateTy>::Profile(ID, state); + ID.AddPointer(state); } - - inline void Profile(llvm::FoldingSetNodeID& ID) const { + + void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, getLocation(), getState()); } - - void addPredecessor(ExplodedNode* V) { - ExplodedNodeImpl::addPredecessor(V); - } - + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNode* V, ExplodedGraph &G); + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + void markAsSink() { Succs.setFlag(); } + ExplodedNode* getFirstPred() { return pred_empty() ? NULL : *(pred_begin()); } - + const ExplodedNode* getFirstPred() const { return const_cast<ExplodedNode*>(this)->getFirstPred(); } - + // Iterators over successor and predecessor vertices. typedef ExplodedNode** succ_iterator; typedef const ExplodedNode* const * const_succ_iterator; typedef ExplodedNode** pred_iterator; typedef const ExplodedNode* const * const_pred_iterator; - pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); } - pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); } + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } const_pred_iterator pred_begin() const { return const_cast<ExplodedNode*>(this)->pred_begin(); - } + } const_pred_iterator pred_end() const { return const_cast<ExplodedNode*>(this)->pred_end(); } - succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); } - succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); } + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } const_succ_iterator succ_begin() const { return const_cast<ExplodedNode*>(this)->succ_begin(); @@ -219,23 +185,40 @@ public: const_succ_iterator succ_end() const { return const_cast<ExplodedNode*>(this)->succ_end(); } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0; + }; + + static void SetAuditor(Auditor* A); }; -class InterExplodedGraphMapImpl; +// FIXME: Is this class necessary? +class InterExplodedGraphMap { + llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M; + friend class ExplodedGraph; -class ExplodedGraphImpl { +public: + ExplodedNode* getMappedNode(const ExplodedNode* N) const; + + InterExplodedGraphMap() {}; + virtual ~InterExplodedGraphMap() {} +}; + +class ExplodedGraph { protected: - friend class GRCoreEngineImpl; - friend class GRStmtNodeBuilderImpl; - friend class GRBranchNodeBuilderImpl; - friend class GRIndirectGotoNodeBuilderImpl; - friend class GRSwitchNodeBuilderImpl; - friend class GREndPathNodeBuilderImpl; - + friend class GRCoreEngine; + // Type definitions. - typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy; - typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy; - + typedef llvm::SmallVector<ExplodedNode*,2> RootsTy; + typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy; + /// Roots - The roots of the simulation graph. Usually there will be only /// one, but clients are free to establish multiple subgraphs within a single /// SimulGraph. Moreover, these subgraphs can often merge when paths from @@ -245,338 +228,199 @@ protected: /// EndNodes - The nodes in the simulation graph which have been /// specially marked as the endpoint of an abstract simulation path. EndNodesTy EndNodes; - - /// Allocator - BumpPtrAllocator to create nodes. - llvm::BumpPtrAllocator Allocator; - - /// cfg - The CFG associated with this analysis graph. - CFG& cfg; - - /// CodeDecl - The declaration containing the code being analyzed. This - /// can be a FunctionDecl or and ObjCMethodDecl. - Decl& CodeDecl; - + + /// Nodes - The nodes in the graph. + llvm::FoldingSet<ExplodedNode> Nodes; + + /// BVC - Allocator and context for allocating nodes and their predecessor + /// and successor groups. + BumpVectorContext BVC; + /// Ctx - The ASTContext used to "interpret" CodeDecl. ASTContext& Ctx; - + /// NumNodes - The number of nodes in the graph. unsigned NumNodes; - /// getNodeImpl - Retrieve the node associated with a (Location,State) - /// pair, where 'State' is represented as an opaque void*. This method - /// is intended to be used only by GRCoreEngineImpl. - virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, - const void* State, - bool* IsNew) = 0; - - virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0; +public: + /// getNode - Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + + ExplodedNode* getNode(const ProgramPoint& L, const GRState *State, + bool* IsNew = 0); + + ExplodedGraph* MakeEmptyGraph() const { + return new ExplodedGraph(Ctx); + } /// addRoot - Add an untyped node to the set of roots. - ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) { + ExplodedNode* addRoot(ExplodedNode* V) { Roots.push_back(V); return V; } /// addEndOfPath - Add an untyped node to the set of EOP nodes. - ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) { + ExplodedNode* addEndOfPath(ExplodedNode* V) { EndNodes.push_back(V); return V; } - - // ctor. - ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx) - : cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {} -public: - virtual ~ExplodedGraphImpl() {} + ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {} + + ~ExplodedGraph() {} unsigned num_roots() const { return Roots.size(); } unsigned num_eops() const { return EndNodes.size(); } - + bool empty() const { return NumNodes == 0; } unsigned size() const { return NumNodes; } - - llvm::BumpPtrAllocator& getAllocator() { return Allocator; } - CFG& getCFG() { return cfg; } - ASTContext& getContext() { return Ctx; } - - Decl& getCodeDecl() { return CodeDecl; } - const Decl& getCodeDecl() const { return CodeDecl; } - - const FunctionDecl* getFunctionDecl() const { - return llvm::dyn_cast<FunctionDecl>(&CodeDecl); - } - - typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap; - - ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg, - const ExplodedNodeImpl* const * NEnd, - InterExplodedGraphMapImpl *M, - llvm::DenseMap<const void*, const void*> *InverseMap) - const; -}; - -class InterExplodedGraphMapImpl { - llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M; - friend class ExplodedGraphImpl; - void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To); - -protected: - ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const; - - InterExplodedGraphMapImpl(); -public: - virtual ~InterExplodedGraphMapImpl() {} -}; - -//===----------------------------------------------------------------------===// -// Type-specialized ExplodedGraph classes. -//===----------------------------------------------------------------------===// - -template <typename STATE> -class InterExplodedGraphMap : public InterExplodedGraphMapImpl { -public: - InterExplodedGraphMap() {}; - ~InterExplodedGraphMap() {}; - ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const { - return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N)); - } -}; - -template <typename STATE> -class ExplodedGraph : public ExplodedGraphImpl { -public: - typedef STATE StateTy; - typedef ExplodedNode<StateTy> NodeTy; - typedef llvm::FoldingSet<NodeTy> AllNodesTy; - -protected: - /// Nodes - The nodes in the graph. - AllNodesTy Nodes; - -protected: - virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, - const void* State, - bool* IsNew) { - - return getNode(L, static_cast<const StateTy*>(State), IsNew); - } - - virtual ExplodedGraphImpl* MakeEmptyGraph() const { - return new ExplodedGraph(cfg, CodeDecl, Ctx); - } - -public: - ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx) - : ExplodedGraphImpl(c, cd, ctx) {} - - /// getNode - Retrieve the node associated with a (Location,State) pair, - /// where the 'Location' is a ProgramPoint in the CFG. If no node for - /// this pair exists, it is created. IsNew is set to true if - /// the node was freshly created. - NodeTy* getNode(const ProgramPoint& L, const StateTy* State, - bool* IsNew = NULL) { - - // Profile 'State' to determine if we already have an existing node. - llvm::FoldingSetNodeID profile; - void* InsertPos = 0; - - NodeTy::Profile(profile, L, State); - NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); - - if (!V) { - // Allocate a new node. - V = (NodeTy*) Allocator.Allocate<NodeTy>(); - new (V) NodeTy(L, State); - - // Insert the node into the node set and return it. - Nodes.InsertNode(V, InsertPos); - - ++NumNodes; - - if (IsNew) *IsNew = true; - } - else - if (IsNew) *IsNew = false; - - return V; - } - // Iterators. + typedef ExplodedNode NodeTy; + typedef llvm::FoldingSet<ExplodedNode> AllNodesTy; typedef NodeTy** roots_iterator; - typedef const NodeTy** const_roots_iterator; + typedef NodeTy* const * const_roots_iterator; typedef NodeTy** eop_iterator; - typedef const NodeTy** const_eop_iterator; - typedef typename AllNodesTy::iterator node_iterator; - typedef typename AllNodesTy::const_iterator const_node_iterator; - - node_iterator nodes_begin() { - return Nodes.begin(); - } + typedef NodeTy* const * const_eop_iterator; + typedef AllNodesTy::iterator node_iterator; + typedef AllNodesTy::const_iterator const_node_iterator; - node_iterator nodes_end() { - return Nodes.end(); - } - - const_node_iterator nodes_begin() const { - return Nodes.begin(); - } - - const_node_iterator nodes_end() const { - return Nodes.end(); - } - - roots_iterator roots_begin() { - return reinterpret_cast<roots_iterator>(Roots.begin()); - } - - roots_iterator roots_end() { - return reinterpret_cast<roots_iterator>(Roots.end()); - } - - const_roots_iterator roots_begin() const { - return const_cast<ExplodedGraph>(this)->roots_begin(); - } - - const_roots_iterator roots_end() const { - return const_cast<ExplodedGraph>(this)->roots_end(); - } + node_iterator nodes_begin() { return Nodes.begin(); } - eop_iterator eop_begin() { - return reinterpret_cast<eop_iterator>(EndNodes.begin()); - } - - eop_iterator eop_end() { - return reinterpret_cast<eop_iterator>(EndNodes.end()); - } - - const_eop_iterator eop_begin() const { - return const_cast<ExplodedGraph>(this)->eop_begin(); - } - - const_eop_iterator eop_end() const { - return const_cast<ExplodedGraph>(this)->eop_end(); - } - - std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*> + node_iterator nodes_end() { return Nodes.end(); } + + const_node_iterator nodes_begin() const { return Nodes.begin(); } + + const_node_iterator nodes_end() const { return Nodes.end(); } + + roots_iterator roots_begin() { return Roots.begin(); } + + roots_iterator roots_end() { return Roots.end(); } + + const_roots_iterator roots_begin() const { return Roots.begin(); } + + const_roots_iterator roots_end() const { return Roots.end(); } + + eop_iterator eop_begin() { return EndNodes.begin(); } + + eop_iterator eop_end() { return EndNodes.end(); } + + const_eop_iterator eop_begin() const { return EndNodes.begin(); } + + const_eop_iterator eop_end() const { return EndNodes.end(); } + + llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } + BumpVectorContext &getNodeAllocator() { return BVC; } + + ASTContext& getContext() { return Ctx; } + + typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; + + std::pair<ExplodedGraph*, InterExplodedGraphMap*> Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, - llvm::DenseMap<const void*, const void*> *InverseMap = 0) const { - - if (NBeg == NEnd) - return std::make_pair((ExplodedGraph*) 0, - (InterExplodedGraphMap<STATE>*) 0); - - assert (NBeg < NEnd); - - const ExplodedNodeImpl* const* NBegImpl = - (const ExplodedNodeImpl* const*) NBeg; - const ExplodedNodeImpl* const* NEndImpl = - (const ExplodedNodeImpl* const*) NEnd; - - llvm::OwningPtr<InterExplodedGraphMap<STATE> > - M(new InterExplodedGraphMap<STATE>()); - - ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(), - InverseMap); - - return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); - } + llvm::DenseMap<const void*, const void*> *InverseMap = 0) const; + + ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, + const ExplodedNode* const * NEnd, + InterExplodedGraphMap *M, + llvm::DenseMap<const void*, const void*> *InverseMap) const; }; -template <typename StateTy> class ExplodedNodeSet { - - typedef ExplodedNode<StateTy> NodeTy; - typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy; + typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; ImplTy Impl; - + public: - ExplodedNodeSet(NodeTy* N) { - assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()); + ExplodedNodeSet(ExplodedNode* N) { + assert (N && !static_cast<ExplodedNode*>(N)->isSink()); Impl.insert(N); } - + ExplodedNodeSet() {} - - inline void Add(NodeTy* N) { - if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N); + + inline void Add(ExplodedNode* N) { + if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N); + } + + ExplodedNodeSet& operator=(const ExplodedNodeSet &X) { + Impl = X.Impl; + return *this; } - - typedef typename ImplTy::iterator iterator; - typedef typename ImplTy::const_iterator const_iterator; + + typedef ImplTy::iterator iterator; + typedef ImplTy::const_iterator const_iterator; inline unsigned size() const { return Impl.size(); } inline bool empty() const { return Impl.empty(); } inline void clear() { Impl.clear(); } - + inline iterator begin() { return Impl.begin(); } inline iterator end() { return Impl.end(); } - + inline const_iterator begin() const { return Impl.begin(); } inline const_iterator end() const { return Impl.end(); } -}; - +}; + } // end clang namespace // GraphTraits namespace llvm { - template<typename StateTy> - struct GraphTraits<clang::ExplodedNode<StateTy>*> { - typedef clang::ExplodedNode<StateTy> NodeType; - typedef typename NodeType::succ_iterator ChildIteratorType; + template<> struct GraphTraits<clang::ExplodedNode*> { + typedef clang::ExplodedNode NodeType; + typedef NodeType::succ_iterator ChildIteratorType; typedef llvm::df_iterator<NodeType*> nodes_iterator; - + static inline NodeType* getEntryNode(NodeType* N) { return N; } - + static inline ChildIteratorType child_begin(NodeType* N) { return N->succ_begin(); } - + static inline ChildIteratorType child_end(NodeType* N) { return N->succ_end(); } - + static inline nodes_iterator nodes_begin(NodeType* N) { return df_begin(N); } - + static inline nodes_iterator nodes_end(NodeType* N) { return df_end(N); } }; - - template<typename StateTy> - struct GraphTraits<const clang::ExplodedNode<StateTy>*> { - typedef const clang::ExplodedNode<StateTy> NodeType; - typedef typename NodeType::succ_iterator ChildIteratorType; + + template<> struct GraphTraits<const clang::ExplodedNode*> { + typedef const clang::ExplodedNode NodeType; + typedef NodeType::const_succ_iterator ChildIteratorType; typedef llvm::df_iterator<NodeType*> nodes_iterator; - + static inline NodeType* getEntryNode(NodeType* N) { return N; } - + static inline ChildIteratorType child_begin(NodeType* N) { return N->succ_begin(); } - + static inline ChildIteratorType child_end(NodeType* N) { return N->succ_end(); } - + static inline nodes_iterator nodes_begin(NodeType* N) { return df_begin(N); } - + static inline nodes_iterator nodes_end(NodeType* N) { return df_end(N); } }; - + } // end llvm namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Analysis/PathSensitive/GRAuditor.h index eca591d4af0e..015c82e80bb5 100644 --- a/include/clang/Analysis/PathSensitive/GRAuditor.h +++ b/include/clang/Analysis/PathSensitive/GRAuditor.h @@ -1,5 +1,5 @@ //==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -18,22 +18,18 @@ #ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR #define LLVM_CLANG_ANALYSIS_GRAUDITOR -#include "clang/AST/Expr.h" -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" - namespace clang { - -template <typename STATE> + +class ExplodedNode; +class GRStateManager; + class GRAuditor { public: - typedef ExplodedNode<STATE> NodeTy; - typedef typename STATE::ManagerTy ManagerTy; - virtual ~GRAuditor() {} - virtual bool Audit(NodeTy* N, ManagerTy& M) = 0; + virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0; }; - - + + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h index b4fd2704b81a..67ed9532db02 100644 --- a/include/clang/Analysis/PathSensitive/GRBlockCounter.h +++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h @@ -1,5 +1,5 @@ //==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -24,27 +24,27 @@ namespace clang { class GRBlockCounter { void* Data; - - GRBlockCounter(void* D) : Data(D) {} + + GRBlockCounter(void* D) : Data(D) {} public: GRBlockCounter() : Data(0) {} - + unsigned getNumVisited(unsigned BlockID) const; - + class Factory { void* F; public: Factory(llvm::BumpPtrAllocator& Alloc); ~Factory(); - + GRBlockCounter GetEmptyCounter(); GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID); }; - + friend class Factory; }; } // end clang namespace - + #endif diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index 0fbdbde55bd5..02e0b0275e4e 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -1,5 +1,5 @@ -//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-// -// +//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -20,646 +20,416 @@ #include "clang/Analysis/PathSensitive/GRWorkList.h" #include "clang/Analysis/PathSensitive/GRBlockCounter.h" #include "clang/Analysis/PathSensitive/GRAuditor.h" +#include "clang/Analysis/PathSensitive/GRSubEngine.h" #include "llvm/ADT/OwningPtr.h" namespace clang { - -class GRStmtNodeBuilderImpl; -class GRBranchNodeBuilderImpl; -class GRIndirectGotoNodeBuilderImpl; -class GRSwitchNodeBuilderImpl; -class GREndPathNodeBuilderImpl; -class GRWorkList; //===----------------------------------------------------------------------===// -/// GRCoreEngineImpl - Implements the core logic of the graph-reachability +/// GRCoreEngine - Implements the core logic of the graph-reachability /// analysis. It traverses the CFG and generates the ExplodedGraph. /// Program "states" are treated as opaque void pointers. -/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl) +/// The template class GRCoreEngine (which subclasses GRCoreEngine) /// provides the matching component to the engine that knows the actual types /// for states. Note that this engine only dispatches to transfer functions /// at the statement and block-level. The analyses themselves must implement /// any transfer function logic and the sub-expression level (if any). -class GRCoreEngineImpl { -protected: - friend class GRStmtNodeBuilderImpl; - friend class GRBranchNodeBuilderImpl; - friend class GRIndirectGotoNodeBuilderImpl; - friend class GRSwitchNodeBuilderImpl; - friend class GREndPathNodeBuilderImpl; - +class GRCoreEngine { + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + + GRSubEngine& SubEngine; + /// G - The simulation graph. Each node is a (location,state) pair. - llvm::OwningPtr<ExplodedGraphImpl> G; - + llvm::OwningPtr<ExplodedGraph> G; + /// WList - A set of queued nodes that need to be processed by the /// worklist algorithm. It is up to the implementation of WList to decide /// the order that nodes are processed. GRWorkList* WList; - + /// BCounterFactory - A factory object for created GRBlockCounter objects. /// These are used to record for key nodes in the ExplodedGraph the /// number of times different CFGBlocks have been visited along a path. GRBlockCounter::Factory BCounterFactory; - - void GenerateNode(const ProgramPoint& Loc, const void* State, - ExplodedNodeImpl* Pred); - - /// getInitialState - Gets the void* representing the initial 'state' - /// of the analysis. This is simply a wrapper (implemented - /// in GRCoreEngine) that performs type erasure on the initial - /// state returned by the checker object. - virtual const void* getInitialState() = 0; - - void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred); - void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred); - void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred); + + void GenerateNode(const ProgramPoint& Loc, const GRState* State, + ExplodedNode* Pred); + + void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred); + void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred); + void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred); void HandlePostStmt(const PostStmt& S, CFGBlock* B, - unsigned StmtIdx, ExplodedNodeImpl *Pred); - + unsigned StmtIdx, ExplodedNode *Pred); + void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, - ExplodedNodeImpl* Pred); - - virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0; - - virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, - GRBlockCounter BC) = 0; + ExplodedNode* Pred); + + /// Get the initial state from the subengine. + const GRState* getInitialState(const LocationContext *InitLoc) { + return SubEngine.getInitialState(InitLoc); + } + + void ProcessEndPath(GREndPathNodeBuilder& Builder); + + void ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder); + - virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0; + bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, + GRBlockCounter BC); - virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilderImpl& Builder) = 0; - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0; - - virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0; + void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilder& Builder); + + + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder); + + + void ProcessSwitch(GRSwitchNodeBuilder& Builder); private: - GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement. - GRCoreEngineImpl& operator=(const GRCoreEngineImpl&); - -protected: - GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl) - : G(g), WList(wl), BCounterFactory(g->getAllocator()) {} - + GRCoreEngine(const GRCoreEngine&); // Do not implement. + GRCoreEngine& operator=(const GRCoreEngine&); + public: + /// Construct a GRCoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), + WList(GRWorkList::MakeBFS()), + BCounterFactory(G->getAllocator()) {} + + /// Construct a GRCoreEngine object to analyze the provided CFG and to + /// use the provided worklist object to execute the worklist algorithm. + /// The GRCoreEngine object assumes ownership of 'wlist'. + GRCoreEngine(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist), + BCounterFactory(G->getAllocator()) {} + + ~GRCoreEngine() { + delete WList; + } + + /// getGraph - Returns the exploded graph. + ExplodedGraph& getGraph() { return *G.get(); } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transfered to the caller. + ExplodedGraph* takeGraph() { return G.take(); } + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of /// steps. Returns true if there is still simulation state on the worklist. - bool ExecuteWorkList(unsigned Steps); - - virtual ~GRCoreEngineImpl(); - - CFG& getCFG() { return G->getCFG(); } + bool ExecuteWorkList(const LocationContext *L, unsigned Steps); }; - -class GRStmtNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRStmtNodeBuilder { + GRCoreEngine& Eng; CFGBlock& B; const unsigned Idx; - ExplodedNodeImpl* Pred; - ExplodedNodeImpl* LastNode; - - typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy; + ExplodedNode* Pred; + ExplodedNode* LastNode; + GRStateManager& Mgr; + GRAuditor* Auditor; + +public: + bool PurgingDeadSymbols; + bool BuildSinks; + bool HasGeneratedNode; + ProgramPoint::Kind PointKind; + const void *Tag; + + const GRState* CleanedState; + + + typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy; DeferredTy Deferred; - - void GenerateAutoTransition(ExplodedNodeImpl* N); - + + void GenerateAutoTransition(ExplodedNode* N); + public: - GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, - ExplodedNodeImpl* N, GRCoreEngineImpl* e); - - ~GRStmtNodeBuilderImpl(); - - ExplodedNodeImpl* getBasePredecessor() const { return Pred; } - - ExplodedNodeImpl* getLastNode() const { + GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, + GRCoreEngine* e, GRStateManager &mgr); + + ~GRStmtNodeBuilder(); + + ExplodedNode* getBasePredecessor() const { return Pred; } + + ExplodedNode* getLastNode() const { return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; } - + + // FIXME: This should not be exposed. + GRWorkList *getWorkList() { return Eng.WList; } + + void SetCleanedState(const GRState* St) { + CleanedState = St; + } + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - + unsigned getCurrentBlockCount() const { return getBlockCounter().getNumVisited(B.getBlockID()); - } - - ExplodedNodeImpl* - generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred); - - ExplodedNodeImpl* - generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred, - ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0); + } - ExplodedNodeImpl* - generateNodeImpl(Stmt* S, const void* State, - ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0) { - ExplodedNodeImpl* N = getLastNode(); - assert (N && "Predecessor of new node is infeasible."); - return generateNodeImpl(S, State, N, K, tag); + ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) { + HasGeneratedNode = true; + return generateNodeInternal(PP, St, Pred); } - - ExplodedNodeImpl* - generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) { - ExplodedNodeImpl* N = getLastNode(); - assert (N && "Predecessor of new node is infeasible."); - return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag); + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred, ProgramPoint::Kind K) { + HasGeneratedNode = true; + + if (PurgingDeadSymbols) + K = ProgramPoint::PostPurgeDeadSymbolsKind; + + return generateNodeInternal(S, St, Pred, K, Tag); } - + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred) { + return generateNode(S, St, Pred, PointKind); + } + + ExplodedNode* + generateNodeInternal(const ProgramPoint &PP, const GRState* State, + ExplodedNode* Pred); + + ExplodedNode* + generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); + /// getStmt - Return the current block-level expression associated with /// this builder. Stmt* getStmt() const { return B[Idx]; } - + /// getBlock - Return the CFGBlock associated with the block-level expression /// of this builder. CFGBlock* getBlock() const { return &B; } -}; - - -template<typename STATE> -class GRStmtNodeBuilder { -public: - typedef STATE StateTy; - typedef typename StateTy::ManagerTy StateManagerTy; - typedef ExplodedNode<StateTy> NodeTy; - -private: - GRStmtNodeBuilderImpl& NB; - StateManagerTy& Mgr; - const StateTy* CleanedState; - GRAuditor<StateTy>* Auditor; - -public: - GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) : - NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false), - BuildSinks(false), HasGeneratedNode(false), - PointKind(ProgramPoint::PostStmtKind), Tag(0) { - - CleanedState = getLastNode()->getState(); - } - void setAuditor(GRAuditor<StateTy>* A) { - Auditor = A; - } - - NodeTy* getLastNode() const { - return static_cast<NodeTy*>(NB.getLastNode()); - } - - NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) { - HasGeneratedNode = true; - return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred)); - } - - NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred, - ProgramPoint::Kind K) { - HasGeneratedNode = true; - if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; - return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag)); - } - - NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) { - return generateNode(S, St, Pred, PointKind); - } - - NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) { - HasGeneratedNode = true; - if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; - return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag)); - } - - NodeTy* generateNode(Stmt* S, const StateTy* St) { - return generateNode(S, St, PointKind); - } + void setAuditor(GRAuditor* A) { Auditor = A; } - - GRBlockCounter getBlockCounter() const { - return NB.getBlockCounter(); - } - - unsigned getCurrentBlockCount() const { - return NB.getCurrentBlockCount(); - } - - const StateTy* GetState(NodeTy* Pred) const { - if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor()) + const GRState* GetState(ExplodedNode* Pred) const { + if ((ExplodedNode*) Pred == getBasePredecessor()) return CleanedState; else return Pred->getState(); } - - void SetCleanedState(const StateTy* St) { - CleanedState = St; - } - - NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, - NodeTy* Pred, const StateTy* St) { + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St) { return MakeNode(Dst, S, Pred, St, PointKind); } - - NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, - NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) { - - const StateTy* PredState = GetState(Pred); - + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St, ProgramPoint::Kind K) { + + const GRState* PredState = GetState(Pred); + // If the state hasn't changed, don't generate a new node. if (!BuildSinks && St == PredState && Auditor == 0) { Dst.Add(Pred); return NULL; } - - NodeTy* N = generateNode(S, St, Pred, K); - - if (N) { + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { if (BuildSinks) N->markAsSink(); else { if (Auditor && Auditor->Audit(N, Mgr)) N->markAsSink(); - + Dst.Add(N); } } - + return N; } - - NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, - NodeTy* Pred, const StateTy* St) { + + ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St) { bool Tmp = BuildSinks; BuildSinks = true; - NodeTy* N = MakeNode(Dst, S, Pred, St); + ExplodedNode* N = MakeNode(Dst, S, Pred, St); BuildSinks = Tmp; return N; } - - bool PurgingDeadSymbols; - bool BuildSinks; - bool HasGeneratedNode; - ProgramPoint::Kind PointKind; - const void *Tag; + }; - -class GRBranchNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRBranchNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; CFGBlock* DstT; CFGBlock* DstF; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; - typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy; + typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy; DeferredTy Deferred; - + bool GeneratedTrue; bool GeneratedFalse; - + bool InFeasibleTrue; + bool InFeasibleFalse; + public: - GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, - ExplodedNodeImpl* pred, GRCoreEngineImpl* e) + GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, + ExplodedNode* pred, GRCoreEngine* e) : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), - GeneratedTrue(false), GeneratedFalse(false) {} - - ~GRBranchNodeBuilderImpl(); - - ExplodedNodeImpl* getPredecessor() const { return Pred; } - const ExplodedGraphImpl& getGraph() const { return *Eng.G; } + GeneratedTrue(false), GeneratedFalse(false), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} + + ~GRBranchNodeBuilder(); + + ExplodedNode* getPredecessor() const { return Pred; } + + const ExplodedGraph& getGraph() const { return *Eng.G; } + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - - ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch); - + + ExplodedNode* generateNode(const GRState* State, bool branch); + CFGBlock* getTargetBlock(bool branch) const { return branch ? DstT : DstF; - } - - void markInfeasible(bool branch) { - if (branch) GeneratedTrue = true; - else GeneratedFalse = true; } -}; -template<typename STATE> -class GRBranchNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph<StateTy> GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - - GRBranchNodeBuilderImpl& NB; - -public: - GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {} - - const GraphTy& getGraph() const { - return static_cast<const GraphTy&>(NB.getGraph()); - } - - NodeTy* getPredecessor() const { - return static_cast<NodeTy*>(NB.getPredecessor()); - } - - const StateTy* getState() const { - return getPredecessor()->getState(); + void markInfeasible(bool branch) { + if (branch) + InFeasibleTrue = GeneratedTrue = true; + else + InFeasibleFalse = GeneratedFalse = true; } - NodeTy* generateNode(const StateTy* St, bool branch) { - return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch)); + bool isFeasible(bool branch) { + return branch ? !InFeasibleTrue : !InFeasibleFalse; } - - GRBlockCounter getBlockCounter() const { - return NB.getBlockCounter(); - } - - CFGBlock* getTargetBlock(bool branch) const { - return NB.getTargetBlock(branch); - } - - void markInfeasible(bool branch) { - NB.markInfeasible(branch); + + const GRState* getState() const { + return getPredecessor()->getState(); } }; - -class GRIndirectGotoNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRIndirectGotoNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; CFGBlock& DispatchBlock; Expr* E; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; + public: - GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, - Expr* e, CFGBlock* dispatch, - GRCoreEngineImpl* eng) + GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e, + CFGBlock* dispatch, GRCoreEngine* eng) : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} - - class Iterator { + class iterator { CFGBlock::succ_iterator I; - - friend class GRIndirectGotoNodeBuilderImpl; - Iterator(CFGBlock::succ_iterator i) : I(i) {} + + friend class GRIndirectGotoNodeBuilder; + iterator(CFGBlock::succ_iterator i) : I(i) {} public: - - Iterator& operator++() { ++I; return *this; } - bool operator!=(const Iterator& X) const { return I != X.I; } - + + iterator& operator++() { ++I; return *this; } + bool operator!=(const iterator& X) const { return I != X.I; } + LabelStmt* getLabel() const { return llvm::cast<LabelStmt>((*I)->getLabel()); } - + CFGBlock* getBlock() const { return *I; } }; - - Iterator begin() { return Iterator(DispatchBlock.succ_begin()); } - Iterator end() { return Iterator(DispatchBlock.succ_end()); } - - ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State, - bool isSink); - - Expr* getTarget() const { return E; } - const void* getState() const { return Pred->State; } -}; - -template<typename STATE> -class GRIndirectGotoNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph<StateTy> GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - GRIndirectGotoNodeBuilderImpl& NB; + iterator begin() { return iterator(DispatchBlock.succ_begin()); } + iterator end() { return iterator(DispatchBlock.succ_end()); } -public: - GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {} - - typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator; - - iterator begin() { return NB.begin(); } - iterator end() { return NB.end(); } - - Expr* getTarget() const { return NB.getTarget(); } - - NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){ - return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink)); - } - - const StateTy* getState() const { - return static_cast<const StateTy*>(NB.getState()); - } + ExplodedNode* generateNode(const iterator& I, const GRState* State, + bool isSink = false); + + Expr* getTarget() const { return E; } + + const GRState* getState() const { return Pred->State; } }; - -class GRSwitchNodeBuilderImpl { - GRCoreEngineImpl& Eng; + +class GRSwitchNodeBuilder { + GRCoreEngine& Eng; CFGBlock* Src; Expr* Condition; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; + public: - GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, - Expr* condition, GRCoreEngineImpl* eng) + GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src, + Expr* condition, GRCoreEngine* eng) : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} - - class Iterator { + + class iterator { CFGBlock::succ_reverse_iterator I; - - friend class GRSwitchNodeBuilderImpl; - Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + + friend class GRSwitchNodeBuilder; + iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + public: - - Iterator& operator++() { ++I; return *this; } - bool operator!=(const Iterator& X) const { return I != X.I; } - + iterator& operator++() { ++I; return *this; } + bool operator!=(const iterator& X) const { return I != X.I; } + CaseStmt* getCase() const { return llvm::cast<CaseStmt>((*I)->getLabel()); } - + CFGBlock* getBlock() const { return *I; } }; - - Iterator begin() { return Iterator(Src->succ_rbegin()+1); } - Iterator end() { return Iterator(Src->succ_rend()); } - - ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, - const void* State); - - ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State, - bool isSink); - + + iterator begin() { return iterator(Src->succ_rbegin()+1); } + iterator end() { return iterator(Src->succ_rend()); } + + ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State); + + ExplodedNode* generateDefaultCaseNode(const GRState* State, + bool isSink = false); + Expr* getCondition() const { return Condition; } - const void* getState() const { return Pred->State; } -}; -template<typename STATE> -class GRSwitchNodeBuilder { - typedef STATE StateTy; - typedef ExplodedGraph<StateTy> GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - - GRSwitchNodeBuilderImpl& NB; - -public: - GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {} - - typedef GRSwitchNodeBuilderImpl::Iterator iterator; - - iterator begin() { return NB.begin(); } - iterator end() { return NB.end(); } - - Expr* getCondition() const { return NB.getCondition(); } - - NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) { - return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St)); - } - - NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) { - return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink)); - } - - const StateTy* getState() const { - return static_cast<const StateTy*>(NB.getState()); - } + const GRState* getState() const { return Pred->State; } }; - -class GREndPathNodeBuilderImpl { - GRCoreEngineImpl& Eng; +class GREndPathNodeBuilder { + GRCoreEngine& Eng; CFGBlock& B; - ExplodedNodeImpl* Pred; + ExplodedNode* Pred; bool HasGeneratedNode; - + public: - GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N, - GRCoreEngineImpl* e) - : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} - - ~GREndPathNodeBuilderImpl(); - - ExplodedNodeImpl* getPredecessor() const { return Pred; } - - GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - - unsigned getCurrentBlockCount() const { - return getBlockCounter().getNumVisited(B.getBlockID()); - } - - ExplodedNodeImpl* generateNodeImpl(const void* State, - const void *tag = 0, - ExplodedNodeImpl *P = 0); - - CFGBlock* getBlock() const { return &B; } -}; + GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e) + : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + ~GREndPathNodeBuilder(); + + ExplodedNode* getPredecessor() const { return Pred; } -template<typename STATE> -class GREndPathNodeBuilder { - typedef STATE StateTy; - typedef ExplodedNode<StateTy> NodeTy; - - GREndPathNodeBuilderImpl& NB; - -public: - GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {} - - NodeTy* getPredecessor() const { - return static_cast<NodeTy*>(NB.getPredecessor()); - } - GRBlockCounter getBlockCounter() const { - return NB.getBlockCounter(); - } - - unsigned getCurrentBlockCount() const { - return NB.getCurrentBlockCount(); - } - - const StateTy* getState() const { - return getPredecessor()->getState(); - } - - NodeTy* MakeNode(const StateTy* St, const void *tag = 0) { - return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag)); + return Eng.WList->getBlockCounter(); } - - NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) { - return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred)); - } -}; - -template<typename SUBENGINE> -class GRCoreEngine : public GRCoreEngineImpl { -public: - typedef SUBENGINE SubEngineTy; - typedef typename SubEngineTy::StateTy StateTy; - typedef typename StateTy::ManagerTy StateManagerTy; - typedef ExplodedGraph<StateTy> GraphTy; - typedef typename GraphTy::NodeTy NodeTy; - -protected: - SubEngineTy& SubEngine; - - virtual const void* getInitialState() { - return SubEngine.getInitialState(); - } - - virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) { - GREndPathNodeBuilder<StateTy> Builder(BuilderImpl); - SubEngine.ProcessEndPath(Builder); - } - - virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) { - GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager()); - SubEngine.ProcessStmt(S, Builder); - } - - virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, - GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, - static_cast<const StateTy*>(State), - BC); + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); } - virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilderImpl& BuilderImpl) { - GRBranchNodeBuilder<StateTy> Builder(BuilderImpl); - SubEngine.ProcessBranch(Condition, Terminator, Builder); - } - - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) { - GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl); - SubEngine.ProcessIndirectGoto(Builder); - } - - virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) { - GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl); - SubEngine.ProcessSwitch(Builder); - } - -public: - /// Construct a GRCoreEngine object to analyze the provided CFG using - /// a DFS exploration of the exploded graph. - GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine) - : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), - GRWorkList::MakeBFS()), - SubEngine(subengine) {} - - /// Construct a GRCoreEngine object to analyze the provided CFG and to - /// use the provided worklist object to execute the worklist algorithm. - /// The GRCoreEngine object assumes ownership of 'wlist'. - GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist, - SubEngineTy& subengine) - : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist), - SubEngine(subengine) {} - - virtual ~GRCoreEngine() {} - - /// getGraph - Returns the exploded graph. - GraphTy& getGraph() { - return *static_cast<GraphTy*>(G.get()); - } - - /// takeGraph - Returns the exploded graph. Ownership of the graph is - /// transfered to the caller. - GraphTy* takeGraph() { - return static_cast<GraphTy*>(G.take()); + ExplodedNode* generateNode(const GRState* State, const void *tag = 0, + ExplodedNode *P = 0); + + CFGBlock* getBlock() const { return &B; } + + const GRState* getState() const { + return getPredecessor()->getState(); } }; diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index f05bc680a7e2..e5c61e68c77c 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -16,111 +16,86 @@ #ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE #define LLVM_CLANG_ANALYSIS_GREXPRENGINE +#include "clang/Analysis/PathSensitive/AnalysisManager.h" +#include "clang/Analysis/PathSensitive/GRSubEngine.h" #include "clang/Analysis/PathSensitive/GRCoreEngine.h" #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" -namespace clang { - +namespace clang { + class PathDiagnosticClient; class Diagnostic; class ObjCForCollectionStmt; + class Checker; + +class GRExprEngine : public GRSubEngine { + AnalysisManager &AMgr; + + GRCoreEngine CoreEngine; -class GRExprEngine { -public: - typedef GRState StateTy; - typedef ExplodedGraph<StateTy> GraphTy; - typedef GraphTy::NodeTy NodeTy; - - // Builders. - typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder; - typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder; - typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder; - typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder; - typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder; - typedef ExplodedNodeSet<StateTy> NodeSet; - -protected: - GRCoreEngine<GRExprEngine> CoreEngine; - /// G - the simulation graph. - GraphTy& G; - - /// Liveness - live-variables information the ValueDecl* and block-level - /// Expr* in the CFG. Used to prune out dead state. - LiveVariables& Liveness; + ExplodedGraph& G; /// Builder - The current GRStmtNodeBuilder which is used when building the /// nodes for a given statement. - StmtNodeBuilder* Builder; - + GRStmtNodeBuilder* Builder; + /// StateMgr - Object that manages the data for all created states. GRStateManager StateMgr; /// SymMgr - Object that manages the symbol information. SymbolManager& SymMgr; - + /// ValMgr - Object that manages/creates SVals. ValueManager &ValMgr; - + /// SVator - SValuator object that creates SVals from expressions. - llvm::OwningPtr<SValuator> SVator; - + SValuator &SVator; + /// EntryNode - The immediate predecessor node. - NodeTy* EntryNode; + ExplodedNode* EntryNode; /// CleanedState - The state for EntryNode "cleaned" of all dead /// variables and symbols (as determined by a liveness analysis). - const GRState* CleanedState; - + const GRState* CleanedState; + /// CurrentStmt - The current block-level statement. Stmt* CurrentStmt; - + // Obj-C Class Identifiers. IdentifierInfo* NSExceptionII; - + // Obj-C Selectors. Selector* NSExceptionInstanceRaiseSelectors; Selector RaiseSel; - + llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; + std::vector<Checker*> Checkers; - /// PurgeDead - Remove dead bindings before processing a statement. - bool PurgeDead; - /// BR - The BugReporter associated with this engine. It is important that // this object be placed at the very end of member variables so that its // destructor is called before the rest of the GRExprEngine is destroyed. GRBugReporter BR; - - /// EargerlyAssume - A flag indicating how the engine should handle - // expressions such as: 'x = (y != 0)'. When this flag is true then - // the subexpression 'y != 0' will be eagerly assumed to be true or false, - // thus evaluating it to the integers 0 or 1 respectively. The upside - // is that this can increase analysis precision until we have a better way - // to lazily evaluate such logic. The downside is that it eagerly - // bifurcates paths. - const bool EagerlyAssume; public: - typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes; - typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy; - + typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes; + typedef llvm::DenseMap<ExplodedNode*, Expr*> UndefArgsTy; + /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted /// from [x ...] with 'x' definitely being nil and the result was a 'struct' // (an undefined value). ErrorNodes NilReceiverStructRetExplicit; - + /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted /// from [x ...] with 'x' possibly being nil and the result was a 'struct' // (an undefined value). ErrorNodes NilReceiverStructRetImplicit; - + /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that /// resulted from [x ...] with 'x' definitely being nil and the result's size // was larger than sizeof(void *) (an undefined value). @@ -130,7 +105,7 @@ public: /// resulted from [x ...] with 'x' possibly being nil and the result's size // was larger than sizeof(void *) (an undefined value). ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; - + /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning /// the address of a stack variable. ErrorNodes RetsStackAddr; @@ -138,65 +113,55 @@ public: /// RetsUndef - Nodes in the ExplodedGraph that result from returning /// an undefined value. ErrorNodes RetsUndef; - + /// UndefBranches - Nodes in the ExplodedGraph that result from /// taking a branch based on an undefined value. ErrorNodes UndefBranches; - + /// UndefStores - Sinks in the ExplodedGraph that result from /// making a store to an undefined lvalue. ErrorNodes UndefStores; - + /// NoReturnCalls - Sinks in the ExplodedGraph that result from // calling a function with the attribute "noreturn". ErrorNodes NoReturnCalls; - + /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from /// taking a dereference on a symbolic pointer that MAY be NULL. ErrorNodes ImplicitNullDeref; - + /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from /// taking a dereference on a symbolic pointer that MUST be NULL. ErrorNodes ExplicitNullDeref; - - /// UnitDeref - Nodes in the ExplodedGraph that result from + + /// UndefDeref - Nodes in the ExplodedGraph that result from /// taking a dereference on an undefined value. ErrorNodes UndefDeref; - /// ImplicitBadDivides - Nodes in the ExplodedGraph that result from - /// evaluating a divide or modulo operation where the denominator - /// MAY be zero. - ErrorNodes ImplicitBadDivides; - - /// ExplicitBadDivides - Nodes in the ExplodedGraph that result from - /// evaluating a divide or modulo operation where the denominator - /// MUST be zero or undefined. - ErrorNodes ExplicitBadDivides; - - /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from /// constructing a zero-sized VLA where the size may be zero. ErrorNodes ImplicitBadSizedVLA; - - /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + + /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from /// constructing a zero-sized VLA where the size must be zero. ErrorNodes ExplicitBadSizedVLA; - + /// UndefResults - Nodes in the ExplodedGraph where the operands are defined /// by the result is not. Excludes divide-by-zero errors. ErrorNodes UndefResults; - + /// BadCalls - Nodes in the ExplodedGraph resulting from calls to function /// pointers that are NULL (or other constants) or Undefined. ErrorNodes BadCalls; - + /// UndefReceiver - Nodes in the ExplodedGraph resulting from message /// ObjC message expressions where the receiver is undefined (uninitialized). ErrorNodes UndefReceivers; - + /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions /// where a pass-by-value argument has an undefined value. UndefArgsTy UndefArgs; - + /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from /// message expressions where a pass-by-value argument has an undefined /// value. @@ -209,136 +174,124 @@ public: /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from /// out-of-bound memory accesses where the index MUST be out-of-bound. ErrorNodes ExplicitOOBMemAccesses; - + public: - GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L, - BugReporterData& BRD, - bool purgeDead, bool eagerlyAssume = true, - StoreManagerCreator SMC = CreateBasicStoreManager, - ConstraintManagerCreator CMC = CreateBasicConstraintManager); + GRExprEngine(AnalysisManager &mgr); ~GRExprEngine(); - - void ExecuteWorkList(unsigned Steps = 150000) { - CoreEngine.ExecuteWorkList(Steps); + + void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + CoreEngine.ExecuteWorkList(L, Steps); } - + /// getContext - Return the ASTContext associated with this analysis. ASTContext& getContext() const { return G.getContext(); } - - /// getCFG - Returns the CFG associated with this analysis. - CFG& getCFG() { return G.getCFG(); } - + + AnalysisManager &getAnalysisManager() const { return AMgr; } + + SValuator &getSValuator() { return SVator; } + GRTransferFuncs& getTF() { return *StateMgr.TF; } - + BugReporter& getBugReporter() { return BR; } - + /// setTransferFunctions void setTransferFunctions(GRTransferFuncs* tf); void setTransferFunctions(GRTransferFuncs& tf) { setTransferFunctions(&tf); } - + /// ViewGraph - Visualize the ExplodedGraph created by executing the /// simulation. void ViewGraph(bool trim = false); - - void ViewGraph(NodeTy** Beg, NodeTy** End); - - /// getLiveness - Returned computed live-variables information for the - /// analyzed function. - const LiveVariables& getLiveness() const { return Liveness; } - LiveVariables& getLiveness() { return Liveness; } - + + void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. - const GRState* getInitialState(); - - GraphTy& getGraph() { return G; } - const GraphTy& getGraph() const { return G; } + const GRState* getInitialState(const LocationContext *InitLoc); + + ExplodedGraph& getGraph() { return G; } + const ExplodedGraph& getGraph() const { return G; } void RegisterInternalChecks(); - - bool isRetStackAddr(const NodeTy* N) const { - return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0; - } - - bool isUndefControlFlow(const NodeTy* N) const { - return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0; + + void registerCheck(Checker *check) { + Checkers.push_back(check); } - - bool isUndefStore(const NodeTy* N) const { - return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0; + + bool isRetStackAddr(const ExplodedNode* N) const { + return N->isSink() && RetsStackAddr.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isImplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefControlFlow(const ExplodedNode* N) const { + return N->isSink() && UndefBranches.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isExplicitNullDeref(const NodeTy* N) const { - return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefStore(const ExplodedNode* N) const { + return N->isSink() && UndefStores.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefDeref(const NodeTy* N) const { - return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0; + + bool isImplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isImplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + + bool isExplicitNullDeref(const ExplodedNode* N) const { + return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isExplicitBadDivide(const NodeTy* N) const { - return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefDeref(const ExplodedNode* N) const { + return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isNoReturnCall(const NodeTy* N) const { - return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0; + + bool isNoReturnCall(const ExplodedNode* N) const { + return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefResult(const NodeTy* N) const { - return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefResult(const ExplodedNode* N) const { + return N->isSink() && UndefResults.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isBadCall(const NodeTy* N) const { - return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0; + + bool isBadCall(const ExplodedNode* N) const { + return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0; } - - bool isUndefArg(const NodeTy* N) const { + + bool isUndefArg(const ExplodedNode* N) const { return N->isSink() && - (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() || - MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end()); + (UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() || + MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end()); } - - bool isUndefReceiver(const NodeTy* N) const { - return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0; + + bool isUndefReceiver(const ExplodedNode* N) const { + return N->isSink() && UndefReceivers.count(const_cast<ExplodedNode*>(N)) != 0; } - + typedef ErrorNodes::iterator ret_stackaddr_iterator; ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); } - ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); } - + ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); } + typedef ErrorNodes::iterator ret_undef_iterator; ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); } ret_undef_iterator ret_undef_end() { return RetsUndef.end(); } - + typedef ErrorNodes::iterator undef_branch_iterator; undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } - undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } - + undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } + typedef ErrorNodes::iterator null_deref_iterator; null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); } null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); } - + null_deref_iterator implicit_null_derefs_begin() { return ImplicitNullDeref.begin(); } null_deref_iterator implicit_null_derefs_end() { return ImplicitNullDeref.end(); } - + typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; - + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { return NilReceiverStructRetExplicit.begin(); } @@ -346,9 +299,9 @@ public: nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { return NilReceiverStructRetExplicit.end(); } - + typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; - + nil_receiver_larger_than_voidptr_ret_iterator nil_receiver_larger_than_voidptr_ret_begin() { return NilReceiverLargerThanVoidPtrRetExplicit.begin(); @@ -358,60 +311,42 @@ public: nil_receiver_larger_than_voidptr_ret_end() { return NilReceiverLargerThanVoidPtrRetExplicit.end(); } - + typedef ErrorNodes::iterator undef_deref_iterator; undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } - - typedef ErrorNodes::iterator bad_divide_iterator; - bad_divide_iterator explicit_bad_divides_begin() { - return ExplicitBadDivides.begin(); - } - - bad_divide_iterator explicit_bad_divides_end() { - return ExplicitBadDivides.end(); - } - - bad_divide_iterator implicit_bad_divides_begin() { - return ImplicitBadDivides.begin(); - } - - bad_divide_iterator implicit_bad_divides_end() { - return ImplicitBadDivides.end(); - } - typedef ErrorNodes::iterator undef_result_iterator; undef_result_iterator undef_results_begin() { return UndefResults.begin(); } undef_result_iterator undef_results_end() { return UndefResults.end(); } typedef ErrorNodes::iterator bad_calls_iterator; bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); } - bad_calls_iterator bad_calls_end() { return BadCalls.end(); } - + bad_calls_iterator bad_calls_end() { return BadCalls.end(); } + typedef UndefArgsTy::iterator undef_arg_iterator; undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); } - undef_arg_iterator undef_arg_end() { return UndefArgs.end(); } - + undef_arg_iterator undef_arg_end() { return UndefArgs.end(); } + undef_arg_iterator msg_expr_undef_arg_begin() { return MsgExprUndefArgs.begin(); } undef_arg_iterator msg_expr_undef_arg_end() { return MsgExprUndefArgs.end(); - } - + } + typedef ErrorNodes::iterator undef_receivers_iterator; undef_receivers_iterator undef_receivers_begin() { return UndefReceivers.begin(); } - + undef_receivers_iterator undef_receivers_end() { return UndefReceivers.end(); } typedef ErrorNodes::iterator oob_memacc_iterator; - oob_memacc_iterator implicit_oob_memacc_begin() { + oob_memacc_iterator implicit_oob_memacc_begin() { return ImplicitOOBMemAccesses.begin(); } oob_memacc_iterator implicit_oob_memacc_end() { @@ -426,45 +361,45 @@ public: void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); void AddCheck(GRSimpleAPICheck* A); - + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - void ProcessStmt(Stmt* S, StmtNodeBuilder& builder); - + /// nodes by processing the 'effects' of a block-level statement. + void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder); + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing /// a CFGBlock. This method returns true if the analysis should continue /// exploring the given path, and false otherwise. bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, GRBlockCounter BC); - + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a branch condition. - void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder); - + void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder); + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. - void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder); - + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder); + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. - void ProcessSwitch(SwitchNodeBuilder& builder); - + void ProcessSwitch(GRSwitchNodeBuilder& builder); + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. - void ProcessEndPath(EndPathNodeBuilder& builder) { + void ProcessEndPath(GREndPathNodeBuilder& builder) { getTF().EvalEndPath(*this, builder); StateMgr.EndPath(builder.getState()); } - + GRStateManager& getStateManager() { return StateMgr; } const GRStateManager& getStateManager() const { return StateMgr; } StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } - + ConstraintManager& getConstraintManager() { return StateMgr.getConstraintManager(); } - + // FIXME: Remove when we migrate over to just using ValueManager. BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); @@ -472,204 +407,198 @@ public: const BasicValueFactory& getBasicVals() const { return StateMgr.getBasicVals(); } - - ValueManager &getValueManager() { return ValMgr; } + + ValueManager &getValueManager() { return ValMgr; } const ValueManager &getValueManager() const { return ValMgr; } - + // FIXME: Remove when we migrate over to just using ValueManager. SymbolManager& getSymbolManager() { return SymMgr; } const SymbolManager& getSymbolManager() const { return SymMgr; } - + protected: - const GRState* GetState(NodeTy* N) { + const GRState* GetState(ExplodedNode* N) { return N == EntryNode ? CleanedState : N->getState(); } - + public: - NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St, + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, const GRState* St, ProgramPoint::Kind K = ProgramPoint::PostStmtKind, const void *tag = 0); protected: - + /// CheckerVisit - Dispatcher for performing checker-specific logic + /// at specific statements. + void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); + /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. - void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); - + void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its /// storage location. Note that not all kinds of expressions has lvalue. - void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst); - + void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred, - NodeSet& Dst, bool asLValue); - + void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + /// VisitAsmStmt - Transfer function logic for inline asm. - void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst); - + void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitAsmStmtHelperOutputs(AsmStmt* A, AsmStmt::outputs_iterator I, AsmStmt::outputs_iterator E, - NodeTy* Pred, NodeSet& Dst); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - NodeTy* Pred, NodeSet& Dst); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitBinaryOperator - Transfer function logic for binary operators. - void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + - /// VisitCall - Transfer function for function calls. - void VisitCall(CallExpr* CE, NodeTy* Pred, + void VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst); - void VisitCallRec(CallExpr* CE, NodeTy* Pred, + ExplodedNodeSet& Dst); + void VisitCallRec(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst, const FunctionProtoType *, + ExplodedNodeSet& Dst, const FunctionProtoType *, unsigned ParamIdx = 0); - + /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst); + void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); - /// VisitCastPointerToInteger - Transfer function (called by VisitCast) that - /// handles pointer to integer casts and array to integer casts. - void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy, - Expr* CastE, NodeTy* Pred, NodeSet& Dst); - /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. - void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred, - NodeSet& Dst, bool asLValue); - + void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst, - bool asLValue); - + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); + /// VisitDeclStmt - Transfer function logic for DeclStmts. - void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); - + void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst); + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); - void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst); + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); - + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue); - + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue); + /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst, - bool asLValue); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); /// VisitObjCForCollectionStmt - Transfer function logic for /// ObjCForCollectionStmt. - void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred, - NodeSet& Dst); - - void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred, - NodeSet& Dst, SVal ElementV); - + void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst, SVal ElementV); + /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. - void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst); - + void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, ObjCMessageExpr::arg_iterator I, ObjCMessageExpr::arg_iterator E, - NodeTy* Pred, NodeSet& Dst); - - void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred, - NodeSet& Dst); - + ExplodedNode* Pred, ExplodedNodeSet& Dst); + + void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + /// VisitReturnStmt - Transfer function logic for return statements. - void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst); - + void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred, - NodeSet& Dst); - + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + /// VisitUnaryOperator - Transfer function logic for unary operators. - void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst, + void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); - - const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred, - SVal Denom); - + + const GRState* CheckDivideZero(Expr* Ex, const GRState* St, ExplodedNode* Pred, + SVal Denom); + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) /// with those assumptions. - void EvalEagerlyAssume(NodeSet& Dst, NodeSet& Src, Expr *Ex); - - SVal EvalCast(SVal X, QualType CastT) { - if (X.isUnknownOrUndef()) - return X; - - if (isa<Loc>(X)) - return SVator->EvalCast(cast<Loc>(X), CastT); - else - return SVator->EvalCast(cast<NonLoc>(X), CastT); - } - + void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex); + SVal EvalMinus(SVal X) { - return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X; + return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X; } - + SVal EvalComplement(SVal X) { - return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X; + return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X; } - + + bool EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + public: - - 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() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R; + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + NonLoc L, NonLoc R, QualType T) { + return SVator.EvalBinOpNN(state, op, L, R, T); } - + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, - SVal lhs, SVal rhs, QualType T); + NonLoc L, SVal R, QualType T) { + return R.isValid() ? SVator.EvalBinOpNN(state, op, L, cast<NonLoc>(R), T) : R; + } -protected: - - void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred); + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal LHS, SVal RHS, QualType T) { + return SVator.EvalBinOp(ST, Op, LHS, RHS, T); + } - void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) { +protected: + void EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, ExplodedNode* Pred); + + void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* Pred) { assert (Builder && "GRStmtNodeBuilder must be defined."); getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred); } - void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred); - - const GRState* MarkBranch(const GRState* St, Stmt* Terminator, + void EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* s, ExplodedNode* Pred); + + const GRState* MarkBranch(const GRState* St, Stmt* Terminator, bool branchTaken); - + /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore, VisitDeclStmt, and others. - void EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + void EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, SVal Val); - + public: - void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag = 0); - - NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred, + + ExplodedNode* EvalLocation(Stmt* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag = 0); - - void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St, + + void EvalStore(ExplodedNodeSet& Dst, Expr* E, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, const void *tag = 0); - - void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred, + + void EvalStore(ExplodedNodeSet& Dst, Expr* E, Expr* StoreE, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, const void *tag = 0); - + }; - + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h index 0f3a1372a0f0..60db406cd13d 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h @@ -15,38 +15,15 @@ #ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS #define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/Support/SaveAndRestore.h" namespace clang { - - -// SaveAndRestore - A utility class that uses RAII to save and restore -// the value of a variable. -template<typename T> -struct SaveAndRestore { - SaveAndRestore(T& x) : X(x), old_value(x) {} - ~SaveAndRestore() { X = old_value; } - T get() { return old_value; } -private: - T& X; - T old_value; -}; - -// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old -// value of a variable is saved, and during the dstor the old value is -// or'ed with the new value. -struct SaveOr { - SaveOr(bool& x) : X(x), old_value(x) { x = false; } - ~SaveOr() { X |= old_value; } -private: - bool& X; - const bool old_value; -}; class GRStmtNodeBuilderRef { - GRExprEngine::NodeSet &Dst; - GRExprEngine::StmtNodeBuilder &B; + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; GRExprEngine& Eng; - GRExprEngine::NodeTy* Pred; + ExplodedNode* Pred; const GRState* state; const Stmt* stmt; const unsigned OldSize; @@ -57,25 +34,25 @@ class GRStmtNodeBuilderRef { private: friend class GRExprEngine; - + GRStmtNodeBuilderRef(); // do not implement void operator=(const GRStmtNodeBuilderRef&); // do not implement - - GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst, - GRExprEngine::StmtNodeBuilder &builder, + + GRStmtNodeBuilderRef(ExplodedNodeSet &dst, + GRStmtNodeBuilder &builder, GRExprEngine& eng, - GRExprEngine::NodeTy* pred, + ExplodedNode* pred, const GRState *st, const Stmt* s, bool auto_create_node) : Dst(dst), B(builder), Eng(eng), Pred(pred), state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {} - + public: ~GRStmtNodeBuilderRef() { // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. + // contains the updated state if we aren't generating sinks. if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { if (AutoCreateNode) B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); @@ -85,14 +62,14 @@ public: } const GRState *getState() { return state; } - + GRStateManager& getStateManager() { return Eng.getStateManager(); } - - GRExprEngine::NodeTy* MakeNode(const GRState* state) { - return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); - } + + ExplodedNode* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index e54b31dfe883..978ff0889e64 100644 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -20,16 +20,16 @@ #include "clang/Analysis/PathSensitive/GRState.h" namespace clang { - + class Diagnostic; class BugReporter; class ASTContext; class GRExprEngine; class PathDiagnosticClient; -template <typename T> class ExplodedGraph; - - -class GRSimpleAPICheck : public GRAuditor<GRState> { +class ExplodedGraph; + + +class GRSimpleAPICheck : public GRAuditor { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index 0da8f5243e9c..d8b9d560ccd8 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -49,12 +49,12 @@ typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); //===----------------------------------------------------------------------===// // GRStateTrait - Traits used by the Generic Data Map of a GRState. //===----------------------------------------------------------------------===// - + template <typename T> struct GRStatePartialTrait; template <typename T> struct GRStateTrait { typedef typename T::data_type data_type; - static inline void* GDMIndex() { return &T::TagInt; } + static inline void* GDMIndex() { return &T::TagInt; } static inline void* MakeVoidPtr(data_type D) { return (void*) D; } static inline data_type MakeData(void* const* P) { return P ? (data_type) *P : (data_type) 0; @@ -66,68 +66,78 @@ template <typename T> struct GRStateTrait { //===----------------------------------------------------------------------===// class GRStateManager; - + /// GRState - This class encapsulates the actual data values for /// for a "state" in our symbolic value tracking. It is intended to be /// used as a functional object; that is once it is created and made /// "persistent" in a FoldingSet its values will never change. class GRState : public llvm::FoldingSetNode { -public: - // Typedefs. +public: typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; - typedef llvm::ImmutableMap<void*, void*> GenericDataMap; - - typedef GRStateManager ManagerTy; - + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + private: void operator=(const GRState& R) const; - + friend class GRStateManager; - GRStateManager *Mgr; + GRStateManager *StateMgr; Environment Env; Store St; // FIXME: Make these private. public: GenericDataMap GDM; - + public: - + /// This ctor is used when creating the first GRState object. - GRState(GRStateManager *mgr, const Environment& env, Store st, - GenericDataMap gdm) - : Mgr(mgr), + GRState(GRStateManager *mgr, const Environment& env, + Store st, GenericDataMap gdm) + : StateMgr(mgr), Env(env), St(st), GDM(gdm) {} - + /// Copy ctor - We must explicitly define this or else the "Next" ptr /// in FoldingSetNode will also get copied. GRState(const GRState& RHS) : llvm::FoldingSetNode(), - Mgr(RHS.Mgr), + StateMgr(RHS.StateMgr), Env(RHS.Env), St(RHS.St), GDM(RHS.GDM) {} - + /// getStateManager - Return the GRStateManager associated with this state. - GRStateManager &getStateManager() const { return *Mgr; } - + GRStateManager &getStateManager() const { + return *StateMgr; + } + + /// getAnalysisContext - Return the AnalysisContext associated with this + /// state. + AnalysisContext &getAnalysisContext() const { + return Env.getAnalysisContext(); + } + /// getEnvironment - Return the environment associated with this state. /// The environment is the mapping from expressions to values. const Environment& getEnvironment() const { return Env; } - + /// getStore - Return the store associated with this state. The store /// is a mapping from locations to values. Store getStore() const { return St; } - + + void setStore(Store s) { St = s; } + /// getGDM - Return the generic data map associated with this state. GenericDataMap getGDM() const { return GDM; } - + + void setGDM(GenericDataMap gdm) { GDM = gdm; } + /// Profile - Profile the contents of a GRState object for use /// in a FoldingSet. static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { + // FIXME: Do we need to include the AnalysisContext in the profile? V->Env.Profile(ID); ID.AddPointer(V->St); V->GDM.Profile(ID); @@ -138,28 +148,19 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, this); } - + SVal LookupExpr(Expr* E) const { return Env.LookupExpr(E); } - + /// makeWithStore - Return a GRState with the same values as the current /// state with the exception of using the specified Store. const GRState *makeWithStore(Store store) const; - - // Iterators. - typedef Environment::seb_iterator seb_iterator; - seb_iterator seb_begin() const { return Env.seb_begin(); } - seb_iterator seb_end() const { return Env.beb_end(); } - - typedef Environment::beb_iterator beb_iterator; - beb_iterator beb_begin() const { return Env.beb_begin(); } - beb_iterator beb_end() const { return Env.beb_end(); } - + BasicValueFactory &getBasicVals() const; SymbolManager &getSymbolManager() const; GRTransferFuncs &getTransferFuncs() const; - + //==---------------------------------------------------------------------==// // Constraints on values. //==---------------------------------------------------------------------==// @@ -192,91 +193,85 @@ public: // FIXME: (a) should probably disappear since it is redundant with (b). // (i.e., (b) could just be set to NULL). // - - const GRState *assume(SVal condition, bool assumption) const; - - const GRState *assumeInBound(SVal idx, SVal upperBound, + + const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const; + + const GRState *AssumeInBound(DefinedOrUnknownSVal idx, + DefinedOrUnknownSVal upperBound, bool assumption) const; - + //==---------------------------------------------------------------------==// // Utility methods for getting regions. //==---------------------------------------------------------------------==// - const VarRegion* getRegion(const VarDecl* D) const; - - const MemRegion* getSelfRegion() const; + const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; //==---------------------------------------------------------------------==// // Binding and retrieving values to/from the environment and symbolic store. //==---------------------------------------------------------------------==// - + /// BindCompoundLiteral - Return the state that has the bindings currently /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region /// for the compound literal and 'BegInit' and 'EndInit' represent an /// array of initializer values. const GRState* bindCompoundLiteral(const CompoundLiteralExpr* CL, SVal V) const; - - const GRState *bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr, - bool Invalidate) const; - - const GRState *bindExpr(const Stmt* Ex, SVal V, bool Invalidate = true) const; - - const GRState *bindBlkExpr(const Stmt *Ex, SVal V) const { - return bindExpr(Ex, V, true, false); - } - - const GRState *bindDecl(const VarDecl* VD, SVal IVal) const; - - const GRState *bindDeclWithNoInit(const VarDecl* VD) const; - + + const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; + + const GRState *bindDecl(const VarDecl *VD, const LocationContext *LC, + SVal V) const; + + const GRState *bindDeclWithNoInit(const VarDecl *VD, + const LocationContext *LC) const; + const GRState *bindLoc(Loc location, SVal V) const; - + const GRState *bindLoc(SVal location, SVal V) const; - + const GRState *unbindLoc(Loc LV) const; /// Get the lvalue for a variable reference. - SVal getLValue(const VarDecl *decl) const; - + SVal getLValue(const VarDecl *D, const LocationContext *LC) const; + /// Get the lvalue for a StringLiteral. SVal getLValue(const StringLiteral *literal) const; - + SVal getLValue(const CompoundLiteralExpr *literal) const; - + /// Get the lvalue for an ivar reference. SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; - + /// Get the lvalue for a field reference. - SVal getLValue(SVal Base, const FieldDecl *decl) const; - + SVal getLValue(const FieldDecl *decl, SVal Base) const; + /// Get the lvalue for an array index. - SVal getLValue(QualType ElementType, SVal Base, SVal Idx) const; - + SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; + const llvm::APSInt *getSymVal(SymbolRef sym) const; SVal getSVal(const Stmt* Ex) const; - - SVal getBlkExprSVal(const Stmt* Ex) const; - + SVal getSValAsScalarOrLoc(const Stmt *Ex) const; - + SVal getSVal(Loc LV, QualType T = QualType()) const; - + SVal getSVal(const MemRegion* R) const; - + SVal getSValAsScalarOrLoc(const MemRegion *R) const; + const llvm::APSInt *getSymVal(SymbolRef sym); + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; template <typename CB> CB scanReachableSymbols(SVal val) const; - + //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). //==---------------------------------------------------------------------==// void* const* FindGDM(void* K) const; - + template<typename T> const GRState *add(typename GRStateTrait<T>::key_type K) const; @@ -285,31 +280,31 @@ public: get() const { return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex())); } - + template<typename T> typename GRStateTrait<T>::lookup_type get(typename GRStateTrait<T>::key_type key) const { void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key); } - + template <typename T> typename GRStateTrait<T>::context_type get_context() const; - - + + template<typename T> const GRState *remove(typename GRStateTrait<T>::key_type K) const; template<typename T> const GRState *remove(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) const; - + template<typename T> const GRState *set(typename GRStateTrait<T>::data_type D) const; - + template<typename T> const GRState *set(typename GRStateTrait<T>::key_type K, - typename GRStateTrait<T>::value_type E) const; + typename GRStateTrait<T>::value_type E) const; template<typename T> const GRState *set(typename GRStateTrait<T>::key_type K, @@ -321,7 +316,7 @@ public: void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key); } - + // State pretty-printing. class Printer { public: @@ -329,66 +324,55 @@ public: virtual void Print(llvm::raw_ostream& Out, const GRState* state, const char* nl, const char* sep) = 0; }; - + // Pretty-printing. void print(llvm::raw_ostream& Out, const char *nl = "\n", - const char *sep = "") const; + const char *sep = "") const; + + void printStdErr() const; + + void printDOT(llvm::raw_ostream& Out) const; - void printStdErr() const; - - void printDOT(llvm::raw_ostream& Out) const; - // Tags used for the Generic Data Map. struct NullDerefTag { static int TagInt; typedef const SVal* data_type; }; }; - -template<> struct GRTrait<GRState*> { - static inline void* toPtr(GRState* St) { return (void*) St; } - static inline GRState* toState(void* P) { return (GRState*) P; } - static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) { - // At this point states have already been uniqued. Just - // add the pointer. - profile.AddPointer(St); - } -}; - - + class GRStateSet { typedef llvm::SmallPtrSet<const GRState*,5> ImplTy; - ImplTy Impl; + ImplTy Impl; public: GRStateSet() {} inline void Add(const GRState* St) { Impl.insert(St); } - + typedef ImplTy::const_iterator iterator; - + inline unsigned size() const { return Impl.size(); } inline bool empty() const { return Impl.empty(); } - + inline iterator begin() const { return Impl.begin(); } inline iterator end() const { return Impl.end(); } - + class AutoPopulate { GRStateSet& S; unsigned StartSize; const GRState* St; public: - AutoPopulate(GRStateSet& s, const GRState* st) + AutoPopulate(GRStateSet& s, const GRState* st) : S(s), StartSize(S.size()), St(st) {} - + ~AutoPopulate() { if (StartSize == S.size()) S.Add(St); } }; -}; - +}; + //===----------------------------------------------------------------------===// // GRStateManager - Factory object for GRStates. //===----------------------------------------------------------------------===// @@ -396,22 +380,21 @@ public: class GRStateManager { friend class GRExprEngine; friend class GRState; - + private: EnvironmentManager EnvMgr; llvm::OwningPtr<StoreManager> StoreMgr; llvm::OwningPtr<ConstraintManager> ConstraintMgr; - GRState::IntSetTy::Factory ISetFactory; - + GRState::GenericDataMap::Factory GDMFactory; - + typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; GDMContextsTy GDMContexts; - + /// Printers - A set of printer objects used for pretty-printing a GRState. /// GRStateManager owns these objects. std::vector<GRState::Printer*> Printers; - + /// StateSet - FoldingSet containing all the states created for analyzing /// a particular function. This is used to unique states. llvm::FoldingSet<GRState> StateSet; @@ -421,52 +404,36 @@ private: /// Alloc - A BumpPtrAllocator to allocate states. llvm::BumpPtrAllocator& Alloc; - + /// CurrentStmt - The block-level statement currently being visited. This /// is set by GRExprEngine. Stmt* CurrentStmt; - - /// cfg - The CFG for the analyzed function/method. - CFG& cfg; - - /// codedecl - The Decl representing the function/method being analyzed. - const Decl& codedecl; - + /// TF - Object that represents a bundle of transfer functions /// for manipulating and creating SVals. GRTransferFuncs* TF; - /// 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; - public: - + GRStateManager(ASTContext& Ctx, StoreManagerCreator CreateStoreManager, ConstraintManagerCreator CreateConstraintManager, - llvm::BumpPtrAllocator& alloc, CFG& c, - const Decl& cd, LiveVariables& L) - : EnvMgr(alloc), - ISetFactory(alloc), - GDMFactory(alloc), - ValueMgr(alloc, Ctx), - Alloc(alloc), - cfg(c), - codedecl(cd), - Liveness(L) { - StoreMgr.reset((*CreateStoreManager)(*this)); - ConstraintMgr.reset((*CreateConstraintManager)(*this)); + llvm::BumpPtrAllocator& alloc) + : EnvMgr(alloc), + GDMFactory(alloc), + ValueMgr(alloc, Ctx, *this), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this)); } - + ~GRStateManager(); - const GRState *getInitialState(); - + const GRState *getInitialState(const LocationContext *InitLoc); + ASTContext &getContext() { return ValueMgr.getContext(); } - const ASTContext &getContext() const { return ValueMgr.getContext(); } - - const Decl &getCodeDecl() { return codedecl; } + const ASTContext &getContext() const { return ValueMgr.getContext(); } + GRTransferFuncs& getTransferFuncs() { return *TF; } BasicValueFactory &getBasicVals() { @@ -475,18 +442,17 @@ public: const BasicValueFactory& getBasicVals() const { return ValueMgr.getBasicValueFactory(); } - + SymbolManager &getSymbolManager() { return ValueMgr.getSymbolManager(); } const SymbolManager &getSymbolManager() const { return ValueMgr.getSymbolManager(); } - + ValueManager &getValueManager() { return ValueMgr; } const ValueManager &getValueManager() const { return ValueMgr; } - - LiveVariables& getLiveVariables() { return Liveness; } + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } MemRegionManager& getRegionManager() { @@ -495,28 +461,22 @@ public: const MemRegionManager& getRegionManager() const { return ValueMgr.getRegionManager(); } - + StoreManager& getStoreManager() { return *StoreMgr; } ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, SymbolReaper& SymReaper); - const GRState* RemoveSubExprBindings(const GRState* St) { - GRState NewSt = *St; - NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env); - return getPersistentState(NewSt); - } - public: SVal ArrayToPointer(Loc Array) { return StoreMgr->ArrayToPointer(Array); } - + // Methods that manipulate the GDM. const GRState* addGDM(const GRState* St, void* Key, void* Data); - + // Methods that query & manipulate the Store. void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { @@ -525,9 +485,9 @@ public: const GRState* getPersistentState(GRState& Impl); - bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V); - bool isEqual(const GRState* state, Expr* Ex, uint64_t); - + bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V); + bool isEqual(const GRState* state, const Expr* Ex, uint64_t); + //==---------------------------------------------------------------------==// // Generic Data Map methods. //==---------------------------------------------------------------------==// @@ -545,21 +505,21 @@ public: // The templated methods below use the GRStateTrait<T> class // to resolve keys into the GDM and to return data values to clients. // - - // Trait based GDM dispatch. + + // Trait based GDM dispatch. template <typename T> const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) { return addGDM(st, GRStateTrait<T>::GDMIndex(), GRStateTrait<T>::MakeVoidPtr(D)); } - + template<typename T> const GRState* set(const GRState* st, typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::value_type V, typename GRStateTrait<T>::context_type C) { - - return addGDM(st, GRStateTrait<T>::GDMIndex(), + + return addGDM(st, GRStateTrait<T>::GDMIndex(), GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C))); } @@ -575,22 +535,22 @@ public: const GRState* remove(const GRState* st, typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) { - - return addGDM(st, GRStateTrait<T>::GDMIndex(), + + return addGDM(st, GRStateTrait<T>::GDMIndex(), GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C))); } - + void* FindGDMContext(void* index, void* (*CreateContext)(llvm::BumpPtrAllocator&), void (*DeleteContext)(void*)); - + template <typename T> typename GRStateTrait<T>::context_type get_context() { void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(), GRStateTrait<T>::CreateContext, GRStateTrait<T>::DeleteContext); - + return GRStateTrait<T>::MakeContext(p); } @@ -602,84 +562,96 @@ public: ConstraintMgr->EndPath(St); } }; - + //===----------------------------------------------------------------------===// // Out-of-line method definitions for GRState. //===----------------------------------------------------------------------===// -inline const VarRegion* GRState::getRegion(const VarDecl* D) const { - return Mgr->getRegionManager().getVarRegion(D); +inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) { + return getStateManager().getSymVal(this, sym); } - -inline const MemRegion* GRState::getSelfRegion() const { - return Mgr->StoreMgr->getSelfRegion(getStore()); + +inline const VarRegion* GRState::getRegion(const VarDecl *D, + const LocationContext *LC) const { + return getStateManager().getRegionManager().getVarRegion(D, LC); } + +inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond, + bool Assumption) const { + if (Cond.isUnknown()) + return this; -inline const GRState *GRState::assume(SVal Cond, bool Assumption) const { - return Mgr->ConstraintMgr->Assume(this, Cond, Assumption); + return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond), + Assumption); } -inline const GRState *GRState::assumeInBound(SVal Idx, SVal UpperBound, +inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, + DefinedOrUnknownSVal UpperBound, bool Assumption) const { - return Mgr->ConstraintMgr->AssumeInBound(this, Idx, UpperBound, Assumption); -} + if (Idx.isUnknown() || UpperBound.isUnknown()) + return this; + + ConstraintManager &CM = *getStateManager().ConstraintMgr; + return CM.AssumeInBound(this, cast<DefinedSVal>(Idx), + cast<DefinedSVal>(UpperBound), Assumption); +} inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, SVal V) const { - return Mgr->StoreMgr->BindCompoundLiteral(this, CL, V); + return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V); } - -inline const GRState *GRState::bindDecl(const VarDecl* VD, SVal IVal) const { - return Mgr->StoreMgr->BindDecl(this, VD, IVal); + +inline const GRState *GRState::bindDecl(const VarDecl* VD, + const LocationContext *LC, + SVal IVal) const { + return getStateManager().StoreMgr->BindDecl(this, VD, LC, IVal); } -inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD) const { - return Mgr->StoreMgr->BindDeclWithNoInit(this, VD); +inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->BindDeclWithNoInit(this, VD, LC); } - + inline const GRState *GRState::bindLoc(Loc LV, SVal V) const { - return Mgr->StoreMgr->Bind(this, LV, V); + return getStateManager().StoreMgr->Bind(this, LV, V); } inline const GRState *GRState::bindLoc(SVal LV, SVal V) const { return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V); } - -inline SVal GRState::getLValue(const VarDecl* VD) const { - return Mgr->StoreMgr->getLValueVar(this, VD); + +inline SVal GRState::getLValue(const VarDecl* VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueVar(VD, LC); } inline SVal GRState::getLValue(const StringLiteral *literal) const { - return Mgr->StoreMgr->getLValueString(this, literal); + return getStateManager().StoreMgr->getLValueString(literal); } - + inline SVal GRState::getLValue(const CompoundLiteralExpr *literal) const { - return Mgr->StoreMgr->getLValueCompoundLiteral(this, literal); + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal); } inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const { - return Mgr->StoreMgr->getLValueIvar(this, D, Base); + return getStateManager().StoreMgr->getLValueIvar(D, Base); } - -inline SVal GRState::getLValue(SVal Base, const FieldDecl* D) const { - return Mgr->StoreMgr->getLValueField(this, Base, D); + +inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const { + return getStateManager().StoreMgr->getLValueField(D, Base); } - -inline SVal GRState::getLValue(QualType ElementType, SVal Base, SVal Idx) const{ - return Mgr->StoreMgr->getLValueElement(this, ElementType, Base, Idx); + +inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ + return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base); } - + inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { - return Mgr->getSymVal(this, sym); -} - -inline SVal GRState::getSVal(const Stmt* Ex) const { - return Env.GetSVal(Ex, Mgr->ValueMgr); + return getStateManager().getSymVal(this, sym); } -inline SVal GRState::getBlkExprSVal(const Stmt* Ex) const { - return Env.GetBlkExprSVal(Ex, Mgr->ValueMgr); +inline SVal GRState::getSVal(const Stmt* Ex) const { + return Env.GetSVal(Ex, getStateManager().ValueMgr); } inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { @@ -688,69 +660,69 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { if (Loc::IsLocType(T) || T->isIntegerType()) return getSVal(S); } - + return UnknownVal(); } inline SVal GRState::getSVal(Loc LV, QualType T) const { - return Mgr->StoreMgr->Retrieve(this, LV, T); + return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal(); } inline SVal GRState::getSVal(const MemRegion* R) const { - return Mgr->StoreMgr->Retrieve(this, loc::MemRegionVal(R)); + return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal(); } - + inline BasicValueFactory &GRState::getBasicVals() const { - return Mgr->getBasicVals(); + return getStateManager().getBasicVals(); } inline SymbolManager &GRState::getSymbolManager() const { - return Mgr->getSymbolManager(); + return getStateManager().getSymbolManager(); } - + inline GRTransferFuncs &GRState::getTransferFuncs() const { - return Mgr->getTransferFuncs(); + return getStateManager().getTransferFuncs(); } template<typename T> const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const { - return Mgr->add<T>(this, K, get_context<T>()); + return getStateManager().add<T>(this, K, get_context<T>()); } - + template <typename T> typename GRStateTrait<T>::context_type GRState::get_context() const { - return Mgr->get_context<T>(); + return getStateManager().get_context<T>(); } - + template<typename T> const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const { - return Mgr->remove<T>(this, K, get_context<T>()); + return getStateManager().remove<T>(this, K, get_context<T>()); } template<typename T> const GRState *GRState::remove(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::context_type C) const { - return Mgr->remove<T>(this, K, C); + return getStateManager().remove<T>(this, K, C); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const { - return Mgr->set<T>(this, D); + return getStateManager().set<T>(this, D); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::value_type E) const { - return Mgr->set<T>(this, K, E, get_context<T>()); + return getStateManager().set<T>(this, K, E, get_context<T>()); } - + template<typename T> const GRState *GRState::set(typename GRStateTrait<T>::key_type K, typename GRStateTrait<T>::value_type E, typename GRStateTrait<T>::context_type C) const { - return Mgr->set<T>(this, K, E, C); + return getStateManager().set<T>(this, K, E, C); } - + template <typename CB> CB GRState::scanReachableSymbols(SVal val) const { CB cb(this); diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h index ce43cda31e9e..5189a1f5aa7e 100644 --- a/include/clang/Analysis/PathSensitive/GRStateTrait.h +++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h @@ -1,5 +1,5 @@ //==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -27,59 +27,59 @@ namespace llvm { namespace clang { template <typename T> struct GRStatePartialTrait; - + // Partial-specialization for ImmutableMap. - + template <typename Key, typename Data, typename Info> struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { typedef llvm::ImmutableMap<Key,Data,Info> data_type; - typedef typename data_type::Factory& context_type; + typedef typename data_type::Factory& context_type; typedef Key key_type; typedef Data value_type; typedef const value_type* lookup_type; - + static inline data_type MakeData(void* const* p) { return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); - } + } static inline void* MakeVoidPtr(data_type B) { return B.getRoot(); - } + } static lookup_type Lookup(data_type B, key_type K) { return B.lookup(K); - } + } static data_type Set(data_type B, key_type K, value_type E,context_type F){ return F.Add(B, K, E); } - + static data_type Remove(data_type B, key_type K, context_type F) { return F.Remove(B, K); } - + static inline context_type MakeContext(void* p) { return *((typename data_type::Factory*) p); } - + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); + return new typename data_type::Factory(Alloc); } - + static void DeleteContext(void* Ctx) { delete (typename data_type::Factory*) Ctx; - } + } }; - - + + // Partial-specialization for ImmutableSet. - + template <typename Key, typename Info> struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > { typedef llvm::ImmutableSet<Key,Info> data_type; - typedef typename data_type::Factory& context_type; + typedef typename data_type::Factory& context_type; typedef Key key_type; - + static inline data_type MakeData(void* const* p) { return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); - } + } static inline void* MakeVoidPtr(data_type B) { return B.getRoot(); @@ -88,60 +88,60 @@ namespace clang { static data_type Add(data_type B, key_type K, context_type F) { return F.Add(B, K); } - + static data_type Remove(data_type B, key_type K, context_type F) { return F.Remove(B, K); } - + static bool Contains(data_type B, key_type K) { return B.contains(K); } - + static inline context_type MakeContext(void* p) { return *((typename data_type::Factory*) p); } - + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); + return new typename data_type::Factory(Alloc); } - + static void DeleteContext(void* Ctx) { delete (typename data_type::Factory*) Ctx; - } + } }; - + // Partial-specialization for ImmutableList. - + template <typename T> struct GRStatePartialTrait< llvm::ImmutableList<T> > { typedef llvm::ImmutableList<T> data_type; typedef T key_type; - typedef typename data_type::Factory& context_type; - + typedef typename data_type::Factory& context_type; + static data_type Add(data_type L, key_type K, context_type F) { return F.Add(K, L); } - + static inline data_type MakeData(void* const* p) { - return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) + return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) : data_type(0); - } - + } + static inline void* MakeVoidPtr(data_type D) { return (void*) D.getInternalPointer(); - } - + } + static inline context_type MakeContext(void* p) { return *((typename data_type::Factory*) p); } - + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); + return new typename data_type::Factory(Alloc); } - + static void DeleteContext(void* Ctx) { delete (typename data_type::Factory*) Ctx; - } + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h new file mode 100644 index 000000000000..62e36f9e641e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRSubEngine.h @@ -0,0 +1,68 @@ +//== GRSubEngine.h - Interface of the subengine of GRCoreEngine ----*- 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 the interface of a subengine of the GRCoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H +#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H + +namespace clang { + +class Stmt; +class CFGBlock; +class GRState; +class GRStateManager; +class GRBlockCounter; +class GRStmtNodeBuilder; +class GRBranchNodeBuilder; +class GRIndirectGotoNodeBuilder; +class GRSwitchNodeBuilder; +class GREndPathNodeBuilder; +class LocationContext; + +class GRSubEngine { +public: + virtual ~GRSubEngine() {} + + virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; + + virtual GRStateManager& getStateManager() = 0; + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) = 0; + + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. + virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC) = 0; + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void ProcessBranch(Stmt* Condition, Stmt* Term, + GRBranchNodeBuilder& builder) = 0; + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0; + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; +}; + +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index db23f81e2d67..5f7b2cb0e327 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -21,66 +21,68 @@ #include <vector> namespace clang { - + class GRExprEngine; class BugReporter; class ObjCMessageExpr; class GRStmtNodeBuilderRef; - + class GRTransferFuncs { public: GRTransferFuncs() {} virtual ~GRTransferFuncs() {} - + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} virtual void RegisterChecks(BugReporter& BR) {} - + // Calls. - - virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, + + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode<GRState>* Pred) {} - - virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, + ExplodedNode* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode<GRState>* Pred) {} - + ExplodedNode* Pred) {} + // Stores. - + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} - + // End-of-path and dead symbol notification. - + virtual void EvalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder<GRState>& Builder) {} - - - virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst, + GREndPathNodeBuilder& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, - ExplodedNode<GRState>* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper) {} - - // Return statements. - virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst, + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder<GRState>& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode<GRState>* Pred) {} + ExplodedNode* Pred) {} - // Assumptions. + // Assumptions. virtual const GRState* EvalAssume(const GRState *state, SVal Cond, bool Assumption) { return state; } }; - + +GRTransferFuncs *CreateCallInliner(ASTContext &ctx); + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h index c76532294c1f..17b83fdf9fdc 100644 --- a/include/clang/Analysis/PathSensitive/GRWorkList.h +++ b/include/clang/Analysis/PathSensitive/GRWorkList.h @@ -1,5 +1,5 @@ //==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -17,31 +17,31 @@ #include "clang/Analysis/PathSensitive/GRBlockCounter.h" -namespace clang { +namespace clang { class ExplodedNodeImpl; - + class GRWorkListUnit { - ExplodedNodeImpl* Node; + ExplodedNode* Node; GRBlockCounter Counter; CFGBlock* Block; unsigned BlockIdx; - + public: - GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C, + GRWorkListUnit(ExplodedNode* N, GRBlockCounter C, CFGBlock* B, unsigned idx) : Node(N), Counter(C), Block(B), BlockIdx(idx) {} - - explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C) + + explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C) : Node(N), Counter(C), Block(NULL), BlockIdx(0) {} - - ExplodedNodeImpl* getNode() const { return Node; } + + ExplodedNode* getNode() const { return Node; } GRBlockCounter getBlockCounter() const { return Counter; } CFGBlock* getBlock() const { return Block; } unsigned getIndex() const { return BlockIdx; } @@ -52,25 +52,25 @@ class GRWorkList { public: virtual ~GRWorkList(); virtual bool hasWork() const = 0; - + virtual void Enqueue(const GRWorkListUnit& U) = 0; - void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) { + void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) { Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); } - - void Enqueue(ExplodedNodeImpl* N) { + + void Enqueue(ExplodedNode* N) { Enqueue(GRWorkListUnit(N, CurrentCounter)); } - + virtual GRWorkListUnit Dequeue() = 0; - + void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; } GRBlockCounter getBlockCounter() const { return CurrentCounter; } - + static GRWorkList *MakeDFS(); static GRWorkList *MakeBFS(); static GRWorkList *MakeBFSBlockDFSContents(); }; -} // end clang namespace +} // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 5926229e517c..0e487691a891 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -31,10 +31,15 @@ namespace llvm { class raw_ostream; } namespace clang { - + class MemRegionManager; -class MemSpaceRegion; - +class MemSpaceRegion; +class LocationContext; + +//===----------------------------------------------------------------------===// +// Base region classes. +//===----------------------------------------------------------------------===// + /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { public: @@ -46,55 +51,57 @@ public: CodeTextRegionKind, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, - TypedViewRegionKind, // Decl Regions. BEG_DECL_REGIONS, VarRegionKind, FieldRegionKind, ObjCIvarRegionKind, ObjCObjectRegionKind, END_DECL_REGIONS, - END_TYPED_REGIONS }; + END_TYPED_REGIONS }; private: const Kind kind; - + protected: MemRegion(Kind k) : kind(k) {} virtual ~MemRegion(); - ASTContext &getContext() const; public: + ASTContext &getContext() const; + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; virtual MemRegionManager* getMemRegionManager() const = 0; std::string getString() const; - + const MemSpaceRegion *getMemorySpace() const; - + + const MemRegion *getBaseRegion() const; + bool hasStackStorage() const; - + bool hasParametersStorage() const; - + bool hasGlobalsStorage() const; - + bool hasGlobalsOrParametersStorage() const; - + bool hasHeapStorage() const; - + bool hasHeapOrStackStorage() const; - virtual void print(llvm::raw_ostream& os) const; + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void dump() const; + + Kind getKind() const { return kind; } - void printStdErr() const; - - Kind getKind() const { return kind; } - template<typename RegionTy> const RegionTy* getAs() const; - + virtual bool isBoundable() const { return false; } static bool classof(const MemRegion*) { return true; } }; - + /// MemSpaceRegion - A memory region that represents and "memory space"; /// for example, the set of global variables, the stack frame, etc. class MemSpaceRegion : public MemRegion { @@ -105,7 +112,7 @@ protected: MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind), Mgr(mgr) {} - + MemRegionManager* getMemRegionManager() const { return Mgr; } @@ -124,13 +131,13 @@ public: /// are subclasses of SubRegion. class SubRegion : public MemRegion { protected: - const MemRegion* superRegion; + const MemRegion* superRegion; SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} public: const MemRegion* getSuperRegion() const { return superRegion; } - + MemRegionManager* getMemRegionManager() const; bool isSubRegionOf(const MemRegion* R) const; @@ -140,6 +147,32 @@ public: } }; +//===----------------------------------------------------------------------===// +// Auxillary data classes for use with MemRegions. +//===----------------------------------------------------------------------===// + +class ElementRegion; + +class RegionRawOffset : public std::pair<const MemRegion*, int64_t> { +private: + friend class ElementRegion; + + RegionRawOffset(const MemRegion* reg, int64_t offset = 0) + : std::pair<const MemRegion*, int64_t>(reg, offset) {} + +public: + // FIXME: Eventually support symbolic offsets. + int64_t getByteOffset() const { return second; } + const MemRegion *getRegion() const { return first; } + + void dumpToStream(llvm::raw_ostream& os) const; + void dump() const; +}; + +//===----------------------------------------------------------------------===// +// MemRegion subclasses. +//===----------------------------------------------------------------------===// + /// AllocaRegion - A region that represents an untyped blob of bytes created /// by a call to 'alloca'. class AllocaRegion : public SubRegion { @@ -151,43 +184,45 @@ protected: AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion) : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} - + public: - + const Expr* getExpr() const { return Ex; } - + + bool isBoundable() const { return true; } + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, unsigned Cnt, const MemRegion *superRegion); - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == AllocaRegionKind; } -}; - +}; + /// TypedRegion - An abstract class representing regions that are typed. class TypedRegion : public SubRegion { protected: TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} - + public: virtual QualType getValueType(ASTContext &C) const = 0; - + virtual QualType getLocationType(ASTContext& C) const { // FIXME: We can possibly optimize this later to cache this value. return C.getPointerType(getValueType(C)); } - + QualType getDesugaredValueType(ASTContext& C) const { QualType T = getValueType(C); - return T.getTypePtr() ? T->getDesugaredType() : T; + return T.getTypePtr() ? T.getDesugaredType() : T; } - + QualType getDesugaredLocationType(ASTContext& C) const { - return getLocationType(C)->getDesugaredType(); + return getLocationType(C).getDesugaredType(); } bool isBoundable() const { @@ -205,32 +240,12 @@ public: /// is a function declared in the program. Symbolic function is a function /// pointer that we don't know which function it points to. class CodeTextRegion : public TypedRegion { -public: - enum CodeKind { Declared, Symbolic }; - -private: - // The function pointer kind that this CodeTextRegion represents. - CodeKind codekind; - - // Data may be a SymbolRef or FunctionDecl*. - const void* Data; - - // Cached function pointer type. - QualType LocationType; + const FunctionDecl *FD; public: - CodeTextRegion(const FunctionDecl* fd, QualType t, const MemRegion* sreg) - : TypedRegion(sreg, CodeTextRegionKind), - codekind(Declared), - Data(fd), - LocationType(t) {} - - CodeTextRegion(SymbolRef sym, QualType t, const MemRegion* sreg) - : TypedRegion(sreg, CodeTextRegionKind), - codekind(Symbolic), - Data(sym), - LocationType(t) {} + CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {} QualType getValueType(ASTContext &C) const { // Do not get the object type of a CodeTextRegion. @@ -239,30 +254,21 @@ public: } QualType getLocationType(ASTContext &C) const { - return LocationType; + return C.getPointerType(FD->getType()); } - bool isDeclared() const { return codekind == Declared; } - bool isSymbolic() const { return codekind == Symbolic; } - - const FunctionDecl* getDecl() const { - assert(codekind == Declared); - return static_cast<const FunctionDecl*>(Data); + const FunctionDecl *getDecl() const { + return FD; } - - SymbolRef getSymbol() const { - assert(codekind == Symbolic); - return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data)); - } - + bool isBoundable() const { return false; } - - virtual void print(llvm::raw_ostream& os) const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; void Profile(llvm::FoldingSetNodeID& ID) const; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - const void* data, QualType t, const MemRegion*); + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, + const MemRegion*); static bool classof(const MemRegion* R) { return R->getKind() == CodeTextRegionKind; @@ -279,25 +285,27 @@ protected: const SymbolRef sym; public: - SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) : SubRegion(sreg, SymbolicRegionKind), sym(s) {} - + SymbolRef getSymbol() const { return sym; } + bool isBoundable() const { return true; } + void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, const MemRegion* superRegion); - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == SymbolicRegionKind; } -}; +}; /// StringRegion - Region associated with a StringLiteral. class StringRegion : public TypedRegion { @@ -315,7 +323,7 @@ protected: public: const StringLiteral* getStringLiteral() const { return Str; } - + QualType getValueType(ASTContext& C) const { return Str->getType(); } @@ -326,53 +334,13 @@ public: ProfileRegion(ID, Str, superRegion); } - void print(llvm::raw_ostream& os) const; + void dumpToStream(llvm::raw_ostream& os) const; static bool classof(const MemRegion* R) { return R->getKind() == StringRegionKind; } }; -class TypedViewRegion : public TypedRegion { - friend class MemRegionManager; - QualType LValueType; - - TypedViewRegion(QualType lvalueType, const MemRegion* sreg) - : TypedRegion(sreg, TypedViewRegionKind), LValueType(lvalueType) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, - const MemRegion* superRegion); - -public: - - void print(llvm::raw_ostream& os) const; - - QualType getLocationType(ASTContext&) const { - return LValueType; - } - - QualType getValueType(ASTContext&) const { - const PointerType* PTy = LValueType->getAsPointerType(); - assert(PTy); - return PTy->getPointeeType(); - } - - bool isBoundable() const { - return isa<PointerType>(LValueType); - } - - void Profile(llvm::FoldingSetNodeID& ID) const { - ProfileRegion(ID, LValueType, superRegion); - } - - static bool classof(const MemRegion* R) { - return R->getKind() == TypedViewRegionKind; - } - - const MemRegion *removeViews() const; -}; - - /// CompoundLiteralRegion - A memory region representing a compound literal. /// Compound literals are essentially temporaries that are stack allocated /// or in the global constant pool. @@ -383,7 +351,7 @@ private: CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const CompoundLiteralExpr* CL, const MemRegion* superRegion); @@ -395,11 +363,11 @@ public: bool isBoundable() const { return !CL->isFileScope(); } void Profile(llvm::FoldingSetNodeID& ID) const; - - void print(llvm::raw_ostream& os) const; + + void dumpToStream(llvm::raw_ostream& os) const; const CompoundLiteralExpr* getLiteralExpr() const { return CL; } - + static bool classof(const MemRegion* R) { return R->getKind() == CompoundLiteralRegionKind; } @@ -414,41 +382,51 @@ protected: static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, const MemRegion* superRegion, Kind k); - + public: const Decl* getDecl() const { return D; } void Profile(llvm::FoldingSetNodeID& ID) const; - + static bool classof(const MemRegion* R) { unsigned k = R->getKind(); return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS; } }; - + class VarRegion : public DeclRegion { friend class MemRegionManager; - - VarRegion(const VarDecl* vd, const MemRegion* sReg) - : DeclRegion(vd, sReg, VarRegionKind) {} + + // Data. + const LocationContext *LC; + + // Constructors and private methods. + VarRegion(const VarDecl* vd, const LocationContext *lC, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind), LC(lC) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD, - const MemRegion* superRegion) { + const LocationContext *LC, + const MemRegion *superRegion) { DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + ID.AddPointer(LC); } - -public: - const VarDecl* getDecl() const { return cast<VarDecl>(D); } - - QualType getValueType(ASTContext& C) const { + + void Profile(llvm::FoldingSetNodeID& ID) const; + +public: + const VarDecl *getDecl() const { return cast<VarDecl>(D); } + + const LocationContext *getLocationContext() const { return LC; } + + QualType getValueType(ASTContext& C) const { // FIXME: We can cache this if needed. return C.getCanonicalType(getDecl()->getType()); - } - - void print(llvm::raw_ostream& os) const; - + } + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == VarRegionKind; - } + } }; class FieldRegion : public DeclRegion { @@ -458,57 +436,57 @@ class FieldRegion : public DeclRegion { : DeclRegion(fd, sReg, FieldRegionKind) {} public: - - void print(llvm::raw_ostream& os) const; - + + void dumpToStream(llvm::raw_ostream& os) const; + const FieldDecl* getDecl() const { return cast<FieldDecl>(D); } - - QualType getValueType(ASTContext& C) const { + + QualType getValueType(ASTContext& C) const { // FIXME: We can cache this if needed. return C.getCanonicalType(getDecl()->getType()); - } + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD, const MemRegion* superRegion) { DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); } - + static bool classof(const MemRegion* R) { return R->getKind() == FieldRegionKind; } }; - + class ObjCObjectRegion : public DeclRegion { - + friend class MemRegionManager; - + ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg) : DeclRegion(ivd, sReg, ObjCObjectRegionKind) {} - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCInterfaceDecl* ivd, const MemRegion* superRegion) { DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind); } - + public: const ObjCInterfaceDecl* getInterface() const { return cast<ObjCInterfaceDecl>(D); } - + QualType getValueType(ASTContext& C) const { return C.getObjCInterfaceType(getInterface()); } - + static bool classof(const MemRegion* R) { return R->getKind() == ObjCObjectRegionKind; } -}; - +}; + class ObjCIvarRegion : public DeclRegion { - + friend class MemRegionManager; - + ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} @@ -516,11 +494,13 @@ class ObjCIvarRegion : public DeclRegion { const MemRegion* superRegion) { DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); } - + public: const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); } QualType getValueType(ASTContext&) const { return getDecl()->getType(); } - + + void dumpToStream(llvm::raw_ostream& os) const; + static bool classof(const MemRegion* R) { return R->getKind() == ObjCIvarRegionKind; } @@ -539,7 +519,7 @@ class ElementRegion : public TypedRegion { cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && "The index must be signed"); } - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, SVal Idx, const MemRegion* superRegion); @@ -550,12 +530,14 @@ public: QualType getValueType(ASTContext&) const { return ElementType; } - + QualType getElementType() const { return ElementType; } - - void print(llvm::raw_ostream& os) const; + + RegionRawOffset getAsRawOffset() const; + + void dumpToStream(llvm::raw_ostream& os) const; void Profile(llvm::FoldingSetNodeID& ID) const; @@ -563,25 +545,13 @@ public: return R->getKind() == ElementRegionKind; } }; - + template<typename RegionTy> const RegionTy* MemRegion::getAs() const { - const MemRegion *R = this; - - do { - if (const RegionTy* RT = dyn_cast<RegionTy>(R)) - return RT; - - if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) { - R = TR->getSuperRegion(); - continue; - } - - break; - } - while (R); - - return 0; + if (const RegionTy* RT = dyn_cast<RegionTy>(this)) + return RT; + + return NULL; } //===----------------------------------------------------------------------===// @@ -592,7 +562,7 @@ class MemRegionManager { ASTContext &C; llvm::BumpPtrAllocator& A; llvm::FoldingSet<MemRegion> Regions; - + MemSpaceRegion *globals; MemSpaceRegion *stack; MemSpaceRegion *stackArguments; @@ -604,11 +574,11 @@ public: MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), unknown(0), code(0) {} - + ~MemRegionManager() {} - + ASTContext &getContext() { return C; } - + /// getStackRegion - Retrieve the memory region associated with the /// current stack frame. MemSpaceRegion *getStackRegion(); @@ -616,11 +586,11 @@ public: /// getStackArgumentsRegion - Retrieve the memory region associated with /// function/method arguments of the current stack frame. MemSpaceRegion *getStackArgumentsRegion(); - + /// getGlobalsRegion - Retrieve the memory region associated with /// all global variables. MemSpaceRegion *getGlobalsRegion(); - + /// getHeapRegion - Retrieve the memory region associated with the /// generic "heap". MemSpaceRegion *getHeapRegion(); @@ -633,69 +603,77 @@ public: /// getAllocaRegion - Retrieve a region associated with a call to alloca(). AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt); - + /// getCompoundLiteralRegion - Retrieve the region associated with a /// given CompoundLiteral. CompoundLiteralRegion* - getCompoundLiteralRegion(const CompoundLiteralExpr* CL); - + getCompoundLiteralRegion(const CompoundLiteralExpr* CL); + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. SymbolicRegion* getSymbolicRegion(SymbolRef sym); StringRegion* getStringRegion(const StringLiteral* Str); /// getVarRegion - Retrieve or create the memory region associated with - /// a specified VarDecl. - VarRegion* getVarRegion(const VarDecl* vd); - + /// a specified VarDecl and LocationContext. + VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. - ElementRegion* getElementRegion(QualType elementType, SVal Idx, - const MemRegion* superRegion,ASTContext &Ctx); + ElementRegion *getElementRegion(QualType elementType, SVal Idx, + const MemRegion *superRegion, + ASTContext &Ctx); + + ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const MemRegion *superRegion) { + return getElementRegion(ER->getElementType(), ER->getIndex(), + superRegion, ER->getContext()); + } /// getFieldRegion - Retrieve or create the memory region associated with /// a specified FieldDecl. 'superRegion' corresponds to the containing /// memory region (which typically represents the memory representing /// a structure or class). - FieldRegion* getFieldRegion(const FieldDecl* fd, + FieldRegion *getFieldRegion(const FieldDecl* fd, const MemRegion* superRegion); - + + FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { + return getFieldRegion(FR->getDecl(), superRegion); + } + /// getObjCObjectRegion - Retrieve or create the memory region associated with /// the instance of a specified Objective-C class. ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID, const MemRegion* superRegion); - + /// getObjCIvarRegion - Retrieve or create the memory region associated with /// a specified Objective-c instance variable. 'superRegion' corresponds /// to the containing region (which typically represents the Objective-C /// object). - ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd, + ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - TypedViewRegion* getTypedViewRegion(QualType LValueType, - const MemRegion* superRegion); + CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD); - CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t); - CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t); - template <typename RegionTy, typename A1> RegionTy* getRegion(const A1 a1); - + template <typename RegionTy, typename A1> - RegionTy* getRegion(const A1 a1, const MemRegion* superRegion); - + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + template <typename RegionTy, typename A1, typename A2> RegionTy* getRegion(const A1 a1, const A2 a2); - bool isGlobalsRegion(const MemRegion* R) { + bool isGlobalsRegion(const MemRegion* R) { assert(R); - return R == globals; + return R == globals; } - + private: MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); }; - + //===----------------------------------------------------------------------===// // Out-of-line member definitions. //===----------------------------------------------------------------------===// @@ -703,69 +681,69 @@ private: inline ASTContext& MemRegion::getContext() const { return getMemRegionManager()->getContext(); } - + template<typename RegionTy> struct MemRegionManagerTrait; - + template <typename RegionTy, typename A1> RegionTy* MemRegionManager::getRegion(const A1 a1) { const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } template <typename RegionTy, typename A1> -RegionTy* MemRegionManager::getRegion(const A1 a1, const MemRegion *superRegion) -{ - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); +RegionTy* MemRegionManager::getSubRegion(const A1 a1, + const MemRegion *superRegion) { + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + template <typename RegionTy, typename A1, typename A2> RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { - + const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, a2, superRegion); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); void* InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); - + if (!R) { R = (RegionTy*) A.Allocate<RegionTy>(); new (R) RegionTy(a1, a2, superRegion); Regions.InsertNode(R, InsertPos); } - + return R; } - + //===----------------------------------------------------------------------===// // Traits for constructing regions. //===----------------------------------------------------------------------===// @@ -776,18 +754,18 @@ template <> struct MemRegionManagerTrait<AllocaRegion> { const Expr *, unsigned) { return MRMgr.getStackRegion(); } -}; - +}; + template <> struct MemRegionManagerTrait<CompoundLiteralRegion> { typedef MemRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, const CompoundLiteralExpr *CL) { - - return CL->isFileScope() ? MRMgr.getGlobalsRegion() + + return CL->isFileScope() ? MRMgr.getGlobalsRegion() : MRMgr.getStackRegion(); } }; - + template <> struct MemRegionManagerTrait<StringRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -795,20 +773,24 @@ template <> struct MemRegionManagerTrait<StringRegion> { return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait<VarRegion> { typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const VarDecl *d) { - if (d->hasLocalStorage()) { - return isa<ParmVarDecl>(d) || isa<ImplicitParamDecl>(d) + static const SuperRegionTy* getSuperRegion(MemRegionManager &MRMgr, + const VarDecl *D, + const LocationContext *LC) { + + // FIXME: Make stack regions have a location context? + + if (D->hasLocalStorage()) { + return isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion(); } - + return MRMgr.getGlobalsRegion(); } }; - + template <> struct MemRegionManagerTrait<SymbolicRegion> { typedef MemRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -820,7 +802,7 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> { template<> struct MemRegionManagerTrait<CodeTextRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const FunctionDecl*, QualType) { + const FunctionDecl*) { return MRMgr.getCodeRegion(); } static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, @@ -828,7 +810,7 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// @@ -836,10 +818,10 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> { //===----------------------------------------------------------------------===// namespace llvm { -static inline raw_ostream& operator<<(raw_ostream& O, - const clang::MemRegion* R) { - R->print(O); - return O; +static inline raw_ostream& operator<<(raw_ostream& os, + const clang::MemRegion* R) { + R->dumpToStream(os); + return os; } } // end llvm namespace diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index 4bc5e27aacf0..4ba3c7396822 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -18,7 +18,11 @@ #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/ImmutableList.h" - + +namespace llvm { + class raw_ostream; +} + //==------------------------------------------------------------------------==// // Base SVal types. //==------------------------------------------------------------------------==// @@ -26,40 +30,43 @@ namespace clang { class CompoundValData; +class LazyCompoundValData; +class GRState; class BasicValueFactory; class MemRegion; +class TypedRegion; class MemRegionManager; class GRStateManager; class ValueManager; - + class SVal { public: enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; enum { BaseBits = 2, BaseMask = 0x3 }; - + protected: void* Data; unsigned Kind; - + protected: SVal(const void* d, bool isLoc, unsigned ValKind) : Data(const_cast<void*>(d)), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} - + explicit SVal(BaseKind k, void* D = NULL) : Data(D), Kind(k) {} - + public: SVal() : Data(0), Kind(0) {} ~SVal() {}; - + /// BufferTy - A temporary buffer to hold a set of SVals. typedef llvm::SmallVector<SVal,5> BufferTy; - + inline unsigned getRawKind() const { return Kind; } inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } - + inline void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) getRawKind()); ID.AddPointer(reinterpret_cast<void*>(Data)); @@ -68,7 +75,7 @@ public: inline bool operator==(const SVal& R) const { return getRawKind() == R.getRawKind() && Data == R.Data; } - + inline bool operator!=(const SVal& R) const { return !(*this == R); } @@ -84,25 +91,25 @@ public: inline bool isUnknownOrUndef() const { return getRawKind() <= UnknownKind; } - + inline bool isValid() const { return getRawKind() > UnknownKind; } - + bool isZeroConstant() const; /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; bool hasConjuredSymbol() const; /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a - /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. /// Otherwise return 0. const FunctionDecl* getAsFunctionDecl() const; - - /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and + + /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* SymbolRef getAsLocSymbol() const; - + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. /// Otherwise return a SymbolRef where 'isValid()' returns false. SymbolRef getAsSymbol() const; @@ -112,9 +119,9 @@ public: const SymExpr *getAsSymbolicExpression() const; const MemRegion *getAsRegion() const; - - void print(llvm::raw_ostream& OS) const; - void printStdErr() const; + + void dumpToStream(llvm::raw_ostream& OS) const; + void dump() const; // Iterators. class symbol_iterator { @@ -123,14 +130,14 @@ public: public: symbol_iterator() {} symbol_iterator(const SymExpr* SE); - + symbol_iterator& operator++(); SymbolRef operator*(); - + bool operator==(const symbol_iterator& X) const; bool operator!=(const symbol_iterator& X) const; }; - + symbol_iterator symbol_begin() const { const SymExpr *SE = getAsSymbolicExpression(); if (SE) @@ -138,97 +145,135 @@ public: else return symbol_iterator(); } - + symbol_iterator symbol_end() const { return symbol_iterator(); } - + // Implement isa<T> support. static inline bool classof(const SVal*) { return true; } }; -class UnknownVal : public SVal { -public: - UnknownVal() : SVal(UnknownKind) {} - - static inline bool classof(const SVal* V) { - return V->getBaseKind() == UnknownKind; - } -}; class UndefinedVal : public SVal { public: UndefinedVal() : SVal(UndefinedKind) {} UndefinedVal(void* D) : SVal(UndefinedKind, D) {} - + static inline bool classof(const SVal* V) { return V->getBaseKind() == UndefinedKind; } - - void* getData() const { return Data; } + + void* getData() const { return Data; } }; -class NonLoc : public SVal { +class DefinedOrUnknownSVal : public SVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically false. + bool isUndef() const; + bool isValid() const; + protected: - NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {} + explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind) + : SVal(d, isLoc, ValKind) {} + + explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) + : SVal(k, D) {} + +public: + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUndef(); + } +}; +class UnknownVal : public DefinedOrUnknownSVal { public: - void print(llvm::raw_ostream& Out) const; + UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + + static inline bool classof(const SVal *V) { + return V->getBaseKind() == UnknownKind; + } +}; +class DefinedSVal : public DefinedOrUnknownSVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically true/false. + bool isUnknown() const; + bool isUnknownOrUndef() const; + bool isValid() const; +protected: + DefinedSVal(const void* d, bool isLoc, unsigned ValKind) + : DefinedOrUnknownSVal(d, isLoc, ValKind) {} +public: + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUnknownOrUndef(); + } +}; + +class NonLoc : public DefinedSVal { +protected: + NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {} + +public: + void dumpToStream(llvm::raw_ostream& Out) const; + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind; } }; -class Loc : public SVal { +class Loc : public DefinedSVal { protected: Loc(unsigned SubKind, const void* D) - : SVal(const_cast<void*>(D), true, SubKind) {} + : DefinedSVal(const_cast<void*>(D), true, SubKind) {} public: - void print(llvm::raw_ostream& Out) const; + void dumpToStream(llvm::raw_ostream& Out) const; - Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {} + Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } - + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == LocKind; } - + static inline bool IsLocType(QualType T) { - return T->isPointerType() || T->isObjCQualifiedIdType() - || T->isBlockPointerType(); + return T->isAnyPointerType() || T->isBlockPointerType(); } }; - + //==------------------------------------------------------------------------==// // Subclasses of NonLoc. //==------------------------------------------------------------------------==// namespace nonloc { - + enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, - LocAsIntegerKind, CompoundValKind }; + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; class SymbolVal : public NonLoc { public: SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} - + SymbolRef getSymbol() const { return (const SymbolData*) Data; } - + static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && + return V->getBaseKind() == NonLocKind && V->getSubKind() == SymbolValKind; } - + static inline bool classof(const NonLoc* V) { return V->getSubKind() == SymbolValKind; } }; -class SymExprVal : public NonLoc { +class SymExprVal : public NonLoc { public: SymExprVal(const SymExpr *SE) : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {} @@ -236,12 +281,12 @@ public: const SymExpr *getSymbolicExpression() const { return reinterpret_cast<SymExpr*>(Data); } - + static inline bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind && V->getSubKind() == SymExprValKind; } - + static inline bool classof(const NonLoc* V) { return V->getSubKind() == SymExprValKind; } @@ -250,30 +295,30 @@ public: class ConcreteInt : public NonLoc { public: ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} - + const llvm::APSInt& getValue() const { return *static_cast<llvm::APSInt*>(Data); } - + // Transfer functions for binary/unary operations on ConcreteInts. SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, const ConcreteInt& R) const; - + ConcreteInt evalComplement(ValueManager &ValMgr) const; - + ConcreteInt evalMinus(ValueManager &ValMgr) const; - + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind && V->getSubKind() == ConcreteIntKind; } - + static inline bool classof(const NonLoc* V) { return V->getSubKind() == ConcreteIntKind; } }; - + class LocAsInteger : public NonLoc { friend class clang::ValueManager; @@ -281,28 +326,28 @@ class LocAsInteger : public NonLoc { NonLoc(LocAsIntegerKind, &data) { assert (isa<Loc>(data.first)); } - + public: - + Loc getLoc() const { return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first); } - + const Loc& getPersistentLoc() const { const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first; return cast<Loc>(V); - } - + } + unsigned getNumBits() const { return ((std::pair<SVal, unsigned>*) Data)->second; } - + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind && V->getSubKind() == LocAsIntegerKind; } - + static inline bool classof(const NonLoc* V) { return V->getSubKind() == LocAsIntegerKind; } @@ -317,10 +362,10 @@ public: const CompoundValData* getValue() const { return static_cast<CompoundValData*>(Data); } - + typedef llvm::ImmutableList<SVal>::iterator iterator; iterator begin() const; - iterator end() const; + iterator end() const; static bool classof(const SVal* V) { return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; @@ -330,7 +375,28 @@ public: return V->getSubKind() == CompoundValKind; } }; - + +class LazyCompoundVal : public NonLoc { + friend class clang::ValueManager; + + LazyCompoundVal(const LazyCompoundValData *D) + : NonLoc(LazyCompoundValKind, D) {} +public: + const LazyCompoundValData *getCVData() const { + return static_cast<const LazyCompoundValData*>(Data); + } + const GRState *getState() const; + const TypedRegion *getRegion() const; + + static bool classof(const SVal *V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LazyCompoundValKind; + } + static bool classof(const NonLoc *V) { + return V->getSubKind() == LazyCompoundValKind; + } +}; + } // end namespace clang::nonloc //==------------------------------------------------------------------------==// @@ -338,27 +404,27 @@ public: //==------------------------------------------------------------------------==// namespace loc { - + enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; class GotoLabel : public Loc { public: GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} - + LabelStmt* getLabel() const { return static_cast<LabelStmt*>(Data); } - + static inline bool classof(const SVal* V) { return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind; } - + static inline bool classof(const Loc* V) { return V->getSubKind() == GotoLabelKind; - } + } }; - + class MemRegionVal : public Loc { public: @@ -367,35 +433,37 @@ public: const MemRegion* getRegion() const { return static_cast<MemRegion*>(Data); } - + + const MemRegion* getBaseRegion() const; + template <typename REGION> const REGION* getRegionAs() const { return llvm::dyn_cast<REGION>(getRegion()); - } - + } + inline bool operator==(const MemRegionVal& R) const { return getRegion() == R.getRegion(); } - + inline bool operator!=(const MemRegionVal& R) const { return getRegion() != R.getRegion(); } - + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == LocKind && V->getSubKind() == MemRegionKind; } - + static inline bool classof(const Loc* V) { return V->getSubKind() == MemRegionKind; - } + } }; class ConcreteInt : public Loc { public: ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} - + const llvm::APSInt& getValue() const { return *static_cast<llvm::APSInt*>(Data); } @@ -403,19 +471,26 @@ public: // Transfer functions for binary/unary operations on ConcreteInts. SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const ConcreteInt& R) const; - + // Implement isa<T> support. static inline bool classof(const SVal* V) { return V->getBaseKind() == LocKind && V->getSubKind() == ConcreteIntKind; } - + static inline bool classof(const Loc* V) { return V->getSubKind() == ConcreteIntKind; } }; - -} // end clang::loc namespace -} // end clang namespace +} // end clang::loc namespace +} // end clang namespace + +namespace llvm { +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + clang::SVal V) { + V.dumpToStream(os); + return os; +} +} // end llvm namespace #endif diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Analysis/PathSensitive/SValuator.h index 490c04e5978e..e63eb12cf8ea 100644 --- a/include/clang/Analysis/PathSensitive/SValuator.h +++ b/include/clang/Analysis/PathSensitive/SValuator.h @@ -9,7 +9,7 @@ // // 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 @@ -24,32 +24,66 @@ class GRState; class ValueManager; class SValuator { + friend class ValueManager; protected: ValueManager &ValMgr; - + + virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0; + + virtual SVal EvalCastL(Loc val, QualType castTy) = 0; + public: SValuator(ValueManager &valMgr) : ValMgr(valMgr) {} virtual ~SValuator() {} + + template <typename T> + class GenericCastResult : public std::pair<const GRState *, T> { + public: + const GRState *getState() const { return this->first; } + T getSVal() const { return this->second; } + GenericCastResult(const GRState *s, T v) + : std::pair<const GRState*,T>(s, v) {} + }; - virtual SVal EvalCast(NonLoc val, QualType castTy) = 0; + class CastResult : public GenericCastResult<SVal> { + public: + CastResult(const GRState *s, SVal v) : GenericCastResult<SVal>(s, v) {} + }; + + class DefinedOrUnknownCastResult : + public GenericCastResult<DefinedOrUnknownSVal> { + public: + DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v) + : GenericCastResult<DefinedOrUnknownSVal>(s, v) {} + }; - virtual SVal EvalCast(Loc val, QualType castTy) = 0; + CastResult EvalCast(SVal V, const GRState *ST, + QualType castTy, QualType originalType); + DefinedOrUnknownCastResult EvalCast(DefinedOrUnknownSVal V, const GRState *ST, + QualType castTy, QualType originalType); + 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 EvalBinOpNN(const GRState *state, 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; -}; + Loc lhs, NonLoc rhs, QualType resultTy) = 0; -SValuator* CreateSimpleSValuator(ValueManager &valMgr); + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal L, SVal R, QualType T); + DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R); +}; + +SValuator* CreateSimpleSValuator(ValueManager &valMgr); + } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 5aa53507fd14..3ff253d0abf3 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -23,16 +23,17 @@ #include "llvm/ADT/SmallVector.h" namespace clang { - + typedef const void* Store; -class GRState; +class GRState; class GRStateManager; class Stmt; class Expr; class ObjCIvarDecl; class SubRegionMap; - +class StackFrameContext; + class StoreManager { protected: ValueManager &ValMgr; @@ -43,37 +44,30 @@ protected: StoreManager(GRStateManager &stateMgr); -protected: - virtual const GRState *AddRegionView(const GRState *state, - const MemRegion *view, - const MemRegion *base) { - return state; - } - -public: +public: virtual ~StoreManager() {} - + /// Return the value bound to specified location in a given state. /// \param[in] state The analysis state. /// \param[in] loc The symbolic memory location. - /// \param[in] T An optional type that provides a hint indicating the + /// \param[in] T An optional type that provides a hint indicating the /// expected type of the returned value. This is used if the value is /// lazily computed. /// \return The value bound to the location \c loc. - virtual SVal Retrieve(const GRState *state, Loc loc, - QualType T = QualType()) = 0; + virtual SValuator::CastResult Retrieve(const GRState *state, Loc loc, + QualType T = QualType()) = 0; /// Return a state with the specified value bound to the given location. /// \param[in] state The analysis state. /// \param[in] loc The symbolic memory location. /// \param[in] val The value to bind to location \c loc. - /// \return A pointer to a GRState object that contains the same bindings as + /// \return A pointer to a GRState object that contains the same bindings as /// \c state with the addition of having the value specified by \c val bound /// to the location given for \c loc. virtual const GRState *Bind(const GRState *state, Loc loc, SVal val) = 0; virtual Store Remove(Store St, Loc L) = 0; - + /// BindCompoundLiteral - Return the store that has the bindings currently /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region /// for the compound literal and 'BegInit' and 'EndInit' represent an @@ -81,36 +75,31 @@ public: virtual const GRState *BindCompoundLiteral(const GRState *state, const CompoundLiteralExpr* cl, SVal v) = 0; - + /// getInitialStore - Returns the initial "empty" store representing the /// value bindings upon entry to an analyzed function. - virtual Store getInitialStore() = 0; - + virtual Store getInitialStore(const LocationContext *InitLoc) = 0; + /// getRegionManager - Returns the internal RegionManager object that is /// used to query and manipulate MemRegion objects. MemRegionManager& getRegionManager() { return MRMgr; } - + /// getSubRegionMap - Returns an opaque map object that clients can query /// to get the subregions of a given MemRegion object. It is the // caller's responsibility to 'delete' the returned map. virtual SubRegionMap *getSubRegionMap(const GRState *state) = 0; - virtual SVal getLValueVar(const GRState *state, const VarDecl *vd) = 0; + virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0; + + virtual SVal getLValueString(const StringLiteral* sl) = 0; + + virtual SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl) = 0; - virtual SVal getLValueString(const GRState *state, - const StringLiteral* sl) = 0; + virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0; - virtual SVal getLValueCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl) = 0; - - virtual SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* decl, - SVal base) = 0; - - virtual SVal getLValueField(const GRState *state, SVal base, - const FieldDecl* D) = 0; - - virtual SVal getLValueElement(const GRState *state, QualType elementType, - SVal base, SVal offset) = 0; + virtual SVal getLValueField(const FieldDecl* D, SVal Base) = 0; + + virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0; // FIXME: Make out-of-line. virtual SVal getSizeInElements(const GRState *state, const MemRegion *region){ @@ -120,7 +109,7 @@ public: /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. virtual SVal ArrayToPointer(Loc Array) = 0; - + class CastResult { const GRState *state; const MemRegion *region; @@ -129,33 +118,32 @@ public: const MemRegion* getRegion() const { return region; } CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){} }; - + /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from /// a MemRegion* to a specific location type. 'R' is the region being /// casted and 'CastToTy' the result type of the cast. - virtual CastResult CastRegion(const GRState *state, const MemRegion *region, - QualType CastToTy); + const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); /// EvalBinOp - Perform pointer arithmetic. virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, Loc lhs, NonLoc rhs, QualType resultTy) { return UnknownVal(); } - - /// getSelfRegion - Returns the region for the 'self' (Objective-C) or - /// 'this' object (C++). When used when analyzing a normal function this - /// method returns NULL. - virtual const MemRegion* getSelfRegion(Store store) = 0; - - virtual Store RemoveDeadBindings(const GRState *state, - Stmt* Loc, SymbolReaper& SymReaper, + + virtual void RemoveDeadBindings(GRState &state, Stmt* Loc, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; - virtual const GRState *BindDecl(const GRState *state, const VarDecl *vd, - SVal initVal) = 0; + virtual const GRState *BindDecl(const GRState *ST, const VarDecl *VD, + const LocationContext *LC, SVal initVal) = 0; - virtual const GRState *BindDeclWithNoInit(const GRState *state, - const VarDecl *vd) = 0; + virtual const GRState *BindDeclWithNoInit(const GRState *ST, + const VarDecl *VD, + const LocationContext *LC) = 0; + + virtual const GRState *InvalidateRegion(const GRState *state, + const MemRegion *R, + const Expr *E, unsigned Count) = 0; // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, @@ -163,25 +151,35 @@ public: return state; } - // FIXME: Make out-of-line. - virtual const GRState *setDefaultValue(const GRState *state, - const MemRegion *region, - SVal val) { + /// EnterStackFrame - Let the StoreManager to do something when execution + /// engine is about to execute into a callee. + virtual const GRState *EnterStackFrame(const GRState *state, + const StackFrameContext *frame) { return state; } virtual void print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) = 0; - + class BindingsHandler { - public: + public: virtual ~BindingsHandler(); virtual bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion *region, SVal val) = 0; }; - + /// iterBindings - Iterate over the bindings in the Store. - virtual void iterBindings(Store store, BindingsHandler& f) = 0; + virtual void iterBindings(Store store, BindingsHandler& f) = 0; + +protected: + const MemRegion *MakeElementRegion(const MemRegion *Base, + QualType pointeeTy, uint64_t index = 0); + + /// CastRetrievedVal - Used by subclasses of StoreManager to implement + /// implicit casts that arise from loads from regions that are reinterpreted + /// as another region. + SValuator::CastResult CastRetrievedVal(SVal val, const GRState *state, + const TypedRegion *R, QualType castTy); }; // FIXME: Do we still need this? @@ -190,14 +188,14 @@ public: class SubRegionMap { public: virtual ~SubRegionMap() {} - + class Visitor { public: virtual ~Visitor() {}; virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; }; - - virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; + + virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; }; // FIXME: Do we need to pass GRStateManager anymore? diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h index f32a7e3481dd..d3996c6330a2 100644 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -21,66 +21,72 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/Allocator.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/ImmutableSet.h" +#include "llvm/ADT/DenseSet.h" namespace llvm { class raw_ostream; } -namespace clang { +namespace clang { class MemRegion; + class TypedRegion; class ASTContext; class BasicValueFactory; } namespace clang { - + class SymExpr : public llvm::FoldingSetNode { public: - enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS, + enum Kind { BEGIN_SYMBOLS, + RegionValueKind, ConjuredKind, DerivedKind, + END_SYMBOLS, SymIntKind, SymSymKind }; private: Kind K; protected: - SymExpr(Kind k) : K(k) {} - + SymExpr(Kind k) : K(k) {} + public: virtual ~SymExpr() {} - - Kind getKind() const { return K; } - - virtual QualType getType(ASTContext&) const = 0; + + Kind getKind() const { return K; } + + void dump() const; + + virtual void dumpToStream(llvm::raw_ostream &os) const = 0; + + virtual QualType getType(ASTContext&) const = 0; virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; - + // Implement isa<T> support. static inline bool classof(const SymExpr*) { return true; } }; - + typedef unsigned SymbolID; - + class SymbolData : public SymExpr { private: const SymbolID Sym; - + protected: - SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} public: virtual ~SymbolData() {} - + SymbolID getSymbolID() const { return Sym; } - + // Implement isa<T> support. - static inline bool classof(const SymExpr* SE) { + static inline bool classof(const SymExpr* SE) { Kind k = SE->getKind(); return k > BEGIN_SYMBOLS && k < END_SYMBOLS; } }; typedef const SymbolData* SymbolRef; - + class SymbolRegionValue : public SymbolData { const MemRegion *R; // We may cast the region to another type, so the expected type of the symbol @@ -90,7 +96,7 @@ class SymbolRegionValue : public SymbolData { public: SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType()) : SymbolData(RegionValueKind, sym), R(r), T(t) {} - + const MemRegion* getRegion() const { return R; } static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R, @@ -99,11 +105,13 @@ public: profile.AddPointer(R); T.Profile(profile); } - + virtual void Profile(llvm::FoldingSetNodeID& profile) { Profile(profile, R, T); } - + + void dumpToStream(llvm::raw_ostream &os) const; + QualType getType(ASTContext&) const; // Implement isa<T> support. @@ -123,15 +131,17 @@ public: const void* symbolTag) : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), SymbolTag(symbolTag) {} - + const Stmt* getStmt() const { return S; } unsigned getCount() const { return Count; } const void* getTag() const { return SymbolTag; } - + QualType getType(ASTContext&) const; - + + void dumpToStream(llvm::raw_ostream &os) const; + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, - QualType T, unsigned Count, const void* SymbolTag) { + QualType T, unsigned Count, const void* SymbolTag) { profile.AddInteger((unsigned) ConjuredKind); profile.AddPointer(S); profile.Add(T); @@ -146,7 +156,39 @@ public: // Implement isa<T> support. static inline bool classof(const SymExpr* SE) { return SE->getKind() == ConjuredKind; - } + } +}; + +class SymbolDerived : public SymbolData { + SymbolRef parentSymbol; + const TypedRegion *R; + +public: + SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r) + : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} + + SymbolRef getParentSymbol() const { return parentSymbol; } + const TypedRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, + const TypedRegion *r) { + profile.AddInteger((unsigned) DerivedKind); + profile.AddPointer(r); + profile.AddPointer(parent); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, parentSymbol, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == DerivedKind; + } }; // SymIntExpr - Represents symbolic expression like 'x' + 3. @@ -163,14 +205,16 @@ public: // FIXME: We probably need to make this out-of-line to avoid redundant // generation of virtual functions. - QualType getType(ASTContext& C) const { return T; } - + QualType getType(ASTContext& C) const { return T; } + BinaryOperator::Opcode getOpcode() const { return Op; } - + + void dumpToStream(llvm::raw_ostream &os) const; + const SymExpr *getLHS() const { return LHS; } const llvm::APSInt &getRHS() const { return RHS; } - static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType t) { ID.AddInteger((unsigned) SymIntKind); @@ -183,11 +227,11 @@ public: void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, LHS, Op, RHS, T); } - + // Implement isa<T> support. static inline bool classof(const SymExpr* SE) { return SE->getKind() == SymIntKind; - } + } }; // SymSymExpr - Represents symbolic expression like 'x' + 'y'. @@ -204,11 +248,13 @@ public: const SymExpr *getLHS() const { return LHS; } const SymExpr *getRHS() const { return RHS; } - + // FIXME: We probably need to make this out-of-line to avoid redundant // generation of virtual functions. QualType getType(ASTContext& C) const { return T; } + void dumpToStream(llvm::raw_ostream &os) const; + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { ID.AddInteger((unsigned) SymSymKind); @@ -221,45 +267,48 @@ public: void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, LHS, Op, RHS, T); } - + // Implement isa<T> support. static inline bool classof(const SymExpr* SE) { return SE->getKind() == SymSymKind; - } + } }; class SymbolManager { typedef llvm::FoldingSet<SymExpr> DataSetTy; - DataSetTy DataSet; + DataSetTy DataSet; unsigned SymbolCounter; llvm::BumpPtrAllocator& BPAlloc; BasicValueFactory &BV; ASTContext& Ctx; - + public: - SymbolManager(ASTContext& ctx, BasicValueFactory &bv, + SymbolManager(ASTContext& ctx, BasicValueFactory &bv, llvm::BumpPtrAllocator& bpalloc) : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} - + ~SymbolManager(); - + static bool canSymbolicate(QualType T); /// Make a unique symbol for MemRegion R according to its kind. - const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R, + const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R, QualType T = QualType()); const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, unsigned VisitCount, const void* SymbolTag = 0); const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, - const void* SymbolTag = 0) { + const void* SymbolTag = 0) { return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); } + const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, + const TypedRegion *R); + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType t); - + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType t) { return getSymIntExpr(&lhs, op, rhs, t); @@ -267,29 +316,28 @@ public: const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t); - + QualType getType(const SymExpr *SE) const { return SE->getType(Ctx); } - + ASTContext &getContext() { return Ctx; } BasicValueFactory &getBasicVals() { return BV; } }; - + class SymbolReaper { - typedef llvm::ImmutableSet<SymbolRef> SetTy; - typedef SetTy::Factory FactoryTy; - - FactoryTy F; + typedef llvm::DenseSet<SymbolRef> SetTy; + SetTy TheLiving; SetTy TheDead; LiveVariables& Liveness; SymbolManager& SymMgr; - + public: SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr) - : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()), - Liveness(liveness), SymMgr(symmgr) {} + : Liveness(liveness), SymMgr(symmgr) {} + + ~SymbolReaper() {} bool isLive(SymbolRef sym); @@ -300,19 +348,19 @@ public: bool isLive(const Stmt* Loc, const VarDecl* VD) const { return Liveness.isLive(Loc, VD); } - + void markLive(SymbolRef sym); bool maybeDead(SymbolRef sym); - - typedef SetTy::iterator dead_iterator; + + typedef SetTy::const_iterator dead_iterator; dead_iterator dead_begin() const { return TheDead.begin(); } dead_iterator dead_end() const { return TheDead.end(); } - + bool hasDeadSymbols() const { - return !TheDead.isEmpty(); + return !TheDead.empty(); } }; - + class SymbolVisitor { public: // VisitSymbol - A visitor method invoked by @@ -321,11 +369,14 @@ public: virtual bool VisitSymbol(SymbolRef sym) = 0; virtual ~SymbolVisitor(); }; - + } // end clang namespace namespace llvm { - llvm::raw_ostream& operator<<(llvm::raw_ostream& Out, - const clang::SymExpr *SE); +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + const clang::SymExpr *SE) { + SE->dumpToStream(os); + return os; } +} // end llvm namespace #endif diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index 36d1df2150df..8d162a681c44 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -16,82 +16,123 @@ #ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H #define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#include "llvm/ADT/OwningPtr.h" #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/SVals.h" #include "clang/Analysis/PathSensitive/BasicValueFactory.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/SValuator.h" namespace llvm { class BumpPtrAllocator; } -namespace clang { +namespace clang { + +class GRStateManager; + class ValueManager { - ASTContext &Context; + ASTContext &Context; BasicValueFactory BasicVals; - + /// SymMgr - Object that manages the symbol information. SymbolManager SymMgr; + /// SVator - SValuator object that creates SVals from expressions. + llvm::OwningPtr<SValuator> SVator; MemRegionManager MemMgr; - + + GRStateManager &StateMgr; + + const QualType ArrayIndexTy; + const unsigned ArrayIndexWidth; + public: - ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context) - : Context(context), BasicVals(Context, alloc), - SymMgr(Context, BasicVals, alloc), - MemMgr(Context, alloc) {} + ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context, + GRStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc), StateMgr(stateMgr), + ArrayIndexTy(context.IntTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) { + // FIXME: Generalize later. + SVator.reset(clang::CreateSimpleSValuator(*this)); + } // Accessors to submanagers. - + ASTContext &getContext() { return Context; } const ASTContext &getContext() const { return Context; } - + + GRStateManager &getStateManager() { return StateMgr; } + BasicValueFactory &getBasicValueFactory() { return BasicVals; } const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } - + SymbolManager &getSymbolManager() { return SymMgr; } const SymbolManager &getSymbolManager() const { return SymMgr; } + SValuator &getSValuator() { return *SVator.get(); } + MemRegionManager &getRegionManager() { return MemMgr; } const MemRegionManager &getRegionManager() const { return MemMgr; } - + // Forwarding methods to SymbolManager. - + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, unsigned VisitCount, const void* SymbolTag = 0) { return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); } - + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, - const void* SymbolTag = 0) { + const void* SymbolTag = 0) { return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); } /// makeZeroVal - Construct an SVal representing '0' for the specified type. - SVal makeZeroVal(QualType T); + DefinedOrUnknownSVal makeZeroVal(QualType T); /// getRegionValueSymbolVal - make a unique symbol for value of R. - SVal getRegionValueSymbolVal(const MemRegion *R, QualType T = QualType()); - - SVal getRegionValueSymbolValOrUnknown(const MemRegion *R, QualType T) { - return SymMgr.canSymbolicate(T) ? getRegionValueSymbolVal(R, T) - : UnknownVal(); + DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R, + QualType T = QualType()); + + DefinedOrUnknownSVal getRegionValueSymbolValOrUnknown(const MemRegion *R, + QualType T) { + if (SymMgr.canSymbolicate(T)) + return getRegionValueSymbolVal(R, T); + return UnknownVal(); } - - SVal getConjuredSymbolVal(const Expr *E, unsigned Count); - SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count); - SVal getFunctionPointer(const FunctionDecl* FD); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, unsigned Count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, QualType T, + unsigned Count); + + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, + const TypedRegion *R); + + DefinedSVal getFunctionPointer(const FunctionDecl *FD); NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); } + NonLoc makeLazyCompoundVal(const GRState *state, const TypedRegion *R) { + return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(state, R)); + } + NonLoc makeZeroArrayIndex() { - return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false)); + return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); + } + + NonLoc makeArrayIndex(uint64_t idx) { + return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); } + SVal convertToArrayIndex(SVal V); + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), I->getType()->isUnsignedIntegerType())); @@ -100,7 +141,7 @@ public: 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)); } @@ -109,7 +150,10 @@ public: return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); } - NonLoc makeIntVal(uint64_t X, QualType T) { + DefinedSVal makeIntVal(uint64_t X, QualType T) { + if (Loc::IsLocType(T)) + return loc::ConcreteInt(BasicVals.getValue(X, T)); + return nonloc::ConcreteInt(BasicVals.getValue(X, T)); } @@ -117,6 +161,10 @@ public: return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); } + NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned)); + } + NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) { return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned)); } @@ -127,10 +175,10 @@ public: NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& rhs, QualType T); - + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType T); - + NonLoc makeTruthVal(bool b, QualType T) { return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); } diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index d2b536ca1cb2..666e45b847cf 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -24,123 +24,95 @@ #include <utility> namespace clang { - + +class LocationContext; + class ProgramPoint { public: - enum Kind { BlockEdgeKind = 0x0, - BlockEntranceKind = 0x1, - BlockExitKind = 0x2, - // Keep the following four together and in this order. - PostStmtKind = 0x3, - PostLocationChecksSucceedKind = 0x4, - PostOutOfBoundsCheckFailedKind = 0x5, - PostNullCheckFailedKind = 0x6, - PostUndefLocationCheckFailedKind = 0x7, - PostLoadKind = 0x8, - PostStoreKind = 0x9, - PostPurgeDeadSymbolsKind = 0x10, - PostStmtCustomKind = 0x11, - PostLValueKind = 0x12, + enum Kind { BlockEdgeKind, + BlockEntranceKind, + BlockExitKind, + PreStmtKind, + // Keep the following together and in this order. + PostStmtKind, + PostLocationChecksSucceedKind, + PostOutOfBoundsCheckFailedKind, + PostNullCheckFailedKind, + PostUndefLocationCheckFailedKind, + PostLoadKind, + PostStoreKind, + PostPurgeDeadSymbolsKind, + PostStmtCustomKind, + PostLValueKind, MinPostStmtKind = PostStmtKind, MaxPostStmtKind = PostLValueKind }; private: - enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 }; - - std::pair<uintptr_t,uintptr_t> Data; + std::pair<const void *, const void *> Data; + Kind K; + + // The LocationContext could be NULL to allow ProgramPoint to be used in + // context insensitive analysis. + const LocationContext *L; const void *Tag; - -protected: - ProgramPoint(const void* P, Kind k, const void *tag = 0) - : Data(reinterpret_cast<uintptr_t>(P), - (uintptr_t) k), Tag(tag) {} - - ProgramPoint(const void* P1, const void* P2, const void *tag = 0) - : Data(reinterpret_cast<uintptr_t>(P1) | TwoPointers, - reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} - - ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0) - : Data(reinterpret_cast<uintptr_t>(P1) | Custom, - reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} protected: - void* getData1NoMask() const { - Kind k = getKind(); k = k; - assert(k == BlockEntranceKind || k == BlockExitKind); - return reinterpret_cast<void*>(Data.first); - } - - void* getData1() const { - Kind k = getKind(); k = k; - assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind)); - return reinterpret_cast<void*>(Data.first & ~Mask); - } + ProgramPoint(const void* P, Kind k, const LocationContext *l, + const void *tag = 0) + : Data(P, NULL), K(k), L(l), Tag(tag) {} - void* getData2() const { - Kind k = getKind(); k = k; - assert(k == BlockEdgeKind || k == PostStmtCustomKind); - return reinterpret_cast<void*>(Data.second); - } - + ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, + const void *tag = 0) + : Data(P1, P2), K(k), L(l), Tag(tag) {} + +protected: + const void* getData1() const { return Data.first; } + const void* getData2() const { return Data.second; } const void *getTag() const { return Tag; } - -public: - Kind getKind() const { - switch (Data.first & Mask) { - case TwoPointers: return BlockEdgeKind; - case Custom: return PostStmtCustomKind; - default: return (Kind) Data.second; - } - } + +public: + Kind getKind() const { return K; } + + const LocationContext *getLocationContext() const { return L; } // For use with DenseMap. This hash is probably slow. unsigned getHashValue() const { llvm::FoldingSetNodeID ID; - ID.AddPointer(reinterpret_cast<void*>(Data.first)); - ID.AddPointer(reinterpret_cast<void*>(Data.second)); - ID.AddPointer(Tag); + Profile(ID); return ID.ComputeHash(); } - + static bool classof(const ProgramPoint*) { return true; } bool operator==(const ProgramPoint & RHS) const { - return Data == RHS.Data && Tag == RHS.Tag; + return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag; } bool operator!=(const ProgramPoint& RHS) const { - return Data != RHS.Data || Tag != RHS.Tag; + return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag; } - - bool operator<(const ProgramPoint& RHS) const { - return Data < RHS.Data && Tag < RHS.Tag; - } - + void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddPointer(reinterpret_cast<void*>(Data.first)); - if (getKind() != PostStmtCustomKind) - ID.AddPointer(reinterpret_cast<void*>(Data.second)); - else { - const std::pair<const void*, const void*> *P = - reinterpret_cast<std::pair<const void*, const void*>*>(Data.second); - ID.AddPointer(P->first); - ID.AddPointer(P->second); - } + ID.AddInteger((unsigned) K); + ID.AddPointer(Data.first); + ID.AddPointer(Data.second); + ID.AddPointer(L); ID.AddPointer(Tag); } }; - + class BlockEntrance : public ProgramPoint { public: - BlockEntrance(const CFGBlock* B, const void *tag = 0) - : ProgramPoint(B, BlockEntranceKind, tag) {} - + BlockEntrance(const CFGBlock* B, const LocationContext *L, + const void *tag = 0) + : ProgramPoint(B, BlockEntranceKind, L, tag) {} + CFGBlock* getBlock() const { - return reinterpret_cast<CFGBlock*>(getData1NoMask()); + return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1())); } - + Stmt* getFirstStmt() const { - CFGBlock* B = getBlock(); + const CFGBlock* B = getBlock(); return B->empty() ? NULL : B->front(); } @@ -151,42 +123,70 @@ public: class BlockExit : public ProgramPoint { public: - BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {} - + BlockExit(const CFGBlock* B, const LocationContext *L) + : ProgramPoint(B, BlockExitKind, L) {} + CFGBlock* getBlock() const { - return reinterpret_cast<CFGBlock*>(getData1NoMask()); + return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1())); } Stmt* getLastStmt() const { - CFGBlock* B = getBlock(); + const CFGBlock* B = getBlock(); return B->empty() ? NULL : B->back(); } - + Stmt* getTerminator() const { return getBlock()->getTerminator(); } - + static bool classof(const ProgramPoint* Location) { return Location->getKind() == BlockExitKind; } }; -class PostStmt : public ProgramPoint { -protected: - PostStmt(const Stmt* S, Kind k,const void *tag = 0) - : ProgramPoint(S, k, tag) {} +class StmtPoint : public ProgramPoint { +public: + StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, + const void *tag) + : ProgramPoint(S, p2, k, L, tag) {} + + const Stmt *getStmt() const { return (const Stmt*) getData1(); } - PostStmt(const Stmt* S, const void* data, bool, const void *tag =0) - : ProgramPoint(S, data, true, tag) {} - + template <typename T> + const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= PreStmtKind && k <= MaxPostStmtKind; + } +}; + + +class PreStmt : public StmtPoint { public: - PostStmt(const Stmt* S, const void *tag = 0) - : ProgramPoint(S, PostStmtKind, tag) {} + PreStmt(const Stmt *S, const LocationContext *L, const void *tag, + const Stmt *SubStmt = 0) + : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} - Stmt* getStmt() const { return (Stmt*) getData1(); } - - template<typename T> - T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PreStmtKind; + } +}; + +class PostStmt : public StmtPoint { +protected: + PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0) + : StmtPoint(S, NULL, k, L, tag) {} + + PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, + const void *tag =0) + : StmtPoint(S, data, k, L, tag) {} + +public: + explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) + : StmtPoint(S, NULL, PostStmtKind, L, tag) {} static bool classof(const ProgramPoint* Location) { unsigned k = Location->getKind(); @@ -196,40 +196,42 @@ public: class PostLocationChecksSucceed : public PostStmt { public: - PostLocationChecksSucceed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostLocationChecksSucceedKind, tag) {} - + PostLocationChecksSucceed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostLocationChecksSucceedKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostLocationChecksSucceedKind; } }; - + class PostStmtCustom : public PostStmt { public: PostStmtCustom(const Stmt* S, - const std::pair<const void*, const void*>* TaggedData) - : PostStmt(S, TaggedData, true) { - assert(getKind() == PostStmtCustomKind); - } + const std::pair<const void*, const void*>* TaggedData,\ + const LocationContext *L) + : PostStmt(S, TaggedData, PostStmtCustomKind, L) {} const std::pair<const void*, const void*>& getTaggedPair() const { - return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2()); + return + *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2()); } - + const void* getTag() const { return getTaggedPair().first; } - + const void* getTaggedData() const { return getTaggedPair().second; } - + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostStmtCustomKind; } }; - + class PostOutOfBoundsCheckFailed : public PostStmt { public: - PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {} - + PostOutOfBoundsCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostOutOfBoundsCheckFailedKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostOutOfBoundsCheckFailedKind; } @@ -237,39 +239,41 @@ public: class PostUndefLocationCheckFailed : public PostStmt { public: - PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {} - + PostUndefLocationCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostUndefLocationCheckFailedKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostUndefLocationCheckFailedKind; } }; - + class PostNullCheckFailed : public PostStmt { public: - PostNullCheckFailed(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostNullCheckFailedKind, tag) {} - + PostNullCheckFailed(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostNullCheckFailedKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostNullCheckFailedKind; } }; - + class PostLoad : public PostStmt { public: - PostLoad(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostLoadKind, tag) {} - + PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostLoadKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostLoadKind; } }; - + class PostStore : public PostStmt { public: - PostStore(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostStoreKind, tag) {} - + PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostStoreKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostStoreKind; } @@ -277,60 +281,61 @@ public: class PostLValue : public PostStmt { public: - PostLValue(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostLValueKind, tag) {} - + PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0) + : PostStmt(S, PostLValueKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostLValueKind; } -}; - +}; + class PostPurgeDeadSymbols : public PostStmt { public: - PostPurgeDeadSymbols(const Stmt* S, const void *tag = 0) - : PostStmt(S, PostPurgeDeadSymbolsKind, tag) {} - + PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L, + const void *tag = 0) + : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} + static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostPurgeDeadSymbolsKind; } }; - + class BlockEdge : public ProgramPoint { public: - BlockEdge(const CFGBlock* B1, const CFGBlock* B2) - : ProgramPoint(B1, B2) {} - + BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L) + : ProgramPoint(B1, B2, BlockEdgeKind, L) {} + CFGBlock* getSrc() const { - return static_cast<CFGBlock*>(getData1()); + return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData1())); } - + CFGBlock* getDst() const { - return static_cast<CFGBlock*>(getData2()); + return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData2())); } - + static bool classof(const ProgramPoint* Location) { return Location->getKind() == BlockEdgeKind; } }; - + } // end namespace clang -namespace llvm { // Traits specialization for DenseMap - +namespace llvm { // Traits specialization for DenseMap + template <> struct DenseMapInfo<clang::ProgramPoint> { static inline clang::ProgramPoint getEmptyKey() { uintptr_t x = - reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; - return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); } static inline clang::ProgramPoint getTombstoneKey() { uintptr_t x = - reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; - return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); } static unsigned getHashValue(const clang::ProgramPoint& Loc) { diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h index a592be815419..27ecc66e66e3 100644 --- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h +++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -17,24 +17,24 @@ #ifndef LLVM_CLANG_STMTDECLBVDVAL_H #define LLVM_CLANG_STMTDECLBVDVAL_H -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" namespace clang { - + class Stmt; class ASTContext; struct DeclBitVector_Types { - + class Idx { unsigned I; public: explicit Idx(unsigned i) : I(i) {} Idx() : I(~0U) {} - + bool isValid() const { return I != ~0U; } @@ -42,35 +42,35 @@ struct DeclBitVector_Types { assert (isValid()); return I; } - }; - + }; + //===--------------------------------------------------------------------===// // AnalysisDataTy - Whole-function meta data. //===--------------------------------------------------------------------===// - + class AnalysisDataTy { public: typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy; typedef DMapTy::const_iterator decl_iterator; - + protected: - DMapTy DMap; + DMapTy DMap; unsigned NDecls; - + public: - + AnalysisDataTy() : NDecls(0) {} virtual ~AnalysisDataTy() {} - + bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); } - + Idx getIdx(const NamedDecl* SD) const { DMapTy::const_iterator I = DMap.find(SD); return I == DMap.end() ? Idx() : Idx(I->second); } unsigned getNumDecls() const { return NDecls; } - + void Register(const NamedDecl* SD) { if (!isTracked(SD)) DMap[SD] = NDecls++; } @@ -78,44 +78,44 @@ struct DeclBitVector_Types { decl_iterator begin_decl() const { return DMap.begin(); } decl_iterator end_decl() const { return DMap.end(); } }; - + //===--------------------------------------------------------------------===// // ValTy - Dataflow value. //===--------------------------------------------------------------------===// - + class ValTy { llvm::BitVector DeclBV; public: - + void resetDeclValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.getNumDecls()); + DeclBV.resize(AD.getNumDecls()); DeclBV.reset(); } void setDeclValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.getNumDecls()); + DeclBV.resize(AD.getNumDecls()); DeclBV.set(); } - + void resetValues(AnalysisDataTy& AD) { resetDeclValues(AD); - } - - bool operator==(const ValTy& RHS) const { + } + + bool operator==(const ValTy& RHS) const { assert (sizesEqual(RHS)); return DeclBV == RHS.DeclBV; } - + void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; } - + llvm::BitVector::reference getBit(unsigned i) { return DeclBV[i]; } - + bool getBit(unsigned i) const { return DeclBV[i]; } - + llvm::BitVector::reference operator()(const NamedDecl* ND, const AnalysisDataTy& AD) { return getBit(AD.getIdx(ND)); @@ -124,48 +124,48 @@ struct DeclBitVector_Types { bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const { return getBit(AD.getIdx(ND)); } - - llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } + + llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } const llvm::BitVector::reference getDeclBit(unsigned i) const { return const_cast<llvm::BitVector&>(DeclBV)[i]; } - + ValTy& operator|=(const ValTy& RHS) { assert (sizesEqual(RHS)); DeclBV |= RHS.DeclBV; return *this; } - + ValTy& operator&=(const ValTy& RHS) { assert (sizesEqual(RHS)); DeclBV &= RHS.DeclBV; return *this; } - + ValTy& OrDeclBits(const ValTy& RHS) { return operator|=(RHS); } - + ValTy& AndDeclBits(const ValTy& RHS) { return operator&=(RHS); } - + bool sizesEqual(const ValTy& RHS) const { return DeclBV.size() == RHS.DeclBV.size(); } }; - + //===--------------------------------------------------------------------===// // Some useful merge operations. //===--------------------------------------------------------------------===// - + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; }; struct StmtDeclBitVector_Types { - + //===--------------------------------------------------------------------===// // AnalysisDataTy - Whole-function meta data. //===--------------------------------------------------------------------===// @@ -179,13 +179,13 @@ struct StmtDeclBitVector_Types { void setContext(ASTContext& c) { ctx = &c; } ASTContext& getContext() { - assert(ctx && "ASTContext should not be NULL."); + assert(ctx && "ASTContext should not be NULL."); return *ctx; } void setCFG(CFG& c) { cfg = &c; } CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } - + bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); } using DeclBitVector_Types::AnalysisDataTy::isTracked; @@ -195,7 +195,7 @@ struct StmtDeclBitVector_Types { return I; } using DeclBitVector_Types::AnalysisDataTy::getIdx; - + unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } }; @@ -206,101 +206,101 @@ struct StmtDeclBitVector_Types { class ValTy : public DeclBitVector_Types::ValTy { llvm::BitVector BlkExprBV; typedef DeclBitVector_Types::ValTy ParentTy; - + static inline ParentTy& ParentRef(ValTy& X) { return static_cast<ParentTy&>(X); } - + static inline const ParentTy& ParentRef(const ValTy& X) { return static_cast<const ParentTy&>(X); } - + public: void resetBlkExprValues(AnalysisDataTy& AD) { BlkExprBV.resize(AD.getNumBlkExprs()); BlkExprBV.reset(); } - + void setBlkExprValues(AnalysisDataTy& AD) { BlkExprBV.resize(AD.getNumBlkExprs()); BlkExprBV.set(); } - + void resetValues(AnalysisDataTy& AD) { resetDeclValues(AD); resetBlkExprValues(AD); } - + void setValues(AnalysisDataTy& AD) { setDeclValues(AD); setBlkExprValues(AD); } - - bool operator==(const ValTy& RHS) const { - return ParentRef(*this) == ParentRef(RHS) + + bool operator==(const ValTy& RHS) const { + return ParentRef(*this) == ParentRef(RHS) && BlkExprBV == RHS.BlkExprBV; } - + void copyValues(const ValTy& RHS) { ParentRef(*this).copyValues(ParentRef(RHS)); BlkExprBV = RHS.BlkExprBV; } - + llvm::BitVector::reference operator()(const Stmt* S, const AnalysisDataTy& AD) { - return BlkExprBV[AD.getIdx(S)]; - } + return BlkExprBV[AD.getIdx(S)]; + } const llvm::BitVector::reference operator()(const Stmt* S, const AnalysisDataTy& AD) const { return const_cast<ValTy&>(*this)(S,AD); } - + using DeclBitVector_Types::ValTy::operator(); - - llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } + + llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } const llvm::BitVector::reference getStmtBit(unsigned i) const { return const_cast<llvm::BitVector&>(BlkExprBV)[i]; } - + ValTy& OrBlkExprBits(const ValTy& RHS) { BlkExprBV |= RHS.BlkExprBV; return *this; } - + ValTy& AndBlkExprBits(const ValTy& RHS) { BlkExprBV &= RHS.BlkExprBV; return *this; } - + ValTy& operator|=(const ValTy& RHS) { assert (sizesEqual(RHS)); ParentRef(*this) |= ParentRef(RHS); BlkExprBV |= RHS.BlkExprBV; return *this; } - + ValTy& operator&=(const ValTy& RHS) { assert (sizesEqual(RHS)); ParentRef(*this) &= ParentRef(RHS); BlkExprBV &= RHS.BlkExprBV; return *this; } - + bool sizesEqual(const ValTy& RHS) const { return ParentRef(*this).sizesEqual(ParentRef(RHS)) && BlkExprBV.size() == RHS.BlkExprBV.size(); } }; - + //===--------------------------------------------------------------------===// // Some useful merge operations. //===--------------------------------------------------------------------===// - + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; - + }; } // end namespace clang diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h new file mode 100644 index 000000000000..a5e11a100665 --- /dev/null +++ b/include/clang/Analysis/Support/BumpVector.h @@ -0,0 +1,215 @@ +//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides BumpVector, a vector-like ADT whose contents are +// allocated from a BumpPtrAllocator. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from SmallVector.h. We can +// refactor this core logic into something common that is shared between +// the two. The main thing that is different is the allocation strategy. + +#ifndef LLVM_CLANG_BUMP_VECTOR +#define LLVM_CLANG_BUMP_VECTOR + +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/PointerIntPair.h" +#include <algorithm> + +namespace clang { + +class BumpVectorContext { + llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1, bool> Alloc; +public: + /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator + /// and destroys it when the BumpVectorContext object is destroyed. + BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), true) {} + + /// Construct a new BumpVectorContext that reuses an existing + /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the + /// BumpVectorContext object is destroyed. + BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, false) {} + + ~BumpVectorContext() { + if (Alloc.getInt()) + delete Alloc.getPointer(); + } + + llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); } +}; + +template<typename T> +class BumpVector { + T *Begin, *End, *Capacity; +public: + // Default ctor - Initialize to empty. + explicit BumpVector(BumpVectorContext &C, unsigned N) + : Begin(NULL), End(NULL), Capacity(NULL) { + reserve(C, N); + } + + ~BumpVector() { + if (llvm::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (llvm::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, BumpVectorContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + void reserve(BumpVectorContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(BumpVectorContext &C, size_type MinSize = 0); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the BumpPtrAllocator. + T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity); + + // Copy the elements over. + if (llvm::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } + else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + + // For now, leak 'Begin'. We can add it back to a freelist in + // BumpVectorContext. + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif // end: LLVM_CLANG_BUMP_VECTOR diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h new file mode 100644 index 000000000000..3940007bb574 --- /dev/null +++ b/include/clang/Analysis/Support/Optional.h @@ -0,0 +1,55 @@ +//===-- Optional.h - Simple variant for passing optional 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 provides Optional, a template class modeled in the spirit of +// OCaml's 'opt' variant. The idea is to strongly type whether or not +// a value can be optional. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL +#define LLVM_CLANG_ANALYSIS_OPTIONAL + +namespace clang { + +template<typename T> +class Optional { + const T x; + unsigned hasVal : 1; +public: + explicit Optional() : hasVal(false) {} + Optional(const T &y) : x(y), hasVal(true) {} + + static inline Optional create(const T* y) { + return y ? Optional(*y) : Optional(); + } + + const T* getPointer() const { assert(hasVal); return &x; } + + operator bool() const { return hasVal; } + const T* operator->() const { return getPointer(); } + const T& operator*() const { assert(hasVal); return x; } +}; +} //end clang namespace + +namespace llvm { +template <typename T> +struct simplify_type<const ::clang::Optional<T> > { + typedef const T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::Optional<T> &Val) { + return Val.getPointer(); + } +}; + +template <typename T> +struct simplify_type< ::clang::Optional<T> > + : public simplify_type<const ::clang::Optional<T> > {}; +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/Support/SaveAndRestore.h b/include/clang/Analysis/Support/SaveAndRestore.h new file mode 100644 index 000000000000..4720c22d990e --- /dev/null +++ b/include/clang/Analysis/Support/SaveAndRestore.h @@ -0,0 +1,44 @@ +//===-- SaveAndRestore.h - Utility -------------------------------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides utility classes that uses RAII to save and restore +// values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE +#define LLVM_CLANG_ANALYSIS_SAVERESTORE + +namespace clang { + +// SaveAndRestore - A utility class that uses RAII to save and restore +// the value of a variable. +template<typename T> +struct SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } +private: + T& X; + T old_value; +}; + +// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old +// value of a variable is saved, and during the dstor the old value is +// or'ed with the new value. +struct SaveOr { + SaveOr(bool& x) : X(x), old_value(x) { x = false; } + ~SaveOr() { X |= old_value; } +private: + bool& X; + const bool old_value; +}; + +} +#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index ee79c517030f..3826d3a3acd6 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -30,28 +30,28 @@ break; #define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\ { static_cast<ImplClass*>(this)->VisitVarDecl(D); } - + namespace clang { template <typename ImplClass> class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { -public: +public: void VisitDeclRefExpr(DeclRefExpr* DR) { - static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); + static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); } - + void VisitDeclStmt(DeclStmt* DS) { for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); DI != DE; ++DI) { Decl* D = *DI; - static_cast<ImplClass*>(this)->VisitDecl(D); + static_cast<ImplClass*>(this)->VisitDecl(D); // Visit the initializer. if (VarDecl* VD = dyn_cast<VarDecl>(D)) if (Expr* I = VD->getInit()) static_cast<ImplClass*>(this)->Visit(I); } } - + void VisitDecl(Decl* D) { switch (D->getKind()) { DISPATCH_CASE(Function,FunctionDecl) @@ -67,7 +67,7 @@ public: assert(false && "Subtype of ScopedDecl not handled."); } } - + DEFAULT_DISPATCH(VarDecl) DEFAULT_DISPATCH(FunctionDecl) DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl) diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index 4d3201962250..83700a3a346d 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -20,12 +20,12 @@ namespace clang { template <typename ImplClass> class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { -public: +public: void VisitStmt(Stmt* S) { static_cast< ImplClass* >(this)->VisitChildren(S); } - + // Defining operator() allows the visitor to be used as a C++ style functor. void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} }; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index f42bbde8f148..426b9ccd8a23 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the CFGStmtVisitor interface, which extends +// This file defines the CFGStmtVisitor interface, which extends // StmtVisitor. This interface is useful for visiting statements in a CFG // where some statements have implicit control-flow and thus should // be treated specially. @@ -18,13 +18,13 @@ #define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H #include "clang/AST/StmtVisitor.h" -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" namespace clang { #define DISPATCH_CASE(CLASS) \ case Stmt::CLASS ## Class: return \ -static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); +static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); #define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ { return\ @@ -36,40 +36,40 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { Stmt* CurrentBlkStmt; struct NullifyStmt { - Stmt*& S; - + Stmt*& S; + NullifyStmt(Stmt*& s) : S(s) {} ~NullifyStmt() { S = NULL; } }; - + public: - CFGStmtVisitor() : CurrentBlkStmt(NULL) {} - + CFGStmtVisitor() : CurrentBlkStmt(NULL) {} + Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; } - + RetTy Visit(Stmt* S) { - if (S == CurrentBlkStmt || + if (S == CurrentBlkStmt || !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) return StmtVisitor<ImplClass,RetTy>::Visit(S); else return RetTy(); } - + /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in - /// CFGBlocks. Root statements are the statements that appear explicitly in + /// CFGBlocks. Root statements are the statements that appear explicitly in /// the list of statements in a CFGBlock. For substatements, or when there /// is no implementation provided for a BlockStmt_XXX method, we default /// to using StmtVisitor's Visit method. RetTy BlockStmt_Visit(Stmt* S) { CurrentBlkStmt = S; NullifyStmt cleanup(CurrentBlkStmt); - + switch (S->getStmtClass()) { DISPATCH_CASE(StmtExpr) DISPATCH_CASE(ConditionalOperator) DISPATCH_CASE(ObjCForCollectionStmt) - + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast<BinaryOperator>(S); if (B->isLogicalOp()) @@ -78,40 +78,40 @@ public: return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); // Fall through. } - + default: if (isa<Expr>(S)) - return + return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); else - return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); } } DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) - + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); } - + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); } - + RetTy BlockStmt_VisitExpr(Expr* E) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); } - + RetTy BlockStmt_VisitStmt(Stmt* S) { return static_cast<ImplClass*>(this)->Visit(S); } RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { - return + return static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); } - + RetTy BlockStmt_VisitComma(BinaryOperator* B) { return static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); @@ -120,21 +120,21 @@ public: //===--------------------------------------------------------------------===// // Utility methods. Not called by default (but subclasses may use them). //===--------------------------------------------------------------------===// - + /// VisitChildren: Call "Visit" on each child of S. void VisitChildren(Stmt* S) { - + switch (S->getStmtClass()) { default: break; - + case Stmt::StmtExprClass: { CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt(); if (CS->body_empty()) return; static_cast<ImplClass*>(this)->Visit(CS->body_back()); return; } - + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast<BinaryOperator>(S); if (B->getOpcode() != BinaryOperator::Comma) break; @@ -142,12 +142,12 @@ public: return; } } - + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) - if (*I) static_cast<ImplClass*>(this)->Visit(*I); + if (*I) static_cast<ImplClass*>(this)->Visit(*I); } -}; - +}; + #undef DEFAULT_BLOCKSTMT_VISIT #undef DISPATCH_CASE diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h index 25101235ddd2..1bc798f4e79e 100644 --- a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h @@ -18,44 +18,43 @@ #include "clang/Analysis/Visitors/CFGStmtVisitor.h" #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" -#include "clang/AST/CFG.h" namespace clang { template <typename ImplClass> class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> { const CFG& cfg; -public: +public: CFGVarDeclVisitor(const CFG& c) : cfg(c) {} - + void VisitStmt(Stmt* S) { static_cast<ImplClass*>(this)->VisitChildren(S); } - + void VisitDeclRefExpr(DeclRefExpr* DR) { static_cast<ImplClass*>(this)->VisitDeclChain(DR->getDecl()); } - + void VisitDeclStmt(DeclStmt* DS) { static_cast<ImplClass*>(this)->VisitDeclChain(DS->getDecl()); } - - void VisitDeclChain(ScopedDecl* D) { + + void VisitDeclChain(ScopedDecl* D) { for (; D != NULL ; D = D->getNextDeclarator()) static_cast<ImplClass*>(this)->VisitScopedDecl(D); } - + void VisitScopedDecl(ScopedDecl* D) { if (VarDecl* V = dyn_cast<VarDecl>(D)) static_cast<ImplClass*>(this)->VisitVarDecl(V); } - + void VisitVarDecl(VarDecl* D) {} - + void VisitAllDecls() { for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI) - static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI)); + static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI)); } }; diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index c2f4061c5d78..27997858c00c 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -35,7 +35,10 @@ // a -> __builtin_va_list // A -> "reference" to __builtin_va_list // V -> Vector, following num elements and a base type. +// X -> _Complex, followed by the base type. // P -> FILE +// J -> jmp_buf +// SJ -> sigjmp_buf // . -> "...". This may only occur at the end of the function list. // // Types maybe prefixed with the following modifiers: @@ -54,15 +57,16 @@ // of the function. These must be kept in sync with the predicates in the // Builtin::Context class. Currently we have: // n -> nothrow +// r -> noreturn // c -> const // F -> this is a libc/libm function with a '__builtin_' prefix added. // f -> this is a libc/libm function without the '__builtin_' prefix. It can // be followed by ':headername:' to state which header this function // comes from. -// p:N: -> this is a printf-like function whose Nth argument is the format +// p:N: -> this is a printf-like function whose Nth argument is the format // string. // P:N: -> similar to the p:N: attribute, but the function is like vprintf -// in that it accepts its arguments as a va_list rather than +// in that it accepts its arguments as a va_list rather than // through an ellipsis // e -> const, but only when -fmath-errno=0 // FIXME: gcc has nonnull @@ -72,28 +76,152 @@ #endif // Standard libc/libm functions: +BUILTIN(__builtin_atan2 , "ddd" , "nc") +BUILTIN(__builtin_atan2f, "fff" , "nc") +BUILTIN(__builtin_atan2l, "LdLdLd", "nc") +BUILTIN(__builtin_abs , "ii" , "ncF") +BUILTIN(__builtin_copysign, "ddd", "ncF") +BUILTIN(__builtin_copysignf, "fff", "ncF") +BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") +BUILTIN(__builtin_fabs , "dd" , "ncF") +BUILTIN(__builtin_fabsf, "ff" , "ncF") +BUILTIN(__builtin_fabsl, "LdLd", "ncF") +BUILTIN(__builtin_fmod , "ddd" , "nc") +BUILTIN(__builtin_fmodf, "fff" , "nc") +BUILTIN(__builtin_fmodl, "LdLdLd", "nc") +BUILTIN(__builtin_frexp , "ddi*" , "nc") +BUILTIN(__builtin_frexpf, "ffi*" , "nc") +BUILTIN(__builtin_frexpl, "LdLdi*", "nc") BUILTIN(__builtin_huge_val, "d", "nc") BUILTIN(__builtin_huge_valf, "f", "nc") BUILTIN(__builtin_huge_vall, "Ld", "nc") BUILTIN(__builtin_inf , "d" , "nc") BUILTIN(__builtin_inff , "f" , "nc") BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_ldexp , "ddi" , "nc") +BUILTIN(__builtin_ldexpf, "ffi" , "nc") +BUILTIN(__builtin_ldexpl, "LdLdi", "nc") +BUILTIN(__builtin_modf , "ddd*" , "nc") +BUILTIN(__builtin_modff, "fff*" , "nc") +BUILTIN(__builtin_modfl, "LdLdLd*", "nc") BUILTIN(__builtin_nan, "dcC*" , "ncF") BUILTIN(__builtin_nanf, "fcC*" , "ncF") BUILTIN(__builtin_nanl, "LdcC*", "ncF") BUILTIN(__builtin_nans, "dcC*" , "ncF") BUILTIN(__builtin_nansf, "fcC*" , "ncF") BUILTIN(__builtin_nansl, "LdcC*", "ncF") -BUILTIN(__builtin_abs , "ii" , "ncF") -BUILTIN(__builtin_fabs , "dd" , "ncF") -BUILTIN(__builtin_fabsf, "ff" , "ncF") -BUILTIN(__builtin_fabsl, "LdLd", "ncF") -BUILTIN(__builtin_copysign, "ddd", "ncF") -BUILTIN(__builtin_copysignf, "fff", "ncF") -BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") BUILTIN(__builtin_powi , "ddi" , "nc") BUILTIN(__builtin_powif, "ffi" , "nc") BUILTIN(__builtin_powil, "LdLdi", "nc") +BUILTIN(__builtin_pow , "ddd" , "nc") +BUILTIN(__builtin_powf, "fff" , "nc") +BUILTIN(__builtin_powl, "LdLdLd", "nc") + +// Standard unary libc/libm functions with double/float/long double variants: +BUILTIN(__builtin_acos , "dd" , "nc") +BUILTIN(__builtin_acosf, "ff" , "nc") +BUILTIN(__builtin_acosl, "LdLd", "nc") +BUILTIN(__builtin_asin , "dd" , "nc") +BUILTIN(__builtin_asinf, "ff" , "nc") +BUILTIN(__builtin_asinl, "LdLd", "nc") +BUILTIN(__builtin_atan , "dd" , "nc") +BUILTIN(__builtin_atanf, "ff" , "nc") +BUILTIN(__builtin_atanl, "LdLd", "nc") +BUILTIN(__builtin_ceil , "dd" , "nc") +BUILTIN(__builtin_ceilf, "ff" , "nc") +BUILTIN(__builtin_ceill, "LdLd", "nc") +BUILTIN(__builtin_cos , "dd" , "nc") +BUILTIN(__builtin_cosf, "ff" , "nc") +BUILTIN(__builtin_cosh , "dd" , "nc") +BUILTIN(__builtin_coshf, "ff" , "nc") +BUILTIN(__builtin_coshl, "LdLd", "nc") +BUILTIN(__builtin_cosl, "LdLd", "nc") +BUILTIN(__builtin_exp , "dd" , "nc") +BUILTIN(__builtin_expf, "ff" , "nc") +BUILTIN(__builtin_expl, "LdLd", "nc") +BUILTIN(__builtin_floor , "dd" , "nc") +BUILTIN(__builtin_floorf, "ff" , "nc") +BUILTIN(__builtin_floorl, "LdLd", "nc") +BUILTIN(__builtin_log , "dd" , "nc") +BUILTIN(__builtin_log10 , "dd" , "nc") +BUILTIN(__builtin_log10f, "ff" , "nc") +BUILTIN(__builtin_log10l, "LdLd", "nc") +BUILTIN(__builtin_logf, "ff" , "nc") +BUILTIN(__builtin_logl, "LdLd", "nc") +BUILTIN(__builtin_sin , "dd" , "nc") +BUILTIN(__builtin_sinf, "ff" , "nc") +BUILTIN(__builtin_sinh , "dd" , "nc") +BUILTIN(__builtin_sinhf, "ff" , "nc") +BUILTIN(__builtin_sinhl, "LdLd", "nc") +BUILTIN(__builtin_sinl, "LdLd", "nc") +BUILTIN(__builtin_sqrt , "dd" , "nc") +BUILTIN(__builtin_sqrtf, "ff" , "nc") +BUILTIN(__builtin_sqrtl, "LdLd", "nc") +BUILTIN(__builtin_tan , "dd" , "nc") +BUILTIN(__builtin_tanf, "ff" , "nc") +BUILTIN(__builtin_tanh , "dd" , "nc") +BUILTIN(__builtin_tanhf, "ff" , "nc") +BUILTIN(__builtin_tanhl, "LdLd", "nc") +BUILTIN(__builtin_tanl, "LdLd", "nc") + +// C99 complex builtins +BUILTIN(__builtin_cabs, "dXd", "Fnc") +BUILTIN(__builtin_cabsf, "fXf", "Fnc") +BUILTIN(__builtin_cabsl, "LdXLd", "Fnc") +BUILTIN(__builtin_cacos, "XdXd", "Fnc") +BUILTIN(__builtin_cacosf, "XfXf", "Fnc") +BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_carg, "dXd", "Fnc") +BUILTIN(__builtin_cargf, "fXf", "Fnc") +BUILTIN(__builtin_cargl, "LdXLd", "Fnc") +BUILTIN(__builtin_casin, "XdXd", "Fnc") +BUILTIN(__builtin_casinf, "XfXf", "Fnc") +BUILTIN(__builtin_casinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_catan, "XdXd", "Fnc") +BUILTIN(__builtin_catanf, "XfXf", "Fnc") +BUILTIN(__builtin_catanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccos, "XdXd", "Fnc") +BUILTIN(__builtin_ccosf, "XfXf", "Fnc") +BUILTIN(__builtin_ccosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccosh, "XdXd", "Fnc") +BUILTIN(__builtin_ccoshf, "XfXf", "Fnc") +BUILTIN(__builtin_ccoshl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cexp, "XdXd", "Fnc") +BUILTIN(__builtin_cexpf, "XfXf", "Fnc") +BUILTIN(__builtin_cexpl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cimag, "dXd", "Fnc") +BUILTIN(__builtin_cimagf, "fXf", "Fnc") +BUILTIN(__builtin_cimagl, "LdXLd", "Fnc") +BUILTIN(__builtin_conj, "dXd", "Fnc") +BUILTIN(__builtin_conjf, "fXf", "Fnc") +BUILTIN(__builtin_conjl, "LdXLd", "Fnc") +BUILTIN(__builtin_clog, "XdXd", "Fnc") +BUILTIN(__builtin_clogf, "XfXf", "Fnc") +BUILTIN(__builtin_clogl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cproj, "XdXd", "Fnc") +BUILTIN(__builtin_cprojf, "XfXf", "Fnc") +BUILTIN(__builtin_cprojl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cpow, "XdXdXd", "Fnc") +BUILTIN(__builtin_cpowf, "XfXfXf", "Fnc") +BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fnc") +BUILTIN(__builtin_creal, "dXd", "Fnc") +BUILTIN(__builtin_crealf, "fXf", "Fnc") +BUILTIN(__builtin_creall, "LdXLd", "Fnc") +BUILTIN(__builtin_csin, "XdXd", "Fnc") +BUILTIN(__builtin_csinf, "XfXf", "Fnc") +BUILTIN(__builtin_csinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csinh, "XdXd", "Fnc") +BUILTIN(__builtin_csinhf, "XfXf", "Fnc") +BUILTIN(__builtin_csinhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csqrt, "XdXd", "Fnc") +BUILTIN(__builtin_csqrtf, "XfXf", "Fnc") +BUILTIN(__builtin_csqrtl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctan, "XdXd", "Fnc") +BUILTIN(__builtin_ctanf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctanh, "XdXd", "Fnc") +BUILTIN(__builtin_ctanhf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc") // FP Comparisons. BUILTIN(__builtin_isgreater , "i.", "nc") @@ -103,6 +231,14 @@ BUILTIN(__builtin_islessequal , "i.", "nc") BUILTIN(__builtin_islessgreater , "i.", "nc") BUILTIN(__builtin_isunordered , "i.", "nc") +// Unary FP classification +// BUILTIN(__builtin_fpclassify, "iiiii.", "nc") +BUILTIN(__builtin_isfinite, "i.", "nc") +BUILTIN(__builtin_isinf, "i.", "nc") +BUILTIN(__builtin_isinf_sign, "i.", "nc") +BUILTIN(__builtin_isnan, "i.", "nc") +BUILTIN(__builtin_isnormal, "i.", "nc") + // Builtins for arithmetic. BUILTIN(__builtin_clz , "iUi" , "nc") BUILTIN(__builtin_clzl , "iULi" , "nc") @@ -138,6 +274,7 @@ BUILTIN(__builtin_stdarg_start, "vA.", "n") BUILTIN(__builtin_bcmp, "iv*v*z", "n") BUILTIN(__builtin_bcopy, "vv*v*z", "n") BUILTIN(__builtin_bzero, "vv*z", "n") +BUILTIN(__builtin_memchr, "v*vC*iz", "nF") BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") BUILTIN(__builtin_memmove, "v*v*vC*z", "nF") @@ -169,6 +306,8 @@ BUILTIN(__builtin_flt_rounds, "i", "nc") BUILTIN(__builtin_setjmp, "iv**", "") BUILTIN(__builtin_longjmp, "vv**i", "") BUILTIN(__builtin_unwind_init, "v", "") +BUILTIN(__builtin_eh_return_data_regno, "ii", "nc") +BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") // GCC Object size checking builtins BUILTIN(__builtin_object_size, "zv*i", "n") @@ -192,7 +331,9 @@ BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") BUILTIN(__builtin_expect, "iii" , "nc") BUILTIN(__builtin_prefetch, "vvC*.", "nc") -BUILTIN(__builtin_trap, "v", "n") +BUILTIN(__builtin_abort, "v", "Fnr") +BUILTIN(__builtin_trap, "v", "nr") +BUILTIN(__builtin_unreachable, "v", "nr") BUILTIN(__builtin_shufflevector, "v." , "nc") @@ -335,6 +476,8 @@ BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n") // C99 library functions // C99 stdlib.h LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h") +LIBBUILTIN(exit, "vi", "fr", "stdlib.h") +LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h") LIBBUILTIN(malloc, "v*z", "f", "stdlib.h") LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h") // C99 string.h @@ -365,6 +508,8 @@ LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h") LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h") LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h") LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h") +// C99 +LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h") // Non-C library functions // FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode! @@ -377,15 +522,17 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h") // POSIX strings.h LIBBUILTIN(index, "c*cC*i", "f", "strings.h") LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h") +// POSIX unistd.h +LIBBUILTIN(_exit, "vi", "fr", "unistd.h") +// POSIX setjmp.h +LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h") +LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h") // FIXME: This type isn't very correct, it should be // id objc_msgSend(id, SEL) // but we need new type letters for that. LIBBUILTIN(objc_msgSend, "v*.", "f", "objc/message.h") -// FIXME: asprintf and vasprintf aren't C99 functions. Should they be -// target-specific builtins, perhaps? - // Builtin math library functions LIBBUILTIN(pow, "ddd", "fe", "math.h") LIBBUILTIN(powl, "LdLdLd", "fe", "math.h") diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index f770c5089eec..07f091a58a4e 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -17,6 +17,10 @@ #include <cstring> +// VC++ defines 'alloca' as an object-like macro, which interferes with our +// builtins. +#undef alloca + namespace llvm { template <typename T> class SmallVectorImpl; } @@ -63,35 +67,40 @@ public: /// \brief Popular the vector with the names of all of the builtins. void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, bool NoBuiltins); - + /// Builtin::GetName - Return the identifier name for the specified builtin, /// e.g. "__builtin_abs". const char *GetName(unsigned ID) const { return GetRecord(ID).Name; } - + /// GetTypeString - Get the type descriptor string for the specified builtin. const char *GetTypeString(unsigned ID) const { return GetRecord(ID).Type; } - + /// isConst - Return true if this function has no side effects and doesn't /// read memory. bool isConst(unsigned ID) const { return strchr(GetRecord(ID).Attributes, 'c') != 0; } - + /// isNoThrow - Return true if we know this builtin never throws an exception. bool isNoThrow(unsigned ID) const { return strchr(GetRecord(ID).Attributes, 'n') != 0; } - + + /// isNoReturn - Return true if we know this builtin never returns. + bool isNoReturn(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'r') != 0; + } + /// isLibFunction - Return true if this is a builtin for a libc/libm function, /// with a "__builtin_" prefix (e.g. __builtin_abs). bool isLibFunction(unsigned ID) const { return strchr(GetRecord(ID).Attributes, 'F') != 0; } - + /// \brief Determines whether this builtin is a predefined libc/libm /// function, such as "malloc", where we know the signature a /// priori. @@ -115,7 +124,7 @@ public: bool hasVAListUse(unsigned ID) const { return strpbrk(GetRecord(ID).Type, "Aa") != 0; } - + /// isConstWithoutErrno - Return true if this function has no side /// effects and doesn't read memory, except for possibly errno. Such /// functions can be const when the MathErrno lang option is diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h index 73e2fcd12fee..4da2ad757223 100644 --- a/include/clang/Basic/ConvertUTF.h +++ b/include/clang/Basic/ConvertUTF.h @@ -8,9 +8,9 @@ *==------------------------------------------------------------------------==*/ /* * Copyright 2001-2004 Unicode, Inc. - * + * * Disclaimer - * + * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine @@ -18,9 +18,9 @@ * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. - * + * * Limitations on Rights to Redistribute This Code - * + * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form @@ -41,7 +41,7 @@ Each routine converts the text between *sourceStart and sourceEnd, putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. + targetEnd. Note: the end pointers are *after* the last item: e.g. *(sourceEnd - 1) is the last item. The return result indicates whether the conversion was successful, @@ -53,12 +53,12 @@ the respective buffers. Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. These conversion functions take a ConversionFlags argument. When this flag is set to strict, both irregular sequences and isolated surrogates @@ -75,15 +75,15 @@ they constitute an error. Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. + Fixes & updates, Sept 2001. ------------------------------------------------------------------------ */ @@ -95,10 +95,10 @@ bit mask & shift operations. ------------------------------------------------------------------------ */ -typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ /* Some fundamental constants */ #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD @@ -108,15 +108,15 @@ typedef unsigned char Boolean; /* 0 or 1 */ #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ } ConversionResult; typedef enum { - strictConversion = 0, - lenientConversion + strictConversion = 0, + lenientConversion } ConversionFlags; /* This is for C++ and does no harm in C */ @@ -125,29 +125,29 @@ extern "C" { #endif ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); #ifdef CLANG_NEEDS_THESE_ONE_DAY ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); #endif Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 207710bdff31..380192e9dae6 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -15,7 +15,9 @@ #define LLVM_CLANG_DIAGNOSTIC_H #include "clang/Basic/SourceLocation.h" +#include "llvm/Support/type_traits.h" #include <string> +#include <vector> #include <cassert> namespace llvm { @@ -23,12 +25,14 @@ namespace llvm { } namespace clang { - class DiagnosticClient; - class SourceRange; + class DeclContext; class DiagnosticBuilder; + class DiagnosticClient; class IdentifierInfo; class LangOptions; - + class PartialDiagnostic; + class SourceRange; + // Import the diagnostic enums themselves. namespace diag { // Start position for diagnostics. @@ -44,7 +48,7 @@ namespace clang { }; class CustomDiagInfo; - + /// diag::kind - All of the diagnostics that can be emitted by the frontend. typedef unsigned kind; @@ -55,7 +59,7 @@ namespace clang { NUM_BUILTIN_COMMON_DIAGNOSTICS #undef DIAG }; - + /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR /// (emit as an error). It allows clients to map errors to @@ -67,13 +71,13 @@ namespace clang { MAP_WARNING = 2, //< Map this diagnostic to a warning. MAP_ERROR = 3, //< Map this diagnostic to an error. MAP_FATAL = 4, //< Map this diagnostic to a fatal error. - + /// Map this diagnostic to "warning", but make it immune to -Werror. This /// happens when you specify -Wno-error=foo. MAP_WARNING_NO_WERROR = 5 }; } - + /// \brief Annotates a diagnostic with some code that should be /// inserted, removed, or replaced to fix the problem. /// @@ -102,7 +106,7 @@ public: /// \brief Create a code modification hint that inserts the given /// code string at a specific location. - static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc, + static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc, const std::string &Code) { CodeModificationHint Hint; Hint.InsertionLoc = InsertionLoc; @@ -120,7 +124,7 @@ public: /// \brief Create a code modification hint that replaces the given /// source range with the given code string. - static CodeModificationHint CreateReplacement(SourceRange RemoveRange, + static CodeModificationHint CreateReplacement(SourceRange RemoveRange, const std::string &Code) { CodeModificationHint Hint; Hint.RemoveRange = RemoveRange; @@ -140,13 +144,13 @@ public: enum Level { Ignored, Note, Warning, Error, Fatal }; - + /// ExtensionHandling - How do we handle otherwise-unmapped extension? This /// is controlled by -pedantic and -pedantic-errors. enum ExtensionHandling { Ext_Ignore, Ext_Warn, Ext_Error }; - + enum ArgumentKind { ak_std_string, // std::string ak_c_string, // const char * @@ -155,14 +159,17 @@ public: ak_identifierinfo, // IdentifierInfo ak_qualtype, // QualType ak_declarationname, // DeclarationName - ak_nameddecl // NamedDecl * + ak_nameddecl, // NamedDecl * + ak_nestednamespec, // NestedNameSpecifier * + ak_declcontext // DeclContext * }; -private: +private: unsigned char AllExtensionsSilenced; // Used by __extension__ bool IgnoreAllWarnings; // Ignore all warnings: -w - bool WarningsAsErrors; // Treat warnings like errors: + bool WarningsAsErrors; // Treat warnings like errors: bool SuppressSystemWarnings; // Suppress warnings in system headers. + bool SuppressAllDiagnostics; // Suppress all diagnostics. ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? DiagnosticClient *Client; @@ -172,13 +179,15 @@ private: /// when the mapping was established as a user mapping. If the high bit is /// clear, then the low bits are set to the default value, and should be /// mapped with -pedantic, -Werror, etc. - mutable unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2]; - + + typedef std::vector<unsigned char> DiagMappings; + mutable std::vector<DiagMappings> DiagMappingsStack; + /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or /// fatal error is emitted, and is sticky. bool ErrorOccurred; bool FatalErrorOccurred; - + /// LastDiagLevel - This is the level of the last diagnostic emitted. This is /// used to emit continuation diagnostics with the same level as the /// diagnostic that they follow. @@ -204,44 +213,70 @@ private: public: explicit Diagnostic(DiagnosticClient *client = 0); ~Diagnostic(); - + //===--------------------------------------------------------------------===// // Diagnostic characterization methods, used by a client to customize how // - + DiagnosticClient *getClient() { return Client; }; const DiagnosticClient *getClient() const { return Client; }; - + + + /// pushMappings - Copies the current DiagMappings and pushes the new copy + /// onto the top of the stack. + void pushMappings(); + + /// popMappings - Pops the current DiagMappings off the top of the stack + /// causing the new top of the stack to be the active mappings. Returns + /// true if the pop happens, false if there is only one DiagMapping on the + /// stack. + bool popMappings(); + void setClient(DiagnosticClient* client) { Client = client; } /// setIgnoreAllWarnings - When set to true, any unmapped warnings are /// ignored. If this and WarningsAsErrors are both set, then this one wins. void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } - + /// setWarningsAsErrors - When set to true, any warnings reported are issued /// as errors. void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } bool getWarningsAsErrors() const { return WarningsAsErrors; } - + /// setSuppressSystemWarnings - When set to true mask warnings that /// come from system headers. void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + /// \brief Suppress all diagnostics, to silence the front end when we + /// know that we don't want any more diagnostics to be passed along to the + /// client + void setSuppressAllDiagnostics(bool Val = true) { + SuppressAllDiagnostics = Val; + } + bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } + + /// \brief Pretend that the last diagnostic issued was ignored. This can + /// be used by clients who suppress diagnostics themselves. + void setLastDiagnosticIgnored() { + LastDiagLevel = Ignored; + } + /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped /// extension diagnostics are mapped onto ignore/warning/error. This /// corresponds to the GCC -pedantic and -pedantic-errors option. void setExtensionHandlingBehavior(ExtensionHandling H) { ExtBehavior = H; } - + /// AllExtensionsSilenced - This is a counter bumped when an __extension__ /// block is encountered. When non-zero, all extension diagnostics are /// entirely silenced, no matter how they are mapped. void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } - + bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } + /// setDiagnosticMapping - This allows the client to specify that certain /// warnings are ignored. Notes can never be mapped, errors can only be /// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily. @@ -252,7 +287,7 @@ public: "Cannot map errors!"); setDiagnosticMappingInternal(Diag, Map, true); } - + /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. /// "unknown-pragmas" to have the specified mapping. This returns true and /// ignores the request if "Group" was unknown, false otherwise. @@ -263,13 +298,13 @@ public: unsigned getNumErrors() const { return NumErrors; } unsigned getNumDiagnostics() const { return NumDiagnostics; } - + /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. unsigned getCustomDiagID(Level L, const char *Message); - - + + /// ConvertArgToString - This method converts a diagnostic argument (as an /// intptr_t) into the string that represents it. void ConvertArgToString(ArgumentKind Kind, intptr_t Val, @@ -279,12 +314,12 @@ public: ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output, ArgToStringCookie); } - + void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { ArgToStringFn = Fn; ArgToStringCookie = Cookie; } - + //===--------------------------------------------------------------------===// // Diagnostic classification and reporting interfaces. // @@ -292,7 +327,7 @@ public: /// getDescription - Given a diagnostic ID, return a description of the /// issue. const char *getDescription(unsigned DiagID) const; - + /// isNoteWarningOrExtension - Return true if the unmapped diagnostic /// level of the specified diagnostic ID is a Warning or Extension. /// This only works on builtin diagnostics, not custom ones, and is not legal to @@ -302,12 +337,12 @@ public: /// \brief Determine whether the given built-in diagnostic ID is a /// Note. static bool isBuiltinNote(unsigned DiagID); - + /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic /// ID is for an extension of some sort. /// static bool isBuiltinExtensionDiag(unsigned DiagID); - + /// getWarningOptionForDiag - Return the lowest-level warning option that /// enables the specified diagnostic. If there is no -Wfoo flag that controls /// the diagnostic, this returns null. @@ -326,8 +361,8 @@ public: /// getDiagnosticLevel - Based on the way the client configured the Diagnostic /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. - Level getDiagnosticLevel(unsigned DiagID) const; - + Level getDiagnosticLevel(unsigned DiagID) const; + /// Report - Issue the message to the client. @c DiagID is a member of the /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder /// which emits the diagnostics (through @c ProcessDiag) when it is destroyed. @@ -337,24 +372,25 @@ public: /// \brief Clear out the current diagnostic. void Clear() { CurDiagID = ~0U; } - + private: /// getDiagnosticMappingInfo - Return the mapping info currently set for the /// specified builtin diagnostic. This returns the high bit encoding, or zero /// if the field is completely uninitialized. unsigned getDiagnosticMappingInfo(diag::kind Diag) const { - return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 15); + const DiagMappings ¤tMappings = DiagMappingsStack.back(); + return (diag::Mapping)((currentMappings[Diag/2] >> (Diag & 1)*4) & 15); } - + void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map, bool isUser) const { if (isUser) Map |= 8; // Set the high bit for user mappings. - unsigned char &Slot = DiagMappings[DiagId/2]; + unsigned char &Slot = DiagMappingsStack.back()[DiagId/2]; unsigned Shift = (DiagId & 1)*4; Slot &= ~(15 << Shift); Slot |= Map << Shift; } - + /// getDiagnosticLevel - This is an internal implementation helper used when /// DiagClass is already known. Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const; @@ -371,7 +407,7 @@ private: /// CurDiagLoc - This is the location of the current diagnostic that is in /// flight. FullSourceLoc CurDiagLoc; - + /// CurDiagID - This is the ID of the current diagnostic that is in flight. /// This is set to ~0U when there is no diagnostic in flight. unsigned CurDiagID; @@ -382,7 +418,7 @@ private: /// than that almost certainly has to be simplified anyway. MaxArguments = 10 }; - + /// NumDiagArgs - This contains the number of entries in Arguments. signed char NumDiagArgs; /// NumRanges - This is the number of ranges in the DiagRanges array. @@ -395,7 +431,7 @@ private: /// values, with one for each argument. This specifies whether the argument /// is in DiagArgumentsStr or in DiagArguments. unsigned char DiagArgumentsKind[MaxArguments]; - + /// DiagArgumentsStr - This holds the values of each string argument for the /// current diagnostic. This value is only used when the corresponding /// ArgumentKind is ak_std_string. @@ -406,11 +442,11 @@ private: /// mangled into an intptr_t and the intepretation depends on exactly what /// sort of argument kind it is. intptr_t DiagArgumentsVal[MaxArguments]; - + /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. const SourceRange *DiagRanges[10]; - + enum { MaxCodeModificationHints = 3 }; /// CodeModificationHints - If valid, provides a hint with some code @@ -443,14 +479,14 @@ private: class DiagnosticBuilder { mutable Diagnostic *DiagObj; mutable unsigned NumArgs, NumRanges, NumCodeModificationHints; - + void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT friend class Diagnostic; explicit DiagnosticBuilder(Diagnostic *diagObj) - : DiagObj(diagObj), NumArgs(0), NumRanges(0), + : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) {} -public: +public: /// Copy constructor. When copied, this "takes" the diagnostic info from the /// input and neuters it. DiagnosticBuilder(const DiagnosticBuilder &D) { @@ -467,7 +503,7 @@ public: /// \brief Create an empty DiagnosticBuilder object that represents /// no actual diagnostic. - explicit DiagnosticBuilder(SuppressKind) + explicit DiagnosticBuilder(SuppressKind) : DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { } /// \brief Force the diagnostic builder to emit the diagnostic now. @@ -504,7 +540,7 @@ public: /// Destructor - The dtor emits the diagnostic if it hasn't already /// been emitted. ~DiagnosticBuilder() { Emit(); } - + /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: /// return Diag(...); @@ -518,7 +554,7 @@ public: DiagObj->DiagArgumentsStr[NumArgs++] = S; } } - + void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { assert(NumArgs < Diagnostic::MaxArguments && "Too many arguments to diagnostic!"); @@ -527,14 +563,14 @@ public: DiagObj->DiagArgumentsVal[NumArgs++] = V; } } - + void AddSourceRange(const SourceRange &R) const { - assert(NumRanges < + assert(NumRanges < sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && "Too many arguments to diagnostic!"); if (DiagObj) DiagObj->DiagRanges[NumRanges++] = &R; - } + } void AddCodeModificationHint(const CodeModificationHint &Hint) const { assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints && @@ -579,6 +615,20 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Diagnostic::ak_identifierinfo); return DB; } + +// Adds a DeclContext to the diagnostic. The enable_if template magic is here +// so that we only match those arguments that are (statically) DeclContexts; +// other arguments that derive from DeclContext (e.g., RecordDecls) will not +// match. +template<typename T> +inline +typename llvm::enable_if<llvm::is_same<T, DeclContext>, + const DiagnosticBuilder &>::type +operator<<(const DiagnosticBuilder &DB, T *DC) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC), + Diagnostic::ak_declcontext); + return DB; +} inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, const SourceRange &R) { @@ -605,7 +655,7 @@ inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){ //===----------------------------------------------------------------------===// // DiagnosticInfo //===----------------------------------------------------------------------===// - + /// DiagnosticInfo - This is a little helper class (which is basically a smart /// pointer that forward info from Diagnostic) that allows clients to enquire /// about the currently in-flight diagnostic. @@ -613,74 +663,74 @@ class DiagnosticInfo { const Diagnostic *DiagObj; public: explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {} - + const Diagnostic *getDiags() const { return DiagObj; } unsigned getID() const { return DiagObj->CurDiagID; } const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; } - + unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } - + /// getArgKind - Return the kind of the specified index. Based on the kind /// of argument, the accessors below can be used to get the value. Diagnostic::ArgumentKind getArgKind(unsigned Idx) const { assert(Idx < getNumArgs() && "Argument index out of range!"); return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; } - + /// getArgStdStr - Return the provided argument string specified by Idx. const std::string &getArgStdStr(unsigned Idx) const { assert(getArgKind(Idx) == Diagnostic::ak_std_string && "invalid argument accessor!"); return DiagObj->DiagArgumentsStr[Idx]; } - + /// getArgCStr - Return the specified C string argument. const char *getArgCStr(unsigned Idx) const { assert(getArgKind(Idx) == Diagnostic::ak_c_string && "invalid argument accessor!"); return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); } - + /// getArgSInt - Return the specified signed integer argument. int getArgSInt(unsigned Idx) const { assert(getArgKind(Idx) == Diagnostic::ak_sint && "invalid argument accessor!"); return (int)DiagObj->DiagArgumentsVal[Idx]; } - + /// getArgUInt - Return the specified unsigned integer argument. unsigned getArgUInt(unsigned Idx) const { assert(getArgKind(Idx) == Diagnostic::ak_uint && "invalid argument accessor!"); return (unsigned)DiagObj->DiagArgumentsVal[Idx]; } - + /// getArgIdentifier - Return the specified IdentifierInfo argument. const IdentifierInfo *getArgIdentifier(unsigned Idx) const { assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo && "invalid argument accessor!"); return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); } - + /// getRawArg - Return the specified non-string argument in an opaque form. intptr_t getRawArg(unsigned Idx) const { assert(getArgKind(Idx) != Diagnostic::ak_std_string && "invalid argument accessor!"); return DiagObj->DiagArgumentsVal[Idx]; } - - + + /// getNumRanges - Return the number of source ranges associated with this /// diagnostic. unsigned getNumRanges() const { return DiagObj->NumDiagRanges; } - + const SourceRange &getRange(unsigned Idx) const { assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); return *DiagObj->DiagRanges[Idx]; } - + unsigned getNumCodeModificationHints() const { return DiagObj->NumCodeModificationHints; } @@ -690,7 +740,7 @@ public: } const CodeModificationHint *getCodeModificationHints() const { - return DiagObj->NumCodeModificationHints? + return DiagObj->NumCodeModificationHints? &DiagObj->CodeModificationHints[0] : 0; } @@ -699,20 +749,20 @@ public: /// array. void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const; }; - + /// DiagnosticClient - This is an abstract interface implemented by clients of /// the front-end, which formats and prints fully processed diagnostics. class DiagnosticClient { public: virtual ~DiagnosticClient(); - + /// setLangOptions - This is set by clients of diagnostics when they know the /// language parameters of the diagnostics that may be sent through. Note /// that this can change over time if a DiagClient has multiple languages sent /// through it. It may also be set to null (e.g. when processing command line /// options). virtual void setLangOptions(const LangOptions *LO) {} - + /// IncludeInDiagnosticCounts - This method (whose default implementation /// returns true) indicates whether the diagnostics handled by this /// DiagnosticClient should be included in the number of diagnostics diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index e059d5e60520..cbf9cdbc1599 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -41,7 +41,8 @@ def err_expected_namespace_name : Error<"expected namespace name">; // Sema && Lex def ext_longlong : Extension< - "'long long' is an extension when C99 mode is not enabled">; + "'long long' is an extension when C99 mode is not enabled">, + InGroup<LongLong>; def warn_integer_too_large : Warning< "integer constant is too large for its type">; def warn_integer_too_large_for_signed : Warning< diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index a8dbd68df10f..dfdf0ff2e733 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -14,6 +14,8 @@ def err_drv_unsupported_opt : Error<"unsupported option '%0'">; def err_drv_unknown_stdin_type : Error< "-E or -x required when input is from standard input">; def err_drv_unknown_language : Error<"language not recognized: '%0'">; +def err_drv_invalid_arch_name : Error< + "invalid arch name '%0'">; def err_drv_invalid_opt_with_multiple_archs : Error< "option '%0' cannot be used with multiple -arch options">; def err_drv_invalid_output_with_multiple_archs : Error< @@ -43,15 +45,21 @@ def err_drv_invalid_version_number : Error< "invalid version number in '%0'">; def err_drv_no_linker_llvm_support : Error< "'%0': unable to pass LLVM bit-code files to linker">; +def err_drv_no_ast_support : Error< + "'%0': unable to use AST files with this tool">; def err_drv_clang_unsupported : Error< "the clang compiler does not support '%0'">; def err_drv_command_failed : Error< "%0 command failed with exit code %1 (use -v to see invocation)">; def err_drv_command_signalled : Error< "%0 command failed due to signal %1 (use -v to see invocation)">; +def err_drv_invalid_mfloat_abi : Error< + "invalid float ABI '%0'">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; +def warn_drv_preprocessed_input_file_unused : Warning< + "%0: previously preprocessed input unused when '%1' is present">; def warn_drv_unused_argument : Warning< "argument unused during compilation: '%0'">; def warn_drv_pipe_ignored_with_save_temps : Warning< @@ -64,5 +72,7 @@ def warn_drv_not_using_clang_arch : Warning< "not using the clang compiler for the '%0' architecture">; def warn_drv_clang_unsupported : Warning< "the clang compiler does not support '%0'">; +def warn_drv_assuming_mfloat_abi_is : Warning< + "unknown platform, assuming -mfloat-abi=%0">; } diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 815ae8d70003..e5c73270fdfc 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -11,8 +11,14 @@ let Component = "Frontend" in { def err_fe_unknown_triple : Error< "unknown target triple '%0', please use -triple or -arch">; +def err_fe_unknown_target_abi : Error<"unknown target ABI '%0'">; def err_fe_error_reading : Error<"error reading '%0'">; def err_fe_error_reading_stdin : Error<"error reading stdin">; +def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; +def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; +def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; +def err_fe_invalid_code_complete_file + : Error<"cannot locate code-completion file %0">, DefaultFatal; def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; def note_fixit_in_macro : Note< @@ -24,6 +30,9 @@ def warn_fixit_no_changes : Note< "FIX-IT detected errors it could not fix; no output will be generated">; // PCH reader +def err_relocatable_without_without_isysroot : Error< + "must specify system root with -isysroot when building a relocatable " + "PCH file">; def warn_pch_target_triple : Error< "PCH file was compiled for the target '%0' but the current translation " "unit is being compiled for target '%1'">; @@ -66,6 +75,9 @@ def warn_pch_altivec : Error< 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_elide_constructors : Error< + "Elidable copy constructors 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">; @@ -80,8 +92,14 @@ def warn_pch_builtins : Error< "PCH file was compiled with builtins %select{enabled|disabled}0 but " "builtins are currently %select{enabled|disabled}1">; def warn_pch_thread_safe_statics : Error< - "PCH file was compiled %select{without|with}0 thread-safe statics but" + "PCH file was compiled %select{without|with}0 thread-safe statics but " "thread-safe statics are currently %select{disabled|enabled}1">; +def warn_pch_posix_threads : Error< + "PCH file was compiled %select{without|with}0 POSIX thread support but " + "POSIX threads are currently %select{disabled|enabled}1">; +def warn_pch_stack_protector : Error< + "stack protector was %select{off|on|required}0 in PCH file but " + "is currently %select{off|on|required}1">; def warn_pch_blocks : Error< "blocks were %select{disabled|enabled}0 in PCH file but " "are currently %select{disabled|enabled}1">; @@ -118,6 +136,8 @@ def warn_pch_version_too_old : Error< "PCH file uses an older PCH format that is no longer supported">; def warn_pch_version_too_new : Error< "PCH file uses a newer PCH format that cannot be read">; +def warn_pch_different_branch : Error< + "PCH file built from a different branch (%0) than the compiler (%1)">; def warn_cmdline_conflicting_macro_def : Error< "definition of the macro '%0' conflicts with the definition used to " "build the precompiled header">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 2896f7988c01..c34bdc111c90 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -19,12 +19,13 @@ def Implicit : DiagGroup<"implicit", [ // Empty DiagGroups: these are recognized by clang but ignored. +def : DiagGroup<"address">; def : DiagGroup<"aggregate-return">; +def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; def : DiagGroup<"cast-align">; def : DiagGroup<"cast-qual">; def : DiagGroup<"char-align">; -def : DiagGroup<"char-subscripts">; def Comment : DiagGroup<"comment">; def : DiagGroup<"conversion">; def : DiagGroup<"declaration-after-statement">; @@ -38,6 +39,7 @@ def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; def FourByteMultiChar : DiagGroup<"four-char-constants">; +def : DiagGroup<"import">; def : DiagGroup<"init-self">; def : DiagGroup<"inline">; def : DiagGroup<"int-to-pointer-cast">; @@ -49,15 +51,17 @@ def : DiagGroup<"missing-noreturn">; def MultiChar : DiagGroup<"multichar">; def : DiagGroup<"nested-externs">; def : DiagGroup<"newline-eof">; -def : DiagGroup<"long-long">; +def LongLong : DiagGroup<"long-long">; def MismatchedTags : DiagGroup<"mismatched-tags">; def : DiagGroup<"missing-field-initializers">; def NonNull : DiagGroup<"nonnull">; def : DiagGroup<"nonportable-cfstrings">; def : DiagGroup<"old-style-definition">; +def : DiagGroup<"overflow">; +def : DiagGroup<"overloaded-virtual">; def : DiagGroup<"packed">; def Parentheses : DiagGroup<"parentheses">; -def : DiagGroup<"pointer-arith">; +def PointerArith : DiagGroup<"pointer-arith">; def : DiagGroup<"pointer-to-int-cast">; def : DiagGroup<"redundant-decls">; def ReturnType : DiagGroup<"return-type">; @@ -66,6 +70,9 @@ def : DiagGroup<"shadow">; def : DiagGroup<"shorten-64-to-32">; def : DiagGroup<"sign-compare">; +// Preprocessor warnings. +def : DiagGroup<"builtin-macro-redefined">; + // Just silence warnings about common forms of -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; def : DiagGroup<"strict-aliasing=1">; @@ -94,11 +101,14 @@ def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedValue : DiagGroup<"unused-value">; def UnusedVariable : DiagGroup<"unused-variable">; def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">; +def Reorder : DiagGroup<"reorder">; def UndeclaredSelector : DiagGroup<"undeclared-selector">; +def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def : DiagGroup<"variadic-macros">; def VectorConversions : DiagGroup<"vector-conversions">; // clang specific def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def : DiagGroup<"write-strings">; +def CharSubscript : DiagGroup<"char-subscripts">; // Aggregation warning settings. @@ -126,6 +136,7 @@ def Most : DiagGroup<"most", [ Implicit, MismatchedTags, MultiChar, + ReturnType, Switch, Trigraphs, Uninitialized, @@ -134,8 +145,8 @@ def Most : DiagGroup<"most", [ UnusedVariable, VectorConversions, VolatileRegisterVar, - ReadOnlySetterAttrs, - UndeclaredSelector + Reorder, + CharSubscript ]>; // -Wall is -Wmost -Wparentheses diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 6ca50db50a8a..3f132c0dabfa 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -112,7 +112,8 @@ def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; def pp_out_of_date_dependency : Warning< "current file is older than dependency %0">; def pp_undef_builtin_macro : Warning<"undefining builtin macro">; -def pp_redef_builtin_macro : Warning<"redefining builtin macro">; +def pp_redef_builtin_macro : Warning<"redefining builtin macro">, + InGroup<DiagGroup<"builtin-macro-redefined">>; def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore, InGroup<DiagGroup<"unused-macros">>; def warn_pp_undef_identifier : Warning< @@ -226,10 +227,17 @@ def ext_stdc_pragma_syntax_eom : def warn_stdc_fenv_access_not_supported : Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, InGroup<UnknownPragmas>; -def warn_pragma_diagnostic_invalid : +def warn_pragma_diagnostic_gcc_invalid : ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or" " 'fatal'">, InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_clang_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'" + " 'push', or 'pop'">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_clang_cannot_ppp : + ExtWarn<"pragma diagnostic pop could not pop, no matching push">, + InGroup<UnknownPragmas>; def warn_pragma_diagnostic_invalid_option : ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, InGroup<UnknownPragmas>; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index d65a97eb7067..6971df50cb55 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -35,6 +35,7 @@ def err_invalid_short_spec : Error<"'short %0' is invalid">; def err_invalid_long_spec : Error<"'long %0' is invalid">; def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; +def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">; def ext_ident_list_in_param : Extension< "type-less parameter names in function declaration">; @@ -77,7 +78,7 @@ def err_expected_rparen : Error<"expected ')'">; def err_expected_rsquare : Error<"expected ']'">; def err_expected_rbrace : Error<"expected '}'">; def err_expected_greater : Error<"expected '>'">; -def err_expected_semi_declation : Error< +def err_expected_semi_declaration : Error< "expected ';' at end of declaration">; def err_expected_semi_decl_list : Error< "expected ';' at end of declaration list">; @@ -135,9 +136,13 @@ def err_rvalue_reference : Error< def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; +def err_missing_comma_before_ellipsis : Error< + "C requires a comma prior to the ellipsis in a variadic function type">; def err_unexpected_typedef_ident : Error< "unexpected type name %0: expected identifier">; def err_expected_class_name : Error<"expected class name">; +def err_destructor_class_name : Error< + "expected the class name after '~' to name a destructor">; def err_unspecified_vla_size_with_static : Error< "'static' may not be used with an unspecified variable length array size">; @@ -150,14 +155,16 @@ def err_typename_invalid_functionspec : Error< "type name does not allow function specifier to be specified">; def err_invalid_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier">; +def err_friend_invalid_in_context : Error< + "'friend' used outside of class">; def err_unknown_typename : Error< "unknown type name %0">; def err_use_of_tag_name_without_tag : Error< "use of tagged type %0 without '%1' tag">; def err_expected_ident_in_using : Error< "expected an identifier in using directive">; -def err_unexpected_template_spec_in_using : Error< - "use of template specialization in using directive not allowed">; +def err_using_decl_can_not_refer_to_template_spec : Error< + "using declaration can not refer to template specialization">; /// Objective-C parser diagnostics @@ -272,6 +279,10 @@ def err_expected_type_name_after_typename : Error< def err_variadic_templates : Error< "variadic templates are only allowed in C++0x">; + +// C++ declarations +def err_friend_decl_defines_class : Error< + "cannot define a type in a friend declaration">; // Language specific pragmas // - Generic warnings diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b1a73d05a45f..b03676d877e2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -67,6 +67,9 @@ def ext_flexible_array_init : Extension< // Declarations. def ext_vla : Extension< "variable length arrays are a C99 feature, accepted as an extension">; +def err_vla_cxx : Error< + "variable length arrays are not permitted in C++">; + def ext_anon_param_requires_type_specifier : Extension< "type specifier required for unnamed parameter, defaults to int">; def err_bad_variable_name : Error< @@ -74,9 +77,11 @@ def err_bad_variable_name : Error< def err_parameter_name_omitted : Error<"parameter name omitted">; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup<UnusedParameter>, DefaultIgnore; +def warn_unused_variable : Warning<"unused variable %0">, + InGroup<UnusedVariable>, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">; - + def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup<ImplicitFunctionDeclare>, DefaultIgnore; @@ -92,10 +97,18 @@ def warn_use_out_of_scope_declaration : Warning< "use of out-of-scope declaration of %0">; def err_inline_non_function : Error< "'inline' can only appear on functions">; + +// C++ using declarations def err_using_requires_qualname : Error< "using declaration requires a qualified name">; def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; +def err_using_decl_nested_name_specifier_is_not_a_base_class : Error< + "using declaration refers into '%0', which is not a base class of %1">; +def err_using_decl_can_not_refer_to_class_member : Error< + "using declaration can not refer to class member">; + def err_using_decl_can_not_refer_to_namespace : Error< + "using declaration can not refer to namespace">; def err_invalid_thread : Error< "'__thread' is only allowed on variable declarations">; @@ -104,6 +117,23 @@ def err_thread_non_global : Error< def err_thread_unsupported : Error< "thread-local storage is unsupported for the current target">; +def warn_maybe_falloff_nonvoid_function : Warning< + "control may reach end of non-void function">, + InGroup<ReturnType>; +def warn_falloff_nonvoid_function : Warning< + "control reaches end of non-void function">, + InGroup<ReturnType>; +def err_maybe_falloff_nonvoid_block : Error< + "control may reach end of non-void block">; +def err_falloff_nonvoid_block : Error< + "control reaches end of non-void block">; +def warn_suggest_noreturn_function : Warning< + "function could be attribute 'noreturn'">, + InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore; +def warn_suggest_noreturn_block : Warning< + "block could be attribute 'noreturn'">, + InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore; + /// Built-in functions. def ext_implicit_lib_function_decl : ExtWarn< "implicitly declaring C library function '%0' with type %1">; @@ -113,11 +143,27 @@ def note_please_include_header : Note< def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; def err_implicit_decl_requires_stdio : Error< "implicit declaration of '%0' requires inclusion of the header <stdio.h>">; +def err_implicit_decl_requires_setjmp : Error< + "implicit declaration of '%0' requires inclusion of the header <setjmp.h>">; def warn_redecl_library_builtin : Warning< "incompatible redeclaration of library function %0">; def err_builtin_definition : Error<"definition of builtin function %0">; def err_types_compatible_p_in_cplusplus : Error< "__builtin_types_compatible_p is not valid in C++">; +def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError; + +/// main() +// static/inline main() are not errors in C, just in C++. +def warn_unusual_main_decl : Warning<"'main' should not be declared " + "%select{static|inline|static or inline}0">; +def err_unusual_main_decl : Error<"'main' is not allowed to be declared " + "%select{static|inline|static or inline}0">; +def err_main_returns_nonint : Error<"'main' must return 'int'">; +def err_main_surplus_args : Error<"%0 is too many arguments for 'main': " + "must be 0, 2, or 3">; +def warn_main_one_arg : Warning<"one-argument 'main' is usually a mistake">; +def err_main_arg_wrong : Error<"%select{first|second|third}0 argument of " + "'main' should be of type %1">; /// parser diagnostics def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">; @@ -135,6 +181,8 @@ def warn_pragma_pack_pop_identifer_and_alignment : Warning< "specifying both a name and alignment to 'pop' is undefined">; def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">; +def warn_pragma_unused_undeclared_var : Warning< + "undeclared variable %0 used as an argument for '#pragma unused'">; def warn_pragma_unused_expected_localvar : Warning< "only local variables can be arguments to '#pragma unused'">; def err_unsupported_pragma_weak : Error< @@ -145,6 +193,8 @@ def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; def err_undef_superclass : Error< "cannot find interface declaration for %0, superclass of %1">; +def err_recursive_superclass : Error< + "trying to recursively use %0 as superclass of %1">; def warn_previous_alias_decl : Warning<"previously declared alias is ignored">; def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; def warn_undef_interface : Warning<"cannot find interface declaration for %0">; @@ -166,10 +216,12 @@ def warn_dup_category_def : Warning< "duplicate definition of category %1 on interface %0">; def err_conflicting_super_class : Error<"conflicting super class name %0">; def err_dup_implementation_class : Error<"reimplementation of class %0">; +def err_dup_implementation_category : Error< + "reimplementation of category %1 for class %0">; def err_conflicting_ivar_type : Error< "instance variable %0 has conflicting type: %1 vs %2">; def err_conflicting_ivar_bitwidth : Error< - "instance variable %0 has conflicting bitfield width">; + "instance variable %0 has conflicting bit-field width">; def err_conflicting_ivar_name : Error< "conflicting instance variable names: %0 vs %1">; def err_inconsistant_ivar_count : Error< @@ -183,6 +235,10 @@ def warn_conflicting_ret_types : Warning< def warn_conflicting_param_types : Warning< "conflicting parameter types in implementation of %0: %1 vs %2">; +def warn_implements_nscopying : Warning< +"default assign attribute on property %0 which implements " +"NSCopying protocol is not appropriate with -fobjc-gc[-only]">; + def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; @@ -255,11 +311,26 @@ def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; def err_static_assert_failed : Error<"static_assert failed \"%0\"">; -def err_friend_decl_outside_class : Error< - "'friend' used outside of class">; +def err_unexpected_friend : Error< + "friends can only be classes or functions">; +def err_enum_friend : Error< + "enum types cannot be friends">; +def err_friend_is_member : Error< + "friends cannot be members of the declaring class">; +def ext_friend_inner_class : Extension< + "C++ 98 does not allow inner classes as friends">; +def err_unelaborated_friend_type : Error< + "must specify '%select{struct|union|class|enum}0' to befriend %1">; +def err_qualified_friend_not_found : Error< + "no function named %0 with type %1 was found in the specified scope">; +def err_introducing_special_friend : Error< + "must use a qualified name when declaring a %select{constructor|" + "destructor|conversion operator}0 as a friend">; +def err_tagless_friend_type_template : Error< + "friend type templates must use an elaborated type">; def err_abstract_type_in_decl : Error< - "%select{return|parameter|variable|field}1 type %0 is an abstract class">; + "%select{return|parameter|variable|field}0 type %1 is an abstract class">; def err_allocation_of_abstract_type : Error< "allocation of an object of abstract type %0">; @@ -285,10 +356,17 @@ def err_distant_exception_spec : Error< "exception specifications are not allowed beyond a single level " "of indirection">; def err_incomplete_in_exception_spec : Error< - "%select{|pointer to |reference to }1incomplete type %0 is not allowed " + "%select{|pointer to |reference to }0incomplete type %1 is not allowed " "in exception specification">; def err_mismatched_exception_spec : Error< "exception specification in declaration does not match previous declaration">; +def err_override_exception_spec : Error< + "exception specification of overriding function is more lax than " + "base version">; +def err_incompatible_exception_specs : Error< + "target exception specification is not superset of source">; +def err_deep_exception_specs_differ : Error< + "exception specifications of %select{return|argument}0 types differ">; // C++ access checking def err_class_redeclared_with_different_access : Error< @@ -299,6 +377,12 @@ def note_previous_access_declaration : Note< // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; +def err_nested_name_member_ref_lookup_ambiguous : Error< + "lookup of %0 in member access expression is ambiguous">; +def note_ambig_member_ref_object_type : Note< + "lookup in the object type %0 refers here">; +def note_ambig_member_ref_scope : Note< + "lookup from the current scope refers here">; // C++ class members def err_storageclass_invalid_for_member : Error< @@ -332,6 +416,21 @@ def err_implicit_object_parameter_init : Error< "cannot initialize object parameter of type %0 with an expression " "of type %1">; +def err_missing_default_constructor : Error< + "default constructor for %1 is missing in initialization of " + "%select{base class|member}0">; +def err_illegal_union_member : Error< + "union member %0 has a non-trivial %select{constructor|" + "copy constructor|copy assignment operator|destructor}1">; +def note_nontrivial_has_virtual : Note< + "because type %0 has a virtual %select{member function|base class}1">; +def note_nontrivial_has_nontrivial : Note< + "because type %0 has a %select{member|base class}1 with a non-trivial " + "%select{constructor|copy constructor|copy assignment operator|destructor}2">; +def note_nontrivial_user_defined : Note< + "because type %0 has a user-declared %select{constructor|copy constructor|" + "copy assignment operator|destructor}1">; + def err_different_return_type_for_overriding_virtual_function : Error< "virtual function %0 has a different return type (%1) than the " "function it overrides (which has return type %2)">; @@ -378,9 +477,15 @@ def err_destructor_with_params : Error<"destructor cannot have any parameters">; def err_destructor_variadic : Error<"destructor cannot be variadic">; def err_destructor_typedef_name : Error< "destructor cannot be declared using a typedef %0 of the class name">; +def err_destructor_name : Error< + "expected the class name after '~' to name the enclosing class">; // C++ initialization def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">; +def err_invalid_initialization : Error< +"invalid initialization of reference of type %0 from expression of type %1">; +def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue " + "due to multiple conversion functions">; // FIXME: passing in an English string as %1! def err_not_reference_to_const_init : Error< "non-const lvalue reference to type %0 cannot be initialized " @@ -412,6 +517,8 @@ def err_illegal_decl_array_of_auto : Error< 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">; +def err_auto_var_requires_init : Error< + "declaration of variable %0 with type %1 requires an initializer">; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< @@ -464,23 +571,37 @@ def err_ext_vector_component_name_illegal : Error< "illegal vector component name '%0'">; def err_attribute_address_space_not_int : Error< "address space attribute requires an integer constant">; +def err_attribute_address_space_negative : Error< + "address space is negative">; +def err_attribute_address_space_too_high : Error< + "address space is larger than the maximum supported (%0)">; def err_attribute_address_multiple_qualifiers : Error< "multiple address spaces specified for type">; def err_implicit_pointer_address_space_cast : Error< "illegal implicit cast between two pointers with different address spaces">; def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; -def err_attribute_annotate_no_string : Error< - "argument to annotate attribute was not a string literal">; +def err_arg_with_address_space : Error< + "parameter may not be qualified with an address space">; +def err_attribute_not_string : Error< + "argument to %0 attribute was not a string literal">; +def err_attribute_section_invalid_for_target : Error< + "argument to 'section' attribute is not valid for this target: %0">; def err_attribute_aligned_not_power_of_two : Error< "requested alignment is not a power of 2">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "'%0' redeclared without %1 attribute: previous %1 ignored">; def warn_attribute_ignored : Warning<"%0 attribute ignored">; +def warn_attribute_precede_definition : Warning< + "attribute declaration must precede definition">; def warn_attribute_weak_on_field : Warning< "__weak attribute cannot be specified on a field declaration">; def warn_attribute_weak_on_local : Warning< "__weak attribute cannot be specified on an automatic variable">; +def warn_weak_identifier_undeclared : Warning< + "weak identifier %0 never declared">; +def err_attribute_weak_static : Error< + "weak declaration of '%0' must be public">; def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; def warn_attribute_wrong_decl_type : Warning< @@ -521,6 +642,8 @@ def err_attr_wrong_decl : Error< "'%0' attribute invalid on this declaration, requires typedef or value">; def warn_attribute_nonnull_no_pointers : Warning< "'nonnull' attribute applied to function with no pointer arguments">; +def warn_attribute_malloc_pointer_only : Warning< + "'malloc' attribute only applies to functions returning a pointer type">; def warn_transparent_union_nonpointer : Warning< "'transparent_union' attribute support incomplete; only supported for " "pointer unions">; @@ -594,8 +717,16 @@ def err_param_default_argument_references_this : Error< def err_param_default_argument_nonfunc : Error< "default arguments can only be specified for parameters in a function " "declaration">; +def err_param_default_argument_template_redecl : Error< + "default arguments cannot be added to a function template that has already " + "been declared">; +def err_param_default_argument_member_template_redecl : Error< + "default arguments cannot be added to an out-of-line definition of a member " + "of a %select{class template|class template partial specialization|nested " + "class in a template}0">; +def note_field_decl : Note<"member is declared here">; def err_defining_default_ctor : Error< - "cannot define the implicit default constructor for %0, because %select{base class|member}1 " + "cannot define the implicit default constructor for %0, because %select{base class|member's type}1 " "%2 does not have any default constructor">; def note_previous_class_decl : Note< "%0 declared here">; @@ -608,6 +739,12 @@ def note_first_required_here : Note< def err_unintialized_member : Error< "cannot define the implicit default constructor for %0, because " "%select{reference|const}1 member %2 cannot be default-initialized">; +def err_null_intialized_reference_member : Error< + "cannot initialize the member to null in default constructor because " + "reference member %0 cannot be null-initialized">; +def err_unintialized_member_in_ctor : Error< + "constructor for %0 must explicitly initialize the " + "%select{reference|const}1 member %2 ">; def err_use_of_default_argument_to_function_declared_later : Error< "use of default argument to function %0 that is declared later in class %1">; @@ -639,12 +776,23 @@ def err_ovl_ambiguous_member_call : Error< def err_ovl_deleted_member_call : Error< "call to %select{unavailable|deleted}0 member function %1">; def err_ovl_candidate : Note<"candidate function">; +def err_ovl_candidate_not_viable : Note<"function not viable because" + " of ambiguity in conversion of argument %0">; +def note_ambiguous_type_conversion: Note< + "because of ambiguity in conversion of %0 to %1">; +def err_ovl_template_candidate : Note< + "candidate function template specialization %0">; def err_ovl_candidate_deleted : Note< "candidate function has been explicitly %select{made unavailable|deleted}0">; -def err_ovl_builtin_candidate : Note<"built-in candidate function %0">; +def err_ovl_builtin_binary_candidate : Note< + "built-in candidate operator %0 (%1, %2)">; +def err_ovl_builtin_unary_candidate : Note< + "built-in candidate operator %0 (%1)">; def err_ovl_no_viable_function_in_init : Error< "no matching constructor for initialization of %0">; def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; +def err_ref_init_ambiguous : Error< + "reference initialization of type %0 with initializer of type %1 is ambiguous">; def err_ovl_deleted_init : Error< "call to %select{unavailable|deleted}0 constructor of %1">; def err_ovl_ambiguous_oper : Error< @@ -663,6 +811,10 @@ def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to non-static member function without an object argument">; +// C++ Address of Overloaded Function +def err_addr_ovl_ambiguous : Error< + "address of overloaded function %0 is ambiguous">; + // C++ Template Declarations def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; @@ -704,6 +856,12 @@ def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; + +def err_template_variable : Error<"variable %0 declared as a template">; +def err_template_variable_noparams : Error< + "extraneous 'template<>' in declaration of variable %0">; +def err_template_tag_noparams : Error< + "extraneous 'template<>' in declaration of %0 %1">; // C++ Template Argument Lists def err_template_arg_list_different_arity : Error< @@ -776,25 +934,64 @@ def err_template_arg_not_pointer_to_member_form : Error< def err_template_arg_extra_parens : Error< "non-type template argument cannot be surrounded by parentheses">; -// C++ class template specialization -def err_template_spec_needs_header : Error< - "template specialization requires 'template<>'">; -def err_template_spec_extra_headers : Error< - "template specialization must have a single 'template<>' header">; +// C++ template specialization +def err_template_spec_unknown_kind : Error< + "can only provide an explicit %select{<error>|<error>|specialization|" + "instantiation|instantiation}0 for a class template, function template, or " + "a member function, static data member, or member class of a class template">; +def note_specialized_entity : Note< + "explicitly %select{<error>|<error>|specialized|instantiated|instantiated}0 " + "declaration is here">; +def err_template_spec_decl_function_scope : Error< + "explicit %select{<error>|<error>|specialization|instantiation|" + "instantiation}0 of %1 in function scope">; +def err_template_spec_decl_class_scope : Error< + "explicit %select{<error>|<error>|specialization|instantiation|" + "instantiation}0 of %1 in class scope">; def err_template_spec_decl_out_of_scope_global : Error< - "class template %select{|partial }0specialization of %1 must occur in the " - "global scope">; + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 must " + "originally be declared in the global scope">; def err_template_spec_decl_out_of_scope : Error< - "class template %select{|partial }0specialization of %1 not in namespace %2">; -def err_template_spec_decl_function_scope : Error< - "%select{class template specialization|class template partial specialization|" - "explicit instantiation}0 of %1 in function scope">; + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 must " + "originally be declared in namespace %2">; def err_template_spec_redecl_out_of_scope : Error< - "%select{class template specialization|class template partial specialization|" - "explicit instantiation}0 of %1 not in a namespace enclosing %2">; + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 not in a " + "namespace enclosing %2">; def err_template_spec_redecl_global_scope : Error< - "%select{class template specialization|class template partial specialization|" - "explicit instantiation}0 of %1 must occur at global scope">; + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 must occur " + "at global scope">; +def err_spec_member_not_instantiated : Error< + "specialization of member %q0 does not specialize an instantiated member">; +def note_specialized_decl : Note<"attempt to specialize declaration here">; +def err_specialization_after_instantiation : Error< + "explicit specialization of %0 after instantiation">; +def note_instantiation_required_here : Note< + "%select{implicit|explicit}0 instantiation first required here">; +def err_template_spec_friend : Error< + "template specialization declaration cannot be a friend">; +def err_template_spec_default_arg : Error< + "default argument not permitted on an explicit " + "%select{instantiation|specialization}0 of function %1">; + +// C++ class template specializations and out-of-line definitions +def err_template_spec_needs_header : Error< + "template specialization requires 'template<>'">; +def err_template_spec_needs_template_parameters : Error< + "template specialization or definition requires a template parameter list" + "corresponding to the nested type %0">; +def err_template_param_list_matches_nontemplate : Error< + "template parameter list matching the non-templated nested type %0 should " + "be empty ('template<>')">; +def err_template_spec_extra_headers : Error< + "extraneous template parameter list in template specialization or " + "out-of-line template definition">; +def err_template_qualified_declarator_no_match : Error< + "nested name specifier '%0' for declaration does not refer into a class, " + "class template or class template partial specialization">; // C++ Class Template Partial Specialization def err_default_arg_in_partial_spec : Error< @@ -815,9 +1012,19 @@ def warn_partial_specs_not_deducible : Warning< "deduced; this partial specialization will never be used">; def note_partial_spec_unused_parameter : Note< "non-deducible template parameter %0">; -def unsup_template_partial_spec_ordering : Error< - "partial ordering of class template partial specializations is not yet " - "supported">; +def err_partial_spec_ordering_ambiguous : Error< + "ambiguous partial specializations of %0">; +def note_partial_spec_match : Note<"partial specialization matches %0">; + +// C++ Function template specializations +def err_function_template_spec_no_match : Error< + "no function template matches function template specialization %0">; +def err_function_template_spec_ambiguous : Error< + "function template specialization %0 ambiguously refers to more than one " + "function template; explicitly specify%select{|additional }1 template " + "arguments to identify a particular function template">; +def note_function_template_spec_matched : Note< + "function template matches specialization %0">; // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< @@ -838,9 +1045,14 @@ 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_template_static_data_member_def_here : Note< + "in instantiation of static data member %q0 requested here">; def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; +def note_default_function_arg_instantiation_here : Note< + "in instantiation of default function argument expression " + "for '%0' required here">; def note_explicit_template_arg_substitution_here : Note< "while substituting explicitly-specified template arguments into function " "template %f, here">; @@ -873,15 +1085,34 @@ def note_nontemplate_decl_here : Note< "non-templated declaration is here">; def err_explicit_instantiation_out_of_scope : Error< "explicit instantiation of %0 not in a namespace enclosing %1">; - +def err_explicit_instantiation_requires_name : Error< + "explicit instantiation declaration requires a name">; +def err_explicit_instantiation_of_typedef : Error< + "explicit instantiation of typedef %0">; +def err_explicit_instantiation_not_known : Error< + "explicit instantiation of %0 does not refer to a function template, member " + "function, member class, or static data member">; +def note_explicit_instantiation_here : Note< + "explicit instantiation refers here">; +def err_explicit_instantiation_data_member_not_instantiated : Error< + "explicit instantiation refers to static data member %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_member_function_not_instantiated : Error< + "explicit instantiation refers to member function %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_ambiguous : Error< + "partial ordering for explicit instantiation of %0 is ambiguous">; +def note_explicit_instantiation_candidate : Note< + "explicit instantiation candidate function template here %0">; + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; -def err_typename_nested_not_found_global : Error< - "no type named %0 in the global namespace">; def err_typename_nested_not_type : Error< - "typename specifier refers to non-type member %0">; + "typename specifier refers to non-type member %0 in %1">; def note_typename_refers_here : Note< "referenced member %0 is declared here">; +def err_typename_missing : Error< + "missing 'typename' prior to dependent type name '%0%1'">; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; @@ -1018,11 +1249,11 @@ def err_bitfield_has_negative_width : Error< "bit-field %0 has negative width (%1)">; def err_anon_bitfield_has_negative_width : Error< "anonymous bit-field has negative width (%0)">; -def err_bitfield_has_zero_width : Error<"bit-field %0 has zero width">; +def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; def err_bitfield_width_exceeds_type_size : Error< "size of bit-field %0 exceeds size of its type (%1 bits)">; def err_anon_bitfield_width_exceeds_type_size : Error< - "size of anonymous bitfield exceeds size of its type (%0 bits)">; + "size of anonymous bit-field exceeds size of its type (%0 bits)">; def err_redefinition_of_label : Error<"redefinition of label '%0'">; def err_undeclared_label_use : Error<"use of undeclared label '%0'">; @@ -1053,6 +1284,8 @@ def note_protected_by_cxx_try : Note< "jump bypasses initialization of try block">; def note_protected_by_cxx_catch : Note< "jump bypasses initialization of catch block">; +def note_protected_by___block : Note< + "jump bypasses setup of __block variable">; def err_func_returning_array_function : Error< "function cannot return array or function type %0">; @@ -1105,16 +1338,16 @@ def err_func_def_incomplete_result : Error< // Expressions. def ext_sizeof_function_type : Extension< - "invalid application of 'sizeof' to a function type">; + "invalid application of 'sizeof' to a function type">, InGroup<PointerArith>; def ext_sizeof_void_type : Extension< - "invalid application of '%0' to a void type">; + "invalid application of '%0' to a void type">, InGroup<PointerArith>; // FIXME: merge with %select def err_sizeof_incomplete_type : Error< "invalid application of 'sizeof' to an incomplete type %0">; def err_alignof_incomplete_type : Error< "invalid application of '__alignof' to an incomplete type %0">; def err_sizeof_alignof_bitfield : Error< - "invalid application of '%select{sizeof|__alignof}0' to bitfield">; + "invalid application of '%select{sizeof|__alignof}0' to bit-field">; def err_offsetof_record_type : Error< "offsetof requires struct, union, or class type, %0 invalid">; def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; @@ -1127,6 +1360,11 @@ def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, InGroup<DiagGroup<"float-equal">>, DefaultIgnore; +def warn_shift_negative : Warning< + "shift count is negative">; +def warn_shift_gt_typewidth : Warning< + "shift count >= width of type">; + def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " "non-fragile ABI">; @@ -1163,12 +1401,15 @@ def err_typecheck_member_reference_unknown : Error< "cannot refer to member %0 with '%select{.|->}1'">; def note_member_reference_needs_call : Note< "perhaps you meant to call this function with '()'?">; +def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, + InGroup<CharSubscript>, DefaultIgnore; def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; -def err_typecheck_no_member : Error<"no member named %0">; +def err_no_member : Error<"no member named %0 in %1">; + def err_member_redeclared : Error<"class member cannot be redeclared">; def err_member_def_does_not_match : Error< - "out-of-line definition does not match any declaration in %0">; + "out-of-line definition of %0 does not match any declaration in %1">; def err_nonstatic_member_out_of_line : Error< "non-static data member defined out-of-line">; def err_qualified_typedef_declarator : Error< @@ -1191,6 +1432,8 @@ def err_typecheck_pointer_arith_void_type : Error< "arithmetic on pointer to void type">; def err_typecheck_decl_incomplete_type : Error< "variable has incomplete type %0">; +def ext_typecheck_decl_incomplete_type : ExtWarn< + "tentative definition of variable with internal linkage has incomplete non-array type %0">; def err_tentative_def_incomplete_type : Error< "tentative definition has type %0 that is never completed">; def err_tentative_def_incomplete_type_arr : Error< @@ -1215,6 +1458,10 @@ def err_typecheck_unary_expr : Error< "invalid argument type %0 to unary expression">; def err_typecheck_indirection_requires_pointer : Error< "indirection requires pointer operand (%0 invalid)">; +def err_indirection_requires_nonfragile_object : Error< + "indirection cannot be to an interface in non-fragile ABI (%0 invalid)">; +def err_direct_interface_unsupported : Error< + "indirection to an interface is not supported (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">; def err_typecheck_sub_ptr_object : Error< @@ -1223,8 +1470,12 @@ def err_typecheck_sub_ptr_compatible : Error< "%0 and %1 are not pointers to compatible types">; def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn< "ordered comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< + "ordered comparison between pointer and zero (%0 and %1) is an extension">; def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< "ordered comparison of function pointers (%0 and %1)">; +def ext_typecheck_comparison_of_fptr_to_void : Extension< + "equality comparison between function pointer and void pointer (%0 and %1)">; def ext_typecheck_comparison_of_pointer_integer : ExtWarn< "comparison between pointer and integer (%0 and %1)">; def ext_typecheck_comparison_of_distinct_pointers : ExtWarn< @@ -1271,9 +1522,10 @@ def err_unexpected_interface : Error< def err_property_not_found : Error< "property %0 not found on object of type %1">; def ext_gnu_void_ptr : Extension< - "use of GNU void* extension">; + "use of GNU void* extension">, InGroup<PointerArith>; def ext_gnu_ptr_func_arith : Extension< - "arithmetic on pointer to function type %0 is a GNU extension">; + "arithmetic on pointer to function type %0 is a GNU extension">, + InGroup<PointerArith>; def error_readonly_property_assignment : Error< "assigning to property with 'readonly' attribute not allowed">; def ext_integer_increment_complex : Extension< @@ -1326,36 +1578,56 @@ def note_property_impl_required : Note< // C++ casts -def err_bad_cxx_cast_generic : Error<"%0 from %2 to %1 is not allowed">; -def err_bad_cxx_cast_rvalue : Error<"%0 from rvalue to reference type %1">; +// These messages adhere to the TryCast pattern: %0 is an int specifying the +// cast type, %1 is the source type, %2 is the destination type. +def err_bad_cxx_cast_generic : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 is not allowed">; +def err_bad_cxx_cast_rvalue : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from rvalue to reference type %2">; def err_bad_cxx_cast_const_away : Error< - "%0 from %2 to %1 casts away constness">; + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 casts away constness">; def err_bad_const_cast_dest : Error< - "const_cast to %0, which is not a reference, pointer-to-object, " - "or pointer-to-data-member">; - -def err_bad_reinterpret_cast_same_type : Error< - "source and destination type of reinterpret_cast are not distinct">; -def ext_reinterpret_cast_fn_obj : Extension< - "reinterpret_cast between pointer-to-function and pointer-to-object is " - "an extension">; - + "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " + "which is not a reference, pointer-to-object, or pointer-to-data-member">; +def ext_cast_fn_obj : Extension< + "cast between pointer-to-function and pointer-to-object is an extension">; def err_bad_reinterpret_cast_small_int : Error< - "cast from pointer to smaller type %0 loses information">; + "cast from pointer to smaller type %2 loses information">; +def err_bad_cxx_cast_vector_to_scalar_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to scalar %2 of different size">; +def err_bad_cxx_cast_scalar_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " + "to vector %2 of different size">; +def err_bad_cxx_cast_vector_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to vector %2 of different size">; +def err_bad_lvalue_to_rvalue_cast : Error< + "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " + "not compatible">; +def err_bad_static_cast_pointer_nonpointer : Error< + "cannot cast from type %1 to pointer type %2">; +def err_bad_static_cast_member_pointer_nonmp : Error< + "cannot cast from type %1 to member pointer type %2">; +def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">; + +// These messages don't adhere to the pattern. +// FIXME: Display the path somehow better. +def err_ambiguous_base_to_derived_cast : Error< + "ambiguous cast from base %0 to derived %1:%2">; +def err_static_downcast_via_virtual : Error< + "cannot cast %0 to %1 via virtual base %2">; +def err_downcast_from_inaccessible_base : Error< + "cannot cast %1 to %0 due to inaccessible conversion path">; def err_bad_dynamic_cast_not_ref_or_ptr : Error< "%0 is not a reference or pointer">; def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; -// FIXME: Display the path somehow better. -def err_ambiguous_base_to_derived_cast : Error< - "ambiguous static_cast from base %0 to derived %1:%2">; -def err_static_downcast_via_virtual : Error< - "cannot cast %0 to %1 via virtual base %2">; -def err_bad_lvalue_to_rvalue_cast : Error< - "cannot cast from lvalue of type %0 to rvalue reference to %1; types are " - "not compatible">; // Other C++ expressions def err_need_header_before_typeid : Error< @@ -1375,6 +1647,8 @@ def err_array_size_not_integral : Error< def err_new_uninitialized_const : Error< "must provide an initializer if the allocated object is 'const'">; def err_delete_operand : Error<"cannot delete expression of type %0">; +def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " + "expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behaviour">; def err_decrement_bool : Error<"cannot decrement expression of type bool">; @@ -1394,6 +1668,9 @@ def err_bad_memptr_rhs : Error< def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; +def warn_exception_caught_by_earlier_handler : Warning< + "exception of type %0 will be caught by earlier handler">; +def note_previous_exception_handler : Note<"for type %0">; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " @@ -1412,6 +1689,22 @@ def err_throw_incomplete_ptr : Error< def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; +def err_ident_in_pseudo_dtor_not_a_type : Error< + "identifier %0 in pseudo-destructor expression does not name a type">; +def err_operator_arrow_circular : Error< + "circular pointer delegation detected">; +def err_pseudo_dtor_base_not_scalar : Error< + "object expression of non-scalar type %0 cannot be used in a " + "pseudo-destructor expression">; +def err_pseudo_dtor_type_mismatch : Error< + "the type of object expression (%0) does not match the type being destroyed " + "(%1) in pseudo-destructor expression">; +def err_pseudo_dtor_call_with_args : Error< + "call to pseudo-destructor cannot have any arguments">; +def err_dtor_expr_without_call : Error< + "%select{destructor reference|pseudo-destructor expression}0 must be " + "called immediately with '()'">; + def err_invalid_use_of_function_type : Error< "a function type is not allowed here">; def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; @@ -1419,6 +1712,8 @@ def err_type_defined_in_condition : Error< "types may not be defined in conditions">; def err_typecheck_bool_condition : Error< "value of type %0 is not contextually convertible to 'bool'">; +def err_typecheck_ambiguous_condition : Error< + "conversion from %0 to %1 is ambiguous">; def err_expected_class_or_namespace : Error<"expected a class or namespace">; def err_invalid_declarator_scope : Error< "definition or redeclaration of %0 not in a namespace enclosing %1">; @@ -1429,6 +1724,13 @@ def err_invalid_declarator_in_function : Error< def err_not_tag_in_scope : Error< "%0 does not name a tag member in the specified scope">; +def err_cannot_form_pointer_to_member_of_reference_type : Error< + "cannot form a pointer-to-member to member %0 of reference type %1">; + +def warn_condition_is_assignment : Warning<"using the result of an " + "assignment as a condition without parentheses">, + InGroup<Parentheses>; + def warn_value_always_zero : Warning<"%0 is always zero in this context">; def warn_value_always_false : Warning<"%0 is always false in this context">; @@ -1436,6 +1738,8 @@ def warn_value_always_false : Warning<"%0 is always false in this context">; // FIXME: %2 is an english string here. def err_typecheck_convert_incompatible : Error< "incompatible type %2 %1, expected %0">; +def err_typecheck_convert_ambiguous : Error< + "ambiguity in initializing value of type %0 with initializer of type %1">; def err_cannot_initialize_decl_noname : Error< "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 " "of type %2">; @@ -1443,8 +1747,6 @@ def err_cannot_initialize_decl : Error< "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">; def warn_incompatible_qualified_id : Warning< "incompatible type %2 %1, expected %0">; -def warn_incompatible_qualified_id_operands : Warning< - "invalid operands to binary expression (%0 and %1)">; def ext_typecheck_convert_pointer_int : ExtWarn< "incompatible pointer to integer conversion %2 %1, expected %0">; def ext_typecheck_convert_int_pointer : ExtWarn< @@ -1486,7 +1788,11 @@ def err_block_decl_ref_not_modifiable_lvalue : Error< def err_typecheck_call_not_function : Error< "called object type %0 is not a function or function pointer">; def err_call_incomplete_return : Error< - "return type of called function (%0) is incomplete">; + "calling function with incomplete return type %0">; +def err_call_function_incomplete_return : Error< + "calling %0 with incomplete return type %1">; +def note_function_with_incomplete_return_type_declared_here : Note< + "%0 declared here">; def err_call_incomplete_argument : Error< "argument type %0 is incomplete">; def err_typecheck_call_too_few_args : Error< @@ -1513,12 +1819,13 @@ def err_cannot_pass_objc_interface_to_vararg : Error< def warn_cannot_pass_non_pod_arg_to_vararg : Warning< "cannot pass object of non-POD type %0 through variadic " - "%select{function|block|method}1; call will abort at runtime">; + "%select{function|block|method|constructor}1; call will abort at runtime">; -def err_typecheck_closure_too_many_args : Error< - "too many arguments to closure call">; def err_typecheck_call_invalid_ordered_compare : Error< "ordered compare requires two args of floating point type (%0 and %1)">; +def err_typecheck_call_invalid_unary_fp : Error< + "floating point classification requires argument of floating point type " + "(passed in %0)">; def err_typecheck_cond_expect_scalar : Error< "used type %0 where arithmetic or pointer type is required">; def ext_typecheck_cond_one_void : Extension< @@ -1548,7 +1855,16 @@ def ext_typecheck_expression_not_constant_but_accepted : Extension< "expression is not a constant, but is accepted as one by GNU extensions">; def warn_unused_expr : Warning<"expression result unused">, InGroup<UnusedValue>; +def warn_unused_property_expr : Warning< + "property access result unused - getters should not have side effects">, + InGroup<UnusedValue>; +def warn_unused_call : Warning< + "ignoring return value of function declared with %0 attribute">, + InGroup<UnusedValue>; +def err_incomplete_type_used_in_type_trait_expr : Error< + "incomplete type %0 used in type trait expression">; + // inline asm. def err_asm_wide_character : Error<"wide string is invalid in 'asm'">; def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; @@ -1606,6 +1922,17 @@ def error_multiple_base_initialization : Error < def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; +def err_mem_initializer_mismatch : Error< + "Too many arguments for member initializer %0">; + +def warn_field_initialized : Warning< + "member '%0' will be initialized after">, + InGroup<Reorder>, DefaultIgnore; +def warn_base_initialized : Warning< + "base class %0 will be initialized after">, + InGroup<Reorder>, DefaultIgnore; +def note_fieldorbase_initialized_here : Note< + "%select{field|base}0 %1">; def err_base_init_does_not_name_class : Error< "constructor initializer %0 does not name a class">; @@ -1690,6 +2017,10 @@ def err_ambiguous_member_multiple_subobject_types : Error< def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; +def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a " + "declaration in a different namespace">; +def note_hidden_tag : Note<"type declaration hidden">; +def note_hiding_object : Note<"declaration hides type">; // C++ operator overloading def err_operator_overload_needs_class_or_enum : Error< @@ -1850,6 +2181,9 @@ def ext_return_has_void_expr : Extension< def warn_noreturn_function_has_return_expr : Warning< "function %0 declared 'noreturn' should not return">, DefaultError, InGroup<DiagGroup<"invalid-noreturn">>; +def warn_falloff_noreturn_function : Warning< + "function declared 'noreturn' should not return">, + InGroup<DiagGroup<"invalid-noreturn">>; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; def err_block_on_nonlocal : Error< @@ -1867,6 +2201,9 @@ def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; +def err_vector_incorrect_num_initializers : Error< + "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; +def err_altivec_empty_initializer : Error<"expected initializer">; def err_stack_const_level : Error< "level argument for a stack address builtin must be constant">; @@ -1918,10 +2255,11 @@ def err_objc_array_of_interfaces : Error< "array of interface %0 is invalid (probably should be an array of pointers)">; def ext_c99_array_usage : Extension< "use of C99-specific array features, accepted as an extension">; +def err_c99_array_usage_cxx : Error< + "C99-specific array features are not permitted in C++">; + def err_invalid_protocol_qualifiers : Error< "invalid protocol qualifiers on non-ObjC type">; -def err_qualified_class_unsupported : Error< - "protocol qualified 'Class' is unsupported">; def warn_ivar_use_hidden : Warning< "local declaration of %0 hides instance variable">; def error_ivar_use_in_class_method : Error< @@ -1933,6 +2271,7 @@ def error_protected_ivar_access : Error<"instance variable %0 is protected">, def warn_maynot_respond : Warning<"%0 may not respond to %1">; def warn_attribute_method_def : Warning< "method attribute can only be specified on method declarations">; - - +def ext_typecheck_base_super : Warning< + "method parameter type %0 does not match " + "super class method parameter type %1">, InGroup<SuperSubClassMismatch>, DefaultIgnore; } diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index d6a0cf34d9fa..7c9113c497ef 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -15,19 +15,17 @@ #define LLVM_CLANG_FILEMANAGER_H #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Allocator.h" #include "llvm/Config/config.h" // for mode_t -#include <map> -#include <set> -#include <string> // FIXME: Enhance libsystem to support inode and other fields in stat. #include <sys/types.h> #include <sys/stat.h> namespace clang { class FileManager; - + /// DirectoryEntry - Cached information about one directory on the disk. /// class DirectoryEntry { @@ -35,7 +33,7 @@ class DirectoryEntry { friend class FileManager; public: DirectoryEntry() : Name(0) {} - const char *getName() const { return Name; } + const char *getName() const { return Name; } }; /// FileEntry - Cached information about one file on the disk. @@ -55,7 +53,7 @@ public: : Name(0), Device(device), Inode(inode), FileMode(m) {} // Add a default constructor for use with llvm::StringMap FileEntry() : Name(0), Device(0), Inode(0), FileMode(0) {} - + const char *getName() const { return Name; } off_t getSize() const { return Size; } unsigned getUID() const { return UID; } @@ -63,11 +61,11 @@ public: dev_t getDevice() const { return Device; } time_t getModificationTime() const { return ModTime; } mode_t getFileMode() const { return FileMode; } - + /// getDir - Return the directory the file lives in. /// const DirectoryEntry *getDir() const { return Dir; } - + bool operator<(const FileEntry& RHS) const { return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode); } @@ -87,19 +85,19 @@ public: /// execution of the front end. class MemorizeStatCalls : public StatSysCallCache { public: - /// \brief The result of a stat() call. + /// \brief The result of a stat() call. /// /// The first member is the result of calling stat(). If stat() /// found something, the second member is a copy of the stat /// structure. typedef std::pair<int, struct stat> StatResult; - /// \brief The set of stat() calls that have been + /// \brief The set of stat() calls that have been llvm::StringMap<StatResult, llvm::BumpPtrAllocator> StatCalls; typedef llvm::StringMap<StatResult, llvm::BumpPtrAllocator>::const_iterator iterator; - + iterator begin() const { return StatCalls.begin(); } iterator end() const { return StatCalls.end(); } @@ -126,22 +124,22 @@ class FileManager { /// llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries; llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries; - + /// NextFileUID - Each FileEntry we create is assigned a unique ID #. /// unsigned NextFileUID; - + // Statistics. unsigned NumDirLookups, NumFileLookups; unsigned NumDirCacheMisses, NumFileCacheMisses; - + // Caching. llvm::OwningPtr<StatSysCallCache> StatCache; int stat_cached(const char* path, struct stat* buf) { return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf); } - + public: FileManager(); ~FileManager(); @@ -152,24 +150,24 @@ public: void setStatCache(StatSysCallCache *statCache) { StatCache.reset(statCache); } - + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. - /// - const DirectoryEntry *getDirectory(const std::string &Filename) { - return getDirectory(&Filename[0], &Filename[0] + Filename.size()); + /// + const DirectoryEntry *getDirectory(const llvm::StringRef &Filename) { + return getDirectory(Filename.begin(), Filename.end()); } const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd); - + /// getFile - Lookup, cache, and verify the specified file. This returns null /// if the file doesn't exist. - /// - const FileEntry *getFile(const std::string &Filename) { - return getFile(&Filename[0], &Filename[0] + Filename.size()); + /// + const FileEntry *getFile(const llvm::StringRef &Filename) { + return getFile(Filename.begin(), Filename.end()); } const FileEntry *getFile(const char *FilenameStart, const char *FilenameEnd); - + void PrintStats() const; }; diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 57cd31163144..84c2fc910d11 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -21,8 +21,8 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PointerLikeTypeTraits.h" -#include <string> -#include <cassert> +#include <string> +#include <cassert> namespace llvm { template <typename T> struct DenseMapInfo; @@ -38,21 +38,21 @@ namespace clang { /// IdentifierLocPair - A simple pair of identifier info and location. typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair; - - + + /// IdentifierInfo - One of these records is kept for each identifier that /// is lexed. This contains information about whether the token was #define'd, /// is a language keyword, or if it is a front-end token of some sort (e.g. a /// variable or function name). The preprocessor keeps this information in a -/// set, and all tok::identifier tokens have a pointer to one of these. +/// set, and all tok::identifier tokens have a pointer to one of these. class IdentifierInfo { // Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a // signed char and TokenKinds > 127 won't be handled correctly. - unsigned TokenID : 8; // Front-end token ID or tok::identifier. + unsigned TokenID : 8; // Front-end token ID or tok::identifier. // Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf). // First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values // are for builtins. - unsigned ObjCOrBuiltinID :10; + unsigned ObjCOrBuiltinID :10; bool HasMacro : 1; // True if there is a #define for this. bool IsExtension : 1; // True if identifier is a lang extension. bool IsPoisoned : 1; // True if identifier is poisoned. @@ -61,50 +61,50 @@ class IdentifierInfo { // 9 bits left in 32-bit word. void *FETokenInfo; // Managed by the language front-end. llvm::StringMapEntry<IdentifierInfo*> *Entry; - + IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE. void operator=(const IdentifierInfo&); // NONASSIGNABLE. - friend class IdentifierTable; + friend class IdentifierTable; public: IdentifierInfo(); - + /// isStr - Return true if this is the identifier for the specified string. /// This is intended to be used for string literals only: II->isStr("foo"). template <std::size_t StrLen> bool isStr(const char (&Str)[StrLen]) const { return getLength() == StrLen-1 && !memcmp(getName(), Str, StrLen-1); } - - /// getName - Return the actual string for this identifier. The returned + + /// getName - Return the actual string for this identifier. The returned /// string is properly null terminated. /// - const char *getName() const { + const char *getName() const { if (Entry) return Entry->getKeyData(); // FIXME: This is gross. It would be best not to embed specific details // of the PTH file format here. - // The 'this' pointer really points to a + // The 'this' pointer really points to a // std::pair<IdentifierInfo, const char*>, where internal pointer // points to the external string data. return ((std::pair<IdentifierInfo, const char*>*) this)->second; } - + /// getLength - Efficiently return the length of this identifier info. /// unsigned getLength() const { if (Entry) return Entry->getKeyLength(); // FIXME: This is gross. It would be best not to embed specific details // of the PTH file format here. - // The 'this' pointer really points to a + // The 'this' pointer really points to a // std::pair<IdentifierInfo, const char*>, where internal pointer // points to the external string data. const char* p = ((std::pair<IdentifierInfo, const char*>*) this)->second-2; return (((unsigned) p[0]) | (((unsigned) p[1]) << 8)) - 1; } - + /// hasMacroDefinition - Return true if this identifier is #defined to some /// other value. bool hasMacroDefinition() const { @@ -112,29 +112,29 @@ public: } void setHasMacroDefinition(bool Val) { if (HasMacro == Val) return; - + HasMacro = Val; if (Val) NeedsHandleIdentifier = 1; else RecomputeNeedsHandleIdentifier(); } - + /// get/setTokenID - If this is a source-language token (e.g. 'for'), this API /// can be used to cause the lexer to map identifiers to source-language /// tokens. tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; } void setTokenID(tok::TokenKind ID) { TokenID = ID; } - + /// getPPKeywordID - Return the preprocessor keyword ID for this identifier. /// For example, "define" will return tok::pp_define. tok::PPKeywordKind getPPKeywordID() const; - + /// getObjCKeywordID - Return the Objective-C keyword ID for the this /// identifier. For example, 'class' will return tok::objc_class if ObjC is /// enabled. tok::ObjCKeywordKind getObjCKeywordID() const { - if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS) + if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS) return tok::ObjCKeywordKind(ObjCOrBuiltinID); else return tok::objc_not_keyword; @@ -144,15 +144,15 @@ public: /// getBuiltinID - Return a value indicating whether this is a builtin /// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target. /// 2+ are specific builtin functions. - unsigned getBuiltinID() const { + unsigned getBuiltinID() const { if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS) - return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; + return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; else return 0; } void setBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS; - assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID + assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID && "ID too large for field!"); } @@ -170,7 +170,7 @@ public: else RecomputeNeedsHandleIdentifier(); } - + /// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the /// Preprocessor will emit an error every time this token is used. void setIsPoisoned(bool Value = true) { @@ -180,10 +180,10 @@ public: else RecomputeNeedsHandleIdentifier(); } - + /// isPoisoned - Return true if this token has been poisoned. bool isPoisoned() const { return IsPoisoned; } - + /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether /// this identifier is a C++ alternate representation of an operator. void setIsCPlusPlusOperatorKeyword(bool Val = true) { @@ -205,7 +205,7 @@ public: /// must be called on a token of this identifier. If this returns false, we /// know that HandleIdentifier will not affect the token. bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; } - + private: /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does /// several special (but rare) things to identifiers of various sorts. For @@ -227,13 +227,13 @@ private: class IdentifierInfoLookup { public: virtual ~IdentifierInfoLookup(); - + /// get - Return the identifier token info for the specified named identifier. /// Unlike the version in IdentifierTable, this returns a pointer instead /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0; -}; +}; /// \brief An abstract class used to resolve numerical identifier /// references (meaningful only to some external source) into @@ -257,7 +257,7 @@ class IdentifierTable { // BumpPtrAllocator! typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy; HashTableTy HashTable; - + IdentifierInfoLookup* ExternalLookup; public: @@ -265,7 +265,7 @@ public: /// info about the language keywords for the language specified by LangOpts. IdentifierTable(const LangOptions &LangOpts, IdentifierInfoLookup* externalLookup = 0); - + /// \brief Set the external identifier lookup mechanism. void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) { ExternalLookup = IILookup; @@ -274,16 +274,16 @@ public: llvm::BumpPtrAllocator& getAllocator() { return HashTable.getAllocator(); } - + /// get - Return the identifier token info for the specified named identifier. /// IdentifierInfo &get(const char *NameStart, const char *NameEnd) { llvm::StringMapEntry<IdentifierInfo*> &Entry = HashTable.GetOrCreateValue(NameStart, NameEnd); - + IdentifierInfo *II = Entry.getValue(); if (II) return *II; - + // No entry; if we have an external lookup, look there first. if (ExternalLookup) { II = ExternalLookup->get(NameStart, NameEnd); @@ -305,7 +305,7 @@ public: return *II; } - + /// \brief Creates a new IdentifierInfo from the given string. /// /// This is a lower-level version of get() that requires that this @@ -314,14 +314,14 @@ public: /// identifier sources can use this routine to build IdentifierInfo /// nodes and then introduce additional information about those /// identifiers. - IdentifierInfo &CreateIdentifierInfo(const char *NameStart, + IdentifierInfo &CreateIdentifierInfo(const char *NameStart, const char *NameEnd) { llvm::StringMapEntry<IdentifierInfo*> &Entry = HashTable.GetOrCreateValue(NameStart, NameEnd); - + IdentifierInfo *II = Entry.getValue(); assert(!II && "IdentifierInfo already exists"); - + // Lookups failed, make a new IdentifierInfo. void *Mem = getAllocator().Allocate<IdentifierInfo>(); II = new (Mem) IdentifierInfo(); @@ -334,37 +334,32 @@ public: return *II; } - IdentifierInfo &get(const char *Name) { - return get(Name, Name+strlen(Name)); - } - IdentifierInfo &get(const std::string &Name) { - // Don't use c_str() here: no need to be null terminated. - const char *NameBytes = Name.data(); - return get(NameBytes, NameBytes+Name.size()); + IdentifierInfo &get(const llvm::StringRef& Name) { + return get(Name.begin(), Name.end()); } typedef HashTableTy::const_iterator iterator; typedef HashTableTy::const_iterator const_iterator; - + iterator begin() const { return HashTable.begin(); } iterator end() const { return HashTable.end(); } unsigned size() const { return HashTable.size(); } - + /// PrintStats - Print some statistics to stderr that indicate how well the /// hashing is doing. void PrintStats() const; - + void AddKeywords(const LangOptions &LangOpts); }; /// Selector - This smart pointer class efficiently represents Objective-C /// method names. This class will either point to an IdentifierInfo or a /// MultiKeywordSelector (which is private). This enables us to optimize -/// selectors that take no arguments and selectors that take 1 argument, which +/// selectors that take no arguments and selectors that take 1 argument, which /// accounts for 78% of all selectors in Cocoa.h. class Selector { friend class DiagnosticInfo; - + enum IdentifierInfoFlag { // MultiKeywordSelector = 0. ZeroArg = 0x1, @@ -372,7 +367,7 @@ class Selector { ArgFlags = ZeroArg|OneArg }; uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. - + Selector(IdentifierInfo *II, unsigned nArgs) { InfoPtr = reinterpret_cast<uintptr_t>(II); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); @@ -383,7 +378,7 @@ class Selector { InfoPtr = reinterpret_cast<uintptr_t>(SI); assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); } - + IdentifierInfo *getAsIdentifierInfo() const { if (getIdentifierInfoFlag()) return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags); @@ -417,19 +412,19 @@ public: bool isNull() const { return InfoPtr == 0; } // Predicates to identify the selector type. - bool isKeywordSelector() const { - return getIdentifierInfoFlag() != ZeroArg; + bool isKeywordSelector() const { + return getIdentifierInfoFlag() != ZeroArg; } - bool isUnarySelector() const { + bool isUnarySelector() const { return getIdentifierInfoFlag() == ZeroArg; } unsigned getNumArgs() const; IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; - + /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return /// it as an std::string. std::string getAsString() const; - + static Selector getEmptyMarker() { return Selector(uintptr_t(-1)); } @@ -452,7 +447,7 @@ public: /// whether this is a no argument selector "foo", a single argument selector /// "foo:" or multi-argument "foo:bar:". Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); - + Selector getUnarySelector(IdentifierInfo *ID) { return Selector(ID, 1); } @@ -519,15 +514,15 @@ struct DenseMapInfo<clang::Selector> { return clang::Selector::getEmptyMarker(); } static inline clang::Selector getTombstoneKey() { - return clang::Selector::getTombstoneMarker(); + return clang::Selector::getTombstoneMarker(); } - + static unsigned getHashValue(clang::Selector S); - + static bool isEqual(clang::Selector LHS, clang::Selector RHS) { return LHS == RHS; } - + static bool isPod() { return true; } }; @@ -537,7 +532,7 @@ template<> class PointerLikeTypeTraits<clang::IdentifierInfo*> { public: static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { - return P; + return P; } static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { return static_cast<clang::IdentifierInfo*>(P); @@ -549,7 +544,7 @@ template<> class PointerLikeTypeTraits<const clang::IdentifierInfo*> { public: static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { - return P; + return P; } static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) { return static_cast<const clang::IdentifierInfo*>(P); diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 26688bf56728..d4d3fe50eba0 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -34,18 +34,17 @@ public: unsigned CPlusPlus : 1; // C++ Support unsigned CPlusPlus0x : 1; // C++0x Support unsigned CXXOperatorNames : 1; // Treat C++ operator names as keywords. - + unsigned ObjC1 : 1; // Objective-C 1 support enabled. unsigned ObjC2 : 1; // Objective-C 2 support enabled. - unsigned ObjCSenderDispatch: 1; // Objective-C 2 three-dimensional dispatch - // enabled. unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled - + 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 Rtti : 1; // Support rtti information. unsigned NeXTRuntime : 1; // Use NeXT runtime. unsigned Freestanding : 1; // Freestanding implementation @@ -53,6 +52,8 @@ public: unsigned ThreadsafeStatics : 1; // Whether static initializers are protected // by locks. + unsigned POSIXThreads : 1; // Compiling with POSIX thread support + // (-pthread) unsigned Blocks : 1; // block extension to C unsigned EmitAllDecls : 1; // Emit all declarations, even if // they are unused. @@ -66,7 +67,7 @@ public: // may be ripped out at any time. unsigned Optimize : 1; // Whether __OPTIMIZE__ should be defined. - unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be + unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be // defined. unsigned Static : 1; // Should __STATIC__ be defined (as // opposed to __DYNAMIC__). @@ -79,12 +80,14 @@ public: unsigned ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout // for __weak/__strong ivars. - unsigned AccessControl : 1; // Whether C++ access control should + 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. + unsigned ElideConstructors : 1; // Whether C++ copy constructors should be + // elided if possible. private: unsigned GC : 2; // Objective-C Garbage Collection modes. We // declare this enum as unsigned because MSVC @@ -101,46 +104,51 @@ private: /// the original input file, for example with -save-temps. const char *MainFileName; -public: +public: unsigned InstantiationDepth; // Maximum template instantiation depth. + const char *ObjCConstantStringClass; + enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPReq }; - enum VisibilityMode { - Default, - Protected, + enum VisibilityMode { + Default, + Protected, Hidden }; - + LangOptions() { Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; GNUMode = ImplicitInt = Digraphs = 0; HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0; + ObjCConstantStringClass = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = 0; Exceptions = NeXTRuntime = Freestanding = NoBuiltin = 0; + Rtti = 1; LaxVectorConversions = 1; HeinousExtensions = 0; AltiVec = OpenCL = StackProtector = 0; - + SymbolVisibility = (unsigned) Default; - + // FIXME: The default should be 1. ThreadsafeStatics = 0; + POSIXThreads = 0; Blocks = 0; EmitAllDecls = 0; MathErrno = 1; // FIXME: The default should be 1. AccessControl = 0; - + ElideConstructors = 1; + OverflowChecking = 0; ObjCGCBitmapPrint = 0; - ObjCSenderDispatch = 0; InstantiationDepth = 99; - + Optimize = 0; OptimizeSize = 0; @@ -154,7 +162,7 @@ public: MainFileName = 0; } - + GCMode getGCMode() const { return (GCMode) GC; } void setGCMode(GCMode m) { GC = (unsigned) m; } @@ -168,8 +176,8 @@ public: const char *getMainFileName() const { return MainFileName; } void setMainFileName(const char *Name) { MainFileName = Name; } - VisibilityMode getVisibilityMode() const { - return (VisibilityMode) SymbolVisibility; + VisibilityMode getVisibilityMode() const { + return (VisibilityMode) SymbolVisibility; } void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; } }; diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile index b08d61457b75..6ed5fefb7e64 100644 --- a/include/clang/Basic/Makefile +++ b/include/clang/Basic/Makefile @@ -9,12 +9,12 @@ TABLEGEN_INC_FILES_COMMON = 1 include $(LEVEL)/Makefile.common -$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td DiagnosticGroups.td Diagnostic%Kinds.td $(TBLGEN) +$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(TBLGEN) $(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen" $(Verb) -$(MKDIR) $(@D) $(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $< -$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td $(wildcard Diagnostic*.td) $(TBLGEN) +$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(wildcard Diagnostic*.td) $(TBLGEN) $(Echo) "Building Clang diagnostic groups with tblgen" $(Verb) -$(MKDIR) $(@D) $(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $< diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index f54d67042c47..65245167d8d5 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -29,7 +29,7 @@ namespace clang { // This is basically copy-and-paste from StringMap. This likely won't // stay here, which is why I didn't both to expose this function from // String Map. -inline unsigned BernsteinHash(const char* x) { +inline unsigned BernsteinHash(const char* x) { unsigned int R = 0; for ( ; *x != '\0' ; ++x) R = R * 33 + *x; return R + (R >> 5); @@ -131,29 +131,29 @@ class OnDiskChainedHashTableGenerator { unsigned NumBuckets; unsigned NumEntries; llvm::BumpPtrAllocator BA; - + class Item { public: typename Info::key_type key; typename Info::data_type data; Item *next; const uint32_t hash; - + Item(typename Info::key_type_ref k, typename Info::data_type_ref d) : key(k), data(d), next(0), hash(Info::ComputeHash(k)) {} }; - - class Bucket { + + class Bucket { public: io::Offset off; Item* head; unsigned length; - + Bucket() {} }; - + Bucket* Buckets; - + private: void insert(Bucket* b, size_t size, Item* E) { unsigned idx = E->hash & (size - 1); @@ -162,7 +162,7 @@ private: ++B.length; B.head = E; } - + void resize(size_t newsize) { Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket)); // Populate newBuckets with the old entries. @@ -173,14 +173,14 @@ private: insert(newBuckets, newsize, E); E = N; } - + free(Buckets); NumBuckets = newsize; Buckets = newBuckets; - } - + } + public: - + void insert(typename Info::key_type_ref key, typename Info::data_type_ref data) { @@ -188,7 +188,7 @@ public: if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2); insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data)); } - + io::Offset Emit(llvm::raw_ostream &out) { Info InfoObj; return Emit(out, InfoObj); @@ -201,42 +201,42 @@ public: for (unsigned i = 0; i < NumBuckets; ++i) { Bucket& B = Buckets[i]; if (!B.head) continue; - + // Store the offset for the data of this bucket. B.off = out.tell(); assert(B.off && "Cannot write a bucket at offset 0. Please add padding."); // Write out the number of items in the bucket. Emit16(out, B.length); - + // Write out the entries in the bucket. for (Item *I = B.head; I ; I = I->next) { Emit32(out, I->hash); - const std::pair<unsigned, unsigned>& Len = + const std::pair<unsigned, unsigned>& Len = InfoObj.EmitKeyDataLength(out, I->key, I->data); InfoObj.EmitKey(out, I->key, Len.first); InfoObj.EmitData(out, I->key, I->data, Len.second); } } - + // Emit the hashtable itself. Pad(out, 4); io::Offset TableOff = out.tell(); Emit32(out, NumBuckets); Emit32(out, NumEntries); for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off); - + return TableOff; } - + OnDiskChainedHashTableGenerator() { NumEntries = 0; - NumBuckets = 64; + NumBuckets = 64; // Note that we do not need to run the constructors of the individual // Bucket objects since 'calloc' returns bytes that are all 0. Buckets = (Bucket*) std::calloc(NumBuckets, sizeof(Bucket)); } - + ~OnDiskChainedHashTableGenerator() { std::free(Buckets); } @@ -254,7 +254,7 @@ public: typedef typename Info::internal_key_type internal_key_type; typedef typename Info::external_key_type external_key_type; typedef typename Info::data_type data_type; - + OnDiskChainedHashTable(unsigned numBuckets, unsigned numEntries, const unsigned char* buckets, const unsigned char* base, @@ -271,7 +271,7 @@ public: const unsigned char* getBuckets() const { return Buckets; } bool isEmpty() const { return NumEntries == 0; } - + class iterator { internal_key_type key; const unsigned char* const data; @@ -282,12 +282,12 @@ public: iterator(const internal_key_type k, const unsigned char* d, unsigned l, Info *InfoObj) : key(k), data(d), len(l), InfoObj(InfoObj) {} - - data_type operator*() const { return InfoObj->ReadData(key, data, len); } - bool operator==(const iterator& X) const { return X.data == data; } + + data_type operator*() const { return InfoObj->ReadData(key, data, len); } + bool operator==(const iterator& X) const { return X.data == data; } bool operator!=(const iterator& X) const { return X.data != data; } - }; - + }; + iterator find(const external_key_type& eKey, Info *InfoPtr = 0) { if (!InfoPtr) InfoPtr = &InfoObj; @@ -295,25 +295,25 @@ public: using namespace io; const internal_key_type& iKey = Info::GetInternalKey(eKey); unsigned key_hash = Info::ComputeHash(iKey); - + // Each bucket is just a 32-bit offset into the hash table file. unsigned idx = key_hash & (NumBuckets - 1); const unsigned char* Bucket = Buckets + sizeof(uint32_t)*idx; - + unsigned offset = ReadLE32(Bucket); if (offset == 0) return iterator(); // Empty bucket. const unsigned char* Items = Base + offset; - + // 'Items' starts with a 16-bit unsigned integer representing the // number of items in this bucket. unsigned len = ReadUnalignedLE16(Items); - + for (unsigned i = 0; i < len; ++i) { // Read the hash. uint32_t item_hash = ReadUnalignedLE32(Items); - + // Determine the length of the key and the data. - const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items); + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items); unsigned item_len = L.first + L.second; // Compare the hashes. If they are not the same, skip the entry entirely. @@ -321,7 +321,7 @@ public: Items += item_len; continue; } - + // Read the key. const internal_key_type& X = InfoPtr->ReadKey((const unsigned char* const) Items, L.first); @@ -331,17 +331,17 @@ public: Items += item_len; continue; } - + // The key matches! return iterator(X, Items + L.first, L.second, InfoPtr); } - + return iterator(); } - + iterator end() const { return iterator(); } - - + + static OnDiskChainedHashTable* Create(const unsigned char* buckets, const unsigned char* const base, const Info &InfoObj = Info()) { @@ -349,14 +349,14 @@ public: assert(buckets > base); assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 && "buckets should be 4-byte aligned."); - + unsigned numBuckets = ReadLE32(buckets); unsigned numEntries = ReadLE32(buckets); return new OnDiskChainedHashTable<Info>(numBuckets, numEntries, buckets, base, InfoObj); - } + } }; } // end namespace clang -#endif +#endif diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h new file mode 100644 index 000000000000..e8cc564c8a20 --- /dev/null +++ b/include/clang/Basic/PartialDiagnostic.h @@ -0,0 +1,155 @@ +//===--- PartialDiagnostic.h - Diagnostic "closures" ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a partial diagnostic that can be emitted anwyhere +// in a DiagnosticBuilder stream. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H +#define LLVM_CLANG_PARTIALDIAGNOSTIC_H + +#include "clang/AST/Type.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { + +class DeclarationName; + +class PartialDiagnostic { + struct Storage { + Storage() : NumDiagArgs(0), NumDiagRanges(0) { } + + enum { + /// MaxArguments - The maximum number of arguments we can hold. We + /// currently only support up to 10 arguments (%0-%9). + /// A single diagnostic with more than that almost certainly has to + /// be simplified anyway. + MaxArguments = 10 + }; + + /// NumDiagArgs - This contains the number of entries in Arguments. + unsigned char NumDiagArgs; + + /// NumDiagRanges - This is the number of ranges in the DiagRanges array. + unsigned char NumDiagRanges; + + /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum + /// values, with one for each argument. This specifies whether the argument + /// is in DiagArgumentsStr or in DiagArguments. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// DiagArgumentsVal - The values for the various substitution positions. + /// This is used when the argument is not an std::string. The specific value + /// is mangled into an intptr_t and the intepretation depends on exactly + /// what sort of argument kind it is. + mutable intptr_t DiagArgumentsVal[MaxArguments]; + + /// DiagRanges - The list of ranges added to this diagnostic. It currently + /// only support 10 ranges, could easily be extended if needed. + mutable const SourceRange *DiagRanges[10]; + }; + + /// DiagID - The diagnostic ID. + mutable unsigned DiagID; + + /// DiagStorare - Storge for args and ranges. + mutable Storage *DiagStorage; + + void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { + if (!DiagStorage) + DiagStorage = new Storage; + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; + DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; + } + + void AddSourceRange(const SourceRange &R) const { + if (!DiagStorage) + DiagStorage = new Storage; + + assert(DiagStorage->NumDiagRanges < + llvm::array_lengthof(DiagStorage->DiagRanges) && + "Too many arguments to diagnostic!"); + DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = &R; + } + + void operator=(const PartialDiagnostic &); // DO NOT IMPLEMENT + +public: + PartialDiagnostic(unsigned DiagID) + : DiagID(DiagID), DiagStorage(0) { } + + PartialDiagnostic(const PartialDiagnostic &Other) + : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage) { + Other.DiagID = 0; + Other.DiagStorage = 0; + } + + ~PartialDiagnostic() { + delete DiagStorage; + } + + unsigned getDiagID() const { return DiagID; } + + void Emit(const DiagnosticBuilder &DB) const { + if (!DiagStorage) + return; + + // Add all arguments. + for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { + DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], + (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); + } + + // Add all ranges. + for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) + DB.AddSourceRange(*DiagStorage->DiagRanges[i]); + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + QualType T) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + Diagnostic::ak_qualtype); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + unsigned I) { + PD.AddTaggedVal(I, Diagnostic::ak_uint); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const SourceRange &R) { + PD.AddSourceRange(R); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + DeclarationName N); +}; + +inline PartialDiagnostic PDiag(unsigned DiagID = 0) { + return PartialDiagnostic(DiagID); +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PartialDiagnostic &PD) { + PD.Emit(DB); + return DB; +} + + +} // end namespace clang +#endif diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 2405c2fe7db7..28cf2db9bc25 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -24,10 +24,10 @@ namespace llvm { } namespace clang { - + class SourceManager; class FileEntry; - + /// FileID - This is an opaque identifier used by SourceManager which refers to /// a source file (MemoryBuffer) along with its #include path and #line data. /// @@ -36,19 +36,19 @@ class FileID { unsigned ID; public: FileID() : ID(0) {} - + bool isInvalid() const { return ID == 0; } - + bool operator==(const FileID &RHS) const { return ID == RHS.ID; } bool operator<(const FileID &RHS) const { return ID < RHS.ID; } bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } bool operator!=(const FileID &RHS) const { return !(*this == RHS); } bool operator>(const FileID &RHS) const { return RHS < *this; } bool operator>=(const FileID &RHS) const { return RHS <= *this; } - + static FileID getSentinel() { return get(~0U); } unsigned getHashValue() const { return ID; } - + private: friend class SourceManager; static FileID get(unsigned V) { @@ -58,8 +58,8 @@ private: } unsigned getOpaqueValue() const { return ID; } }; - - + + /// SourceLocation - This is a carefully crafted 32-bit identifier that encodes /// a full include stack, line and column number information for a position in /// an input translation unit. @@ -72,17 +72,17 @@ class SourceLocation { public: SourceLocation() : ID(0) {} // 0 is an invalid FileID. - + bool isFileID() const { return (ID & MacroIDBit) == 0; } bool isMacroID() const { return (ID & MacroIDBit) != 0; } - + /// isValid - Return true if this is a valid SourceLocation object. Invalid /// SourceLocations are often used when events have no corresponding location /// in the source (e.g. a diagnostic is required for a command line option). /// bool isValid() const { return ID != 0; } bool isInvalid() const { return ID == 0; } - + private: /// getOffset - Return the index for SourceManager's SLocEntryTable table, /// note that this is not an index *into* it though. @@ -96,7 +96,7 @@ private: L.ID = ID; return L; } - + static SourceLocation getMacroLoc(unsigned ID) { assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); SourceLocation L; @@ -104,7 +104,7 @@ private: return L; } public: - + /// getFileLocWithOffset - Return a source location with the specified offset /// from this file SourceLocation. SourceLocation getFileLocWithOffset(int Offset) const { @@ -113,14 +113,14 @@ public: L.ID = ID+Offset; return L; } - + /// getRawEncoding - When a SourceLocation itself cannot be used, this returns /// an (opaque) 32-bit integer encoding for it. This should only be passed /// to SourceLocation::getFromRawEncoding, it should not be inspected /// directly. unsigned getRawEncoding() const { return ID; } - - + + /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into /// a real SourceLocation. static SourceLocation getFromRawEncoding(unsigned Encoding) { @@ -128,7 +128,7 @@ public: X.ID = Encoding; return X; } - + void print(llvm::raw_ostream &OS, const SourceManager &SM) const; void dump(const SourceManager &SM) const; }; @@ -140,7 +140,7 @@ inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { return !(LHS == RHS); } - + inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { return LHS.getRawEncoding() < RHS.getRawEncoding(); } @@ -153,24 +153,24 @@ public: SourceRange(): B(SourceLocation()), E(SourceLocation()) {} SourceRange(SourceLocation loc) : B(loc), E(loc) {} SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} - + SourceLocation getBegin() const { return B; } SourceLocation getEnd() const { return E; } - + void setBegin(SourceLocation b) { B = b; } void setEnd(SourceLocation e) { E = e; } - + bool isValid() const { return B.isValid() && E.isValid(); } - + bool operator==(const SourceRange &X) const { return B == X.B && E == X.E; } - + bool operator!=(const SourceRange &X) const { return B != X.B || E != X.E; } }; - + /// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful /// for argument passing to functions that expect both objects. class FullSourceLoc : public SourceLocation { @@ -179,21 +179,21 @@ public: /// Creates a FullSourceLoc where isValid() returns false. explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {} - explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM) + explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} - + SourceManager &getManager() { assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; } - + const SourceManager &getManager() const { assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; } - + FileID getFileID() const; - + FullSourceLoc getInstantiationLoc() const; FullSourceLoc getSpellingLoc() const; @@ -204,37 +204,37 @@ public: unsigned getSpellingColumnNumber() const; const char *getCharacterData() const; - + const llvm::MemoryBuffer* getBuffer() const; - + /// getBufferData - Return a pointer to the start and end of the source buffer /// data for the specified FileID. std::pair<const char*, const char*> getBufferData() const; - + /// getDecomposedLoc - Decompose the specified location into a raw FileID + /// Offset pair. The first element is the FileID, the second is the /// offset from the start of the buffer of the location. std::pair<FileID, unsigned> getDecomposedLoc() const; bool isInSystemHeader() const; - + /// Prints information about this FullSourceLoc to stderr. Useful for /// debugging. void dump() const { SourceLocation::dump(*SrcMgr); } - friend inline bool + friend inline bool operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { return LHS.getRawEncoding() == RHS.getRawEncoding() && LHS.SrcMgr == RHS.SrcMgr; } - friend inline bool + friend inline bool operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { return !(LHS == RHS); } }; - + /// PresumedLoc - This class represents an unpacked "presumed" location which /// can be presented to the user. A 'presumed' location can be modified by /// #line and GNU line marker directives and is always the instantiation point @@ -250,13 +250,13 @@ public: PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { } - + /// isInvalid - Return true if this object is invalid or uninitialized. This /// occurs when created with invalid source locations or when walking off /// the top of a #include stack. bool isInvalid() const { return Filename == 0; } bool isValid() const { return Filename != 0; } - + /// getFilename - Return the presumed filename of this location. This can be /// affected by #line etc. const char *getFilename() const { return Filename; } @@ -264,7 +264,7 @@ public: /// getLine - Return the presumed line number of this location. This can be /// affected by #line etc. unsigned getLine() const { return Line; } - + /// getColumn - Return the presumed column number of this location. This can /// not be affected by #line, but is packaged here for convenience. unsigned getColumn() const { return Col; } @@ -274,7 +274,7 @@ public: SourceLocation getIncludeLoc() const { return IncludeLoc; } }; - + } // end namespace clang namespace llvm { @@ -286,20 +286,20 @@ namespace llvm { return clang::FileID(); } static inline clang::FileID getTombstoneKey() { - return clang::FileID::getSentinel(); + return clang::FileID::getSentinel(); } - + static unsigned getHashValue(clang::FileID S) { return S.getHashValue(); } - + static bool isEqual(clang::FileID LHS, clang::FileID RHS) { return LHS == RHS; } - + static bool isPod() { return true; } }; - + } // end namespace llvm #endif diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 249ca89f717d..7eb988f005ec 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -24,9 +24,9 @@ namespace llvm { class MemoryBuffer; } - + namespace clang { - + class SourceManager; class FileManager; class FileEntry; @@ -46,7 +46,7 @@ namespace SrcMgr { enum CharacteristicKind { C_User, C_System, C_ExternCSystem }; - + /// ContentCache - Once instance of this struct is kept for every file /// loaded or used. This object owns the MemoryBuffer object. class ContentCache { @@ -54,17 +54,20 @@ namespace SrcMgr { /// file. This is owned by the ContentCache object. mutable const llvm::MemoryBuffer *Buffer; + /// The line and column at which we should truncate the file. + unsigned TruncateAtLine, TruncateAtColumn; + public: /// Reference to the file entry. This reference does not own /// the FileEntry object. It is possible for this to be NULL if /// the ContentCache encapsulates an imaginary text buffer. const FileEntry *Entry; - + /// SourceLineCache - A bump pointer allocated array of offsets for each /// source line. This is lazily computed. This is owned by the /// SourceManager BumpPointerAllocator object. unsigned *SourceLineCache; - + /// NumLines - The number of lines in this ContentCache. This is only valid /// if SourceLineCache is non-null. unsigned NumLines; @@ -76,44 +79,57 @@ namespace SrcMgr { /// getBuffer - Returns the memory buffer for the associated content. const llvm::MemoryBuffer *getBuffer() const; - + /// getSize - Returns the size of the content encapsulated by this /// ContentCache. This can be the size of the source file or the size of an /// arbitrary scratch buffer. If the ContentCache encapsulates a source /// file this size is retrieved from the file's FileEntry. unsigned getSize() const; - + /// getSizeBytesMapped - Returns the number of bytes actually mapped for /// this ContentCache. This can be 0 if the MemBuffer was not actually /// instantiated. unsigned getSizeBytesMapped() const; - + void setBuffer(const llvm::MemoryBuffer *B) { assert(!Buffer && "MemoryBuffer already set."); Buffer = B; } - + + /// \brief Truncate this file at the given line and column. + /// + /// \param Line the line on which to truncate the current file (1-based). + /// \param Column the column at which to truncate the current file. + /// (1-based). + void truncateAt(unsigned Line, unsigned Column); + + /// \brief Determines whether the file was artificially truncated with + /// truncateAt(). + bool isTruncated() const { return TruncateAtLine && TruncateAtColumn; } + ContentCache(const FileEntry *Ent = 0) - : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {} + : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), Entry(Ent), + SourceLineCache(0), NumLines(0) {} ~ContentCache(); - + /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transfered, so this is a logical error. - ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) { + ContentCache(const ContentCache &RHS) + : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), SourceLineCache(0) { Entry = RHS.Entry; assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0 && "Passed ContentCache object cannot own a buffer."); - - NumLines = RHS.NumLines; + + NumLines = RHS.NumLines; } - + private: // Disable assignments. - ContentCache &operator=(const ContentCache& RHS); - }; + ContentCache &operator=(const ContentCache& RHS); + }; /// FileInfo - Information about a FileID, basically just the logical file /// that it represents and include stack information. @@ -128,7 +144,7 @@ namespace SrcMgr { /// IncludeLoc - The location of the #include that brought in this file. /// This is an invalid SLOC for the main file (top of the #include chain). unsigned IncludeLoc; // Really a SourceLocation - + /// Data - This contains the ContentCache* and the bits indicating the /// characteristic of the file and whether it has #line info, all bitmangled /// together. @@ -145,39 +161,39 @@ namespace SrcMgr { X.Data |= (unsigned)FileCharacter; return X; } - + SourceLocation getIncludeLoc() const { return SourceLocation::getFromRawEncoding(IncludeLoc); } const ContentCache* getContentCache() const { return reinterpret_cast<const ContentCache*>(Data & ~7UL); } - + /// getCharacteristic - Return whether this is a system header or not. - CharacteristicKind getFileCharacteristic() const { + CharacteristicKind getFileCharacteristic() const { return (CharacteristicKind)(Data & 3); } /// hasLineDirectives - Return true if this FileID has #line directives in /// it. bool hasLineDirectives() const { return (Data & 4) != 0; } - + /// setHasLineDirectives - Set the flag that indicates that this FileID has /// line table entries associated with it. void setHasLineDirectives() { Data |= 4; } }; - + /// InstantiationInfo - Each InstantiationInfo encodes the Instantiation /// location - where the token was ultimately instantiated, and the /// SpellingLoc - where the actual character data for the token came from. class InstantiationInfo { // Really these are all SourceLocations. - + /// SpellingLoc - Where the spelling for the token can be found. unsigned SpellingLoc; - + /// InstantiationLocStart/InstantiationLocEnd - In a macro expansion, these /// indicate the start and end of the instantiation. In object-like macros, /// these will be the same. In a function-like macro instantiation, the @@ -193,12 +209,12 @@ namespace SrcMgr { SourceLocation getInstantiationLocEnd() const { return SourceLocation::getFromRawEncoding(InstantiationLocEnd); } - + std::pair<SourceLocation,SourceLocation> getInstantiationLocRange() const { return std::make_pair(getInstantiationLocStart(), getInstantiationLocEnd()); } - + /// get - Return a InstantiationInfo for an expansion. IL specifies /// the instantiation location (where the macro is expanded), and SL /// specifies the spelling location (where the characters from the token @@ -213,7 +229,7 @@ namespace SrcMgr { return X; } }; - + /// SLocEntry - This is a discriminated union of FileInfo and /// InstantiationInfo. SourceManager keeps an array of these objects, and /// they are uniquely identified by the FileID datatype. @@ -225,10 +241,10 @@ namespace SrcMgr { }; public: unsigned getOffset() const { return Offset >> 1; } - + bool isInstantiation() const { return Offset & 1; } bool isFile() const { return !isInstantiation(); } - + const FileInfo &getFile() const { assert(isFile() && "Not a file SLocEntry!"); return File; @@ -238,7 +254,7 @@ namespace SrcMgr { assert(isInstantiation() && "Not an instantiation SLocEntry!"); return Instantiation; } - + static SLocEntry get(unsigned Offset, const FileInfo &FI) { SLocEntry E; E.Offset = Offset << 1; @@ -277,18 +293,18 @@ public: /// location specifies where it was expanded. class SourceManager { mutable llvm::BumpPtrAllocator ContentCacheAlloc; - + /// FileInfos - Memoized information about all of the files tracked by this /// SourceManager. This set allows us to merge ContentCache entries based /// on their FileEntry*. All ContentCache objects will thus have unique, - /// non-null, FileEntry pointers. + /// non-null, FileEntry pointers. llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos; - + /// MemBufferInfos - Information about various memory buffers that we have /// read in. All FileEntry* within the stored ContentCache objects are NULL, /// as they do not refer to a file. std::vector<SrcMgr::ContentCache*> MemBufferInfos; - + /// SLocEntryTable - This is an array of SLocEntry's that we have created. /// FileID is an index into this vector. This array is sorted by the offset. std::vector<SrcMgr::SLocEntry> SLocEntryTable; @@ -308,49 +324,55 @@ class SourceManager { /// LastFileIDLookup records the last FileID looked up or created, because it /// is very common to look up many tokens from the same file. mutable FileID LastFileIDLookup; - + /// LineTable - This holds information for #line directives. It is referenced /// by indices from SLocEntryTable. LineTableInfo *LineTable; - + /// LastLineNo - These ivars serve as a cache used in the getLineNumber /// method which is used to speedup getLineNumber calls to nearby locations. mutable FileID LastLineNoFileIDQuery; mutable SrcMgr::ContentCache *LastLineNoContentCache; mutable unsigned LastLineNoFilePos; mutable unsigned LastLineNoResult; - + /// MainFileID - The file ID for the main source file of the translation unit. FileID MainFileID; // Statistics for -print-stats. mutable unsigned NumLinearScans, NumBinaryProbes; - + // Cache results for the isBeforeInTranslationUnit method. mutable FileID LastLFIDForBeforeTUCheck; mutable FileID LastRFIDForBeforeTUCheck; mutable bool LastResForBeforeTUCheck; + + // Keep track of the file/line/column that we should truncate. + const FileEntry *TruncateFile; + unsigned TruncateAtLine; + unsigned TruncateAtColumn; // SourceManager doesn't support copy construction. explicit SourceManager(const SourceManager&); - void operator=(const SourceManager&); + void operator=(const SourceManager&); public: - SourceManager() - : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0) { + SourceManager() + : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), + NumBinaryProbes(0), TruncateFile(0), TruncateAtLine(0), + TruncateAtColumn(0) { clearIDTables(); } ~SourceManager(); - + void clearIDTables(); - + //===--------------------------------------------------------------------===// // MainFileID creation and querying methods. //===--------------------------------------------------------------------===// /// getMainFileID - Returns the FileID of the main source file. FileID getMainFileID() const { return MainFileID; } - + /// createMainFileID - Create the FileID for the main source file. FileID createMainFileID(const FileEntry *SourceFile, SourceLocation IncludePos) { @@ -358,15 +380,15 @@ public: MainFileID = createFileID(SourceFile, IncludePos, SrcMgr::C_User); return MainFileID; } - + //===--------------------------------------------------------------------===// // Methods to create new FileID's and instantiations. //===--------------------------------------------------------------------===// - + /// createFileID - Create a new FileID that represents the specified file /// being #included from the specified IncludePosition. This returns 0 on /// error and translates NULL into standard input. - /// PreallocateID should be non-zero to specify which a pre-allocated, + /// PreallocateID should be non-zero to specify which a pre-allocated, /// lazily computed source location is being filled in by this operation. FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, @@ -376,7 +398,7 @@ public: if (IR == 0) return FileID(); // Error opening file? return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset); } - + /// createFileIDForMemBuffer - Create a new FileID that represents the /// specified memory buffer. This does no caching of the buffer and takes /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once. @@ -386,7 +408,7 @@ public: return createFileID(createMemBufferContentCache(Buffer), SourceLocation(), SrcMgr::C_User, PreallocatedID, Offset); } - + /// createMainFileIDForMembuffer - Create the FileID for a memory buffer /// that will represent the FileID for the main source. One example /// of when this would be used is when the main source is read from STDIN. @@ -405,31 +427,31 @@ public: unsigned TokLength, unsigned PreallocatedID = 0, unsigned Offset = 0); - + //===--------------------------------------------------------------------===// // FileID manipulation methods. //===--------------------------------------------------------------------===// - + /// getBuffer - Return the buffer for the specified FileID. /// const llvm::MemoryBuffer *getBuffer(FileID FID) const { return getSLocEntry(FID).getFile().getContentCache()->getBuffer(); } - + /// getFileEntryForID - Returns the FileEntry record for the provided FileID. const FileEntry *getFileEntryForID(FileID FID) const { return getSLocEntry(FID).getFile().getContentCache()->Entry; } - + /// getBufferData - Return a pointer to the start and end of the source buffer /// data for the specified FileID. std::pair<const char*, const char*> getBufferData(FileID FID) const; - - + + //===--------------------------------------------------------------------===// // SourceLocation manipulation methods. //===--------------------------------------------------------------------===// - + /// getFileID - Return the FileID for a SourceLocation. This is a very /// hot method that is used for all SourceManager queries that start with a /// SourceLocation object. It is responsible for finding the entry in @@ -437,14 +459,14 @@ public: /// FileID getFileID(SourceLocation SpellingLoc) const { unsigned SLocOffset = SpellingLoc.getOffset(); - + // If our one-entry cache covers this offset, just return it. if (isOffsetInFileID(LastFileIDLookup, SLocOffset)) return LastFileIDLookup; return getFileIDSlow(SLocOffset); } - + /// getLocForStartOfFile - Return the source location corresponding to the /// first byte of the specified file. SourceLocation getLocForStartOfFile(FileID FID) const { @@ -453,7 +475,7 @@ public: unsigned FileOffset = getSLocEntry(FID).getOffset(); return SourceLocation::getFileLoc(FileOffset); } - + /// getInstantiationLoc - Given a SourceLocation object, return the /// instantiation location referenced by the ID. SourceLocation getInstantiationLoc(SourceLocation Loc) const { @@ -462,18 +484,18 @@ public: if (Loc.isFileID()) return Loc; return getInstantiationLocSlowCase(Loc); } - + /// getImmediateInstantiationRange - Loc is required to be an instantiation /// location. Return the start/end of the instantiation information. std::pair<SourceLocation,SourceLocation> getImmediateInstantiationRange(SourceLocation Loc) const; - + /// getInstantiationRange - Given a SourceLocation object, return the /// range of tokens covered by the instantiation in the ultimate file. std::pair<SourceLocation,SourceLocation> getInstantiationRange(SourceLocation Loc) const; - - + + /// getSpellingLoc - Given a SourceLocation object, return the spelling /// location referenced by the ID. This is the place where the characters /// that make up the lexed token can be found. @@ -483,12 +505,12 @@ public: if (Loc.isFileID()) return Loc; return getSpellingLocSlowCase(Loc); } - + /// getImmediateSpellingLoc - Given a SourceLocation object, return the /// spelling location referenced by the ID. This is the first level down /// towards the place where the characters that make up the lexed token can be /// found. This should not generally be used by clients. - SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; + SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; /// getDecomposedLoc - Decompose the specified location into a raw FileID + /// Offset pair. The first element is the FileID, the second is the @@ -497,7 +519,7 @@ public: FileID FID = getFileID(Loc); return std::make_pair(FID, Loc.getOffset()-getSLocEntry(FID).getOffset()); } - + /// getDecomposedInstantiationLoc - Decompose the specified location into a /// raw FileID + Offset pair. If the location is an instantiation record, /// walk through it until we find the final location instantiated. @@ -505,11 +527,11 @@ public: getDecomposedInstantiationLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); const SrcMgr::SLocEntry *E = &getSLocEntry(FID); - + unsigned Offset = Loc.getOffset()-E->getOffset(); if (Loc.isFileID()) return std::make_pair(FID, Offset); - + return getDecomposedInstantiationLocSlowCase(E, Offset); } @@ -520,29 +542,29 @@ public: getDecomposedSpellingLoc(SourceLocation Loc) const { FileID FID = getFileID(Loc); const SrcMgr::SLocEntry *E = &getSLocEntry(FID); - + unsigned Offset = Loc.getOffset()-E->getOffset(); if (Loc.isFileID()) return std::make_pair(FID, Offset); return getDecomposedSpellingLocSlowCase(E, Offset); - } - + } + /// getFileOffset - This method returns the offset from the start /// of the file that the specified SourceLocation represents. This is not very /// meaningful for a macro ID. unsigned getFileOffset(SourceLocation SpellingLoc) const { return getDecomposedLoc(SpellingLoc).second; } - - + + //===--------------------------------------------------------------------===// // Queries about the code at a SourceLocation. //===--------------------------------------------------------------------===// - + /// getCharacterData - Return a pointer to the start of the specified location /// in the appropriate spelling MemoryBuffer. const char *getCharacterData(SourceLocation SL) const; - + /// getColumnNumber - Return the column # for the specified file position. /// This is significantly cheaper to compute than the line number. This /// returns zero if the column number isn't known. This may only be called on @@ -551,24 +573,24 @@ public: unsigned getColumnNumber(FileID FID, unsigned FilePos) const; unsigned getSpellingColumnNumber(SourceLocation Loc) const; unsigned getInstantiationColumnNumber(SourceLocation Loc) const; - - + + /// getLineNumber - Given a SourceLocation, return the spelling line number /// for the position indicated. This requires building and caching a table of /// line offsets for the MemoryBuffer, so this is not cheap: use only when /// about to emit a diagnostic. unsigned getLineNumber(FileID FID, unsigned FilePos) const; - + unsigned getInstantiationLineNumber(SourceLocation Loc) const; unsigned getSpellingLineNumber(SourceLocation Loc) const; - + /// Return the filename or buffer identifier of the buffer the location is in. /// Note that this name does not respect #line directives. Use getPresumedLoc /// for normal clients. const char *getBufferName(SourceLocation Loc) const; - + /// getFileCharacteristic - return the file characteristic of the specified - /// source location, indicating whether this is a normal file, a system + /// source location, indicating whether this is a normal file, a system /// header, or an "implicit extern C" system header. /// /// This state can be modified with flags on GNU linemarker directives like: @@ -576,7 +598,7 @@ public: /// which changes all source locations in the current file after that to be /// considered to be from a system header. SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const; - + /// getPresumedLoc - This method returns the "presumed" location of a /// SourceLocation specifies. A "presumed location" can be modified by #line /// or GNU line marker directives. This provides a view on the data that a @@ -585,44 +607,44 @@ public: /// Note that a presumed location is always given as the instantiation point /// of an instantiation location, not at the spelling location. PresumedLoc getPresumedLoc(SourceLocation Loc) const; - + /// isFromSameFile - Returns true if both SourceLocations correspond to /// the same file. bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const { return getFileID(Loc1) == getFileID(Loc2); } - + /// isFromMainFile - Returns true if the file of provided SourceLocation is /// the main file. bool isFromMainFile(SourceLocation Loc) const { return getFileID(Loc) == getMainFileID(); - } - + } + /// isInSystemHeader - Returns if a SourceLocation is in a system header. bool isInSystemHeader(SourceLocation Loc) const { return getFileCharacteristic(Loc) != SrcMgr::C_User; } - + /// isInExternCSystemHeader - Returns if a SourceLocation is in an "extern C" /// system header. bool isInExternCSystemHeader(SourceLocation Loc) const { return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem; } - + //===--------------------------------------------------------------------===// // Line Table Manipulation Routines //===--------------------------------------------------------------------===// - + /// getLineTableFilenameID - Return the uniqued ID for the specified filename. - /// + /// unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); - + /// AddLineNote - Add a line note to the line table for the FileID and offset /// specified by Loc. If FilenameID is -1, it is considered to be /// unspecified. void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, - bool IsFileEntry, bool IsFileExit, + bool IsFileEntry, bool IsFileExit, bool IsSystemHeader, bool IsExternCHeader); /// \brief Determine if the source manager has a line table. @@ -641,12 +663,18 @@ public: /// be based upon the first inclusion. 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; + /// \brief Truncate the given file at the specified line/column. + void truncateFileAt(const FileEntry *Entry, unsigned Line, unsigned Column); + + /// \brief Determine whether this file was truncated. + bool isTruncatedFile(FileID FID) const; + // Iterators over FileInfos. typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> ::const_iterator fileinfo_iterator; @@ -657,22 +685,22 @@ public: /// void PrintStats() const; - // Iteration over the source location entry table. + // Iteration over the source location entry table. typedef std::vector<SrcMgr::SLocEntry>::const_iterator sloc_entry_iterator; - sloc_entry_iterator sloc_entry_begin() const { - return SLocEntryTable.begin(); + sloc_entry_iterator sloc_entry_begin() const { + return SLocEntryTable.begin(); } - sloc_entry_iterator sloc_entry_end() const { - return SLocEntryTable.end(); + sloc_entry_iterator sloc_entry_end() const { + return SLocEntryTable.end(); } unsigned sloc_entry_size() const { return SLocEntryTable.size(); } const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { assert(FID.ID < SLocEntryTable.size() && "Invalid id"); - if (ExternalSLocEntries && + if (ExternalSLocEntries && FID.ID < SLocEntryLoaded.size() && !SLocEntryLoaded[FID.ID]) ExternalSLocEntries->ReadSLocEntry(FID.ID); @@ -698,14 +726,14 @@ private: const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); // If the entry is after the offset, it can't contain it. if (SLocOffset < Entry.getOffset()) return false; - + // If this is the last entry than it does. Otherwise, the entry after it // has to not include it. if (FID.ID+1 == SLocEntryTable.size()) return true; return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset(); } - + /// createFileID - Create a new fileID for the specified ContentCache and /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. @@ -714,15 +742,15 @@ private: SrcMgr::CharacteristicKind DirCharacter, unsigned PreallocatedID = 0, unsigned Offset = 0); - + const SrcMgr::ContentCache * getOrCreateContentCache(const FileEntry *SourceFile); /// createMemBufferContentCache - Create a new ContentCache for the specified /// memory buffer. - const SrcMgr::ContentCache* + const SrcMgr::ContentCache* createMemBufferContentCache(const llvm::MemoryBuffer *Buf); - + FileID getFileIDSlow(unsigned SLocOffset) const; SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const; @@ -730,7 +758,7 @@ private: std::pair<FileID, unsigned> getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, - unsigned Offset) const; + unsigned Offset) const; std::pair<FileID, unsigned> getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, unsigned Offset) const; diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h index 0bcb68e4601d..258989cb7787 100644 --- a/include/clang/Basic/SourceManagerInternals.h +++ b/include/clang/Basic/SourceManagerInternals.h @@ -28,22 +28,22 @@ namespace clang { struct LineEntry { /// FileOffset - The offset in this file that the line entry occurs at. unsigned FileOffset; - + /// LineNo - The presumed line number of this line entry: #line 4. unsigned LineNo; - + /// FilenameID - The ID of the filename identified by this line entry: /// #line 4 "foo.c". This is -1 if not specified. int FilenameID; - - /// Flags - Set the 0 if no flags, 1 if a system header, + + /// Flags - Set the 0 if no flags, 1 if a system header, SrcMgr::CharacteristicKind FileKind; - + /// IncludeOffset - This is the offset of the virtual include stack location, /// which is manipulated by GNU linemarker directives. If this is 0 then /// there is no virtual #includer. unsigned IncludeOffset; - + static LineEntry get(unsigned Offs, unsigned Line, int Filename, SrcMgr::CharacteristicKind FileKind, unsigned IncludeOffset) { @@ -70,7 +70,7 @@ inline bool operator<(const LineEntry &E, unsigned Offset) { inline bool operator<(unsigned Offset, const LineEntry &E) { return Offset < E.FileOffset; } - + /// LineTableInfo - This class is used to hold and unique data used to /// represent #line information. class LineTableInfo { @@ -81,22 +81,22 @@ class LineTableInfo { /// to string. llvm::StringMap<unsigned, llvm::BumpPtrAllocator> FilenameIDs; std::vector<llvm::StringMapEntry<unsigned>*> FilenamesByID; - + /// LineEntries - This is a map from FileIDs to a list of line entries (sorted /// by the offset they occur in the file. std::map<unsigned, std::vector<LineEntry> > LineEntries; public: LineTableInfo() { } - + void clear() { FilenameIDs.clear(); FilenamesByID.clear(); LineEntries.clear(); } - + ~LineTableInfo() {} - + unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); const char *getFilename(unsigned ID) const { assert(ID < FilenamesByID.size() && "Invalid FilenameID"); @@ -110,7 +110,7 @@ public: unsigned LineNo, int FilenameID, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind); - + /// FindNearestLineEntry - Find the line entry nearest to FID that is before /// it. If there is no line entry before Offset in FID, return null. const LineEntry *FindNearestLineEntry(unsigned FID, unsigned Offset); diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 537d553bc2d1..a1e0a17c882e 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -16,31 +16,37 @@ // FIXME: Daniel isn't smart enough to use a prototype for this. #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/DataTypes.h" #include <cassert> #include <vector> #include <string> -namespace llvm { struct fltSemantics; } +namespace llvm { +struct fltSemantics; +class StringRef; +} namespace clang { class Diagnostic; +class SourceLocation; class SourceManager; class LangOptions; - namespace Builtin { struct Info; } - + /// TargetInfo - This class exposes information about the current target. /// class TargetInfo { - std::string Triple; + llvm::Triple Triple; protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. bool TLSSupported; unsigned char PointerWidth, PointerAlign; unsigned char WCharWidth, WCharAlign; + unsigned char Char16Width, Char16Align; + unsigned char Char32Width, Char32Align; unsigned char IntWidth, IntAlign; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; @@ -55,8 +61,8 @@ protected: // TargetInfo Constructor. Default initializes all fields. TargetInfo(const std::string &T); - -public: + +public: /// CreateTargetInfo - Return the target info object for the specified target /// triple. static TargetInfo* CreateTargetInfo(const std::string &Triple); @@ -77,7 +83,7 @@ public: }; protected: IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, - Int64Type; + Char16Type, Char32Type, Int64Type; public: IntType getSizeType() const { return SizeType; } IntType getIntMaxType() const { return IntMaxType; } @@ -87,6 +93,8 @@ public: } IntType getIntPtrType() const { return IntPtrType; } IntType getWCharType() const { return WCharType; } + IntType getChar16Type() const { return Char16Type; } + IntType getChar32Type() const { return Char32Type; } IntType getInt64Type() const { return Int64Type; } /// getPointerWidth - Return the width of pointers on this target, for the @@ -97,44 +105,50 @@ public: uint64_t getPointerAlign(unsigned AddrSpace) const { return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace); } - + /// getBoolWidth/Align - Return the size of '_Bool' and C++ 'bool' for this /// target, in bits. unsigned getBoolWidth(bool isWide = false) const { return 8; } // FIXME unsigned getBoolAlign(bool isWide = false) const { return 8; } // FIXME - - unsigned getCharWidth(bool isWide = false) const { - return isWide ? getWCharWidth() : 8; // FIXME - } - unsigned getCharAlign(bool isWide = false) const { - return isWide ? getWCharAlign() : 8; // FIXME - } - + + unsigned getCharWidth() const { return 8; } // FIXME + unsigned getCharAlign() const { return 8; } // FIXME + /// getShortWidth/Align - Return the size of 'signed short' and - /// 'unsigned short' for this target, in bits. + /// 'unsigned short' for this target, in bits. unsigned getShortWidth() const { return 16; } // FIXME unsigned getShortAlign() const { return 16; } // FIXME - + /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for /// this target, in bits. unsigned getIntWidth() const { return IntWidth; } unsigned getIntAlign() const { return IntAlign; } - + /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' /// for this target, in bits. unsigned getLongWidth() const { return LongWidth; } unsigned getLongAlign() const { return LongAlign; } - + /// getLongLongWidth/Align - Return the size of 'signed long long' and /// 'unsigned long long' for this target, in bits. unsigned getLongLongWidth() const { return LongLongWidth; } unsigned getLongLongAlign() const { return LongLongAlign; } - - /// getWcharWidth/Align - Return the size of 'wchar_t' for this target, in + + /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in /// bits. unsigned getWCharWidth() const { return WCharWidth; } unsigned getWCharAlign() const { return WCharAlign; } + /// getChar16Width/Align - Return the size of 'char16_t' for this target, in + /// bits. + unsigned getChar16Width() const { return Char16Width; } + unsigned getChar16Align() const { return Char16Align; } + + /// getChar32Width/Align - Return the size of 'char32_t' for this target, in + /// bits. + unsigned getChar32Width() const { return Char32Width; } + unsigned getChar32Align() const { return Char32Align; } + /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. unsigned getFloatWidth() const { return FloatWidth; } unsigned getFloatAlign() const { return FloatAlign; } @@ -152,13 +166,13 @@ public: const llvm::fltSemantics &getLongDoubleFormat() const { return *LongDoubleFormat; } - + /// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this - /// target, in bits. + /// target, in bits. unsigned getIntMaxTWidth() const { return IntMaxTWidth; } - + /// getUserLabelPrefix - This returns the default value of the /// __USER_LABEL_PREFIX__ macro, which is the prefix given to user symbols by /// default. On most platforms this is "_", but it is "" on some, and "." on @@ -166,22 +180,22 @@ public: const char *getUserLabelPrefix() const { return UserLabelPrefix; } - + /// getTypeName - Return the user string for the specified integer type enum. /// For example, SignedShort -> "short". static const char *getTypeName(IntType T); - + ///===---- Other target property query methods --------------------------===// - + /// getTargetDefines - Appends the target-specific #define values for this /// target set to the specified buffer. virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &DefineBuffer) const = 0; - + /// getTargetBuiltins - Return information about target-specific builtins for /// the current primary target, and info about which builtins are non-portable /// across the current set of primary and secondary targets. - virtual void getTargetBuiltins(const Builtin::Info *&Records, + virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const = 0; /// getVAListDeclaration - Return the declaration to use for @@ -196,7 +210,7 @@ public: // getNormalizedGCCRegisterName - Returns the "normalized" GCC register name. // For example, on x86 it will return "ax" when "eax" is passed in. const char *getNormalizedGCCRegisterName(const char *Name) const; - + struct ConstraintInfo { enum { CI_None = 0x00, @@ -207,7 +221,7 @@ public: }; unsigned Flags; int TiedOperand; - + std::string ConstraintStr; // constraint: "=rm" std::string Name; // Operand name: [foo] with no []'s. public: @@ -221,11 +235,11 @@ public: bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } - + /// hasMatchingInput - Return true if this output operand has a matching /// (tied) input operand. bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } - + /// hasTiedOperand() - Return true if this input operand is a matching /// constraint that ties it to an output operand. If this returns true, /// then getTiedOperand will indicate which output operand this is tied to. @@ -234,12 +248,12 @@ public: assert(hasTiedOperand() && "Has no tied operand!"); return (unsigned)TiedOperand; } - + void setIsReadWrite() { Flags |= CI_ReadWrite; } void setAllowsMemory() { Flags |= CI_AllowsMemory; } void setAllowsRegister() { Flags |= CI_AllowsRegister; } void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } - + /// setTiedOperand - Indicate that this is an input operand that is tied to /// the specified output operand. Copy over the various constraint /// information from the output. @@ -261,24 +275,20 @@ public: bool resolveSymbolicName(const char *&Name, ConstraintInfo *OutputConstraints, unsigned NumOutputs, unsigned &Index) const; - + virtual std::string convertConstraint(const char Constraint) const { return std::string(1, Constraint); } - + // Returns a string of target-specific clobbers, in LLVM format. virtual const char *getClobbers() const = 0; - - /// getTargetPrefix - Return the target prefix used for identifying - /// llvm intrinsics. - virtual const char *getTargetPrefix() const = 0; - - /// getTargetTriple - Return the target triple of the primary target. - const char *getTargetTriple() const { - return Triple.c_str(); + + /// getTriple - Return the target triple of the primary target. + const llvm::Triple &getTriple() const { + return Triple; } - + const char *getTargetDescription() const { return DescriptionString; } @@ -290,55 +300,56 @@ public: virtual bool useGlobalsForAutomaticVariables() const { return false; } - /// getStringSymbolPrefix - Get the default symbol prefix to - /// use for string literals. - virtual const char *getStringSymbolPrefix(bool IsConstant) const { - return ".str"; - } - - /// getCFStringSymbolPrefix - Get the default symbol prefix - /// to use for CFString literals. - virtual const char *getCFStringSymbolPrefix() const { - return ""; - } - - /// getUnicodeStringSymbolPrefix - Get the default symbol prefix to - /// use for string literals. - virtual const char *getUnicodeStringSymbolPrefix() const { - return ".str"; - } - /// getUnicodeStringSection - Return the section to use for unicode /// string literals, or 0 if no special section is used. - virtual const char *getUnicodeStringSection() const { + virtual const char *getUnicodeStringSection() const { return 0; } /// getCFStringSection - Return the section to use for CFString /// literals, or 0 if no special section is used. - virtual const char *getCFStringSection() const { + virtual const char *getCFStringSection() const { return "__DATA,__cfstring"; } - /// getCFStringDataSection - Return the section to use for the - /// constant string data associated with a CFString literal, or 0 if - /// no special section is used. - virtual const char *getCFStringDataSection() const { - return "__TEXT,__cstring,cstring_literals"; + /// isValidSectionSpecifier - This is an optional hook that targets can + /// implement to perform semantic checking on attribute((section("foo"))) + /// specifiers. In this case, "foo" is passed in to be checked. If the + /// section specifier is invalid, the backend should return a non-empty string + /// that indicates the problem. + /// + /// This hook is a simple quality of implementation feature to catch errors + /// and give good diagnostics in cases when the assembler or code generator + /// would otherwise reject the section specifier. + /// + virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const { + return ""; } /// getDefaultLangOptions - Allow the target to specify default settings for /// various language options. These may be overridden by command line - /// options. + /// options. virtual void getDefaultLangOptions(LangOptions &Opts) {} /// getDefaultFeatures - Get the default set of target features for /// the \args CPU; this should include all legal feature strings on /// the target. - virtual void getDefaultFeatures(const std::string &CPU, + virtual void getDefaultFeatures(const std::string &CPU, llvm::StringMap<bool> &Features) const { } + /// getABI - Get the ABI in use. + virtual const char *getABI() const { + return ""; + } + + /// setABI - Use the specific ABI. + /// + /// \return - False on error (invalid ABI name). + virtual bool setABI(const std::string &Name) { + return false; + } + /// setFeatureEnabled - Enable or disable a specific target feature, /// the feature name must be valid. /// @@ -359,10 +370,17 @@ public: return RegParmMax; } - // isTLSSupported - Whether the target supports thread-local storage - unsigned isTLSSupported() const { + /// isTLSSupported - Whether the target supports thread-local storage. + bool isTLSSupported() const { return TLSSupported; } + + /// getEHDataRegisterNumber - Return the register number that + /// __builtin_eh_return_regno would return with the specified argument. + virtual int getEHDataRegisterNumber(unsigned RegNo) const { + return -1; + } + protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { @@ -374,11 +392,11 @@ protected: virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const { return PtrDiffType; } - virtual void getGCCRegNames(const char * const *&Names, + virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const = 0; - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, unsigned &NumAliases) const = 0; - virtual bool validateAsmConstraint(const char *&Name, + virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const= 0; }; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index e711996cf26d..239712c08caf 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -92,6 +92,7 @@ PPKEYWORD(unassert) TOK(unknown) // Not a token. TOK(eof) // End of file. TOK(eom) // End of macro (end of line inside a macro). +TOK(code_completion) // Code completion marker // C99 6.4.9: Comments. TOK(comment) // Comment (only in -E -C[C] mode) diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h index 62a9e428bf21..85dc0671de62 100644 --- a/include/clang/Basic/TokenKinds.h +++ b/include/clang/Basic/TokenKinds.h @@ -29,7 +29,7 @@ enum TokenKind { /// PPKeywordKind - This provides a namespace for preprocessor keywords which /// start with a '#' at the beginning of the line. enum PPKeywordKind { -#define PPKEYWORD(X) pp_##X, +#define PPKEYWORD(X) pp_##X, #include "clang/Basic/TokenKinds.def" NUM_PP_KEYWORDS }; diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h index f0e1aa7db233..120d5a4210d0 100644 --- a/include/clang/Basic/Version.h +++ b/include/clang/Basic/Version.h @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This header defines version macros for Clang. +// This header defines version macros and version-related utility functions +// for Clang. // //===----------------------------------------------------------------------===// @@ -17,12 +18,25 @@ /// \brief Clang major version #define CLANG_VERSION_MAJOR 1 +// FIXME: Updates to this file must also update CMakeLists.txt and VER. /// \brief Clang minor version -#define CLANG_VERSION_MINOR 0 +#define CLANG_VERSION_MINOR 1 + +/// \brief Clang patchlevel version +// #define CLANG_VERSION_PATCHLEVEL 1 /// \brief Helper macro for CLANG_VERSION_STRING. #define CLANG_MAKE_VERSION_STRING2(X) #X +#ifdef CLANG_VERSION_PATCHLEVEL +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y,Z) CLANG_MAKE_VERSION_STRING2(X.Y.Z) + +/// \brief A string that describes the Clang version number, e.g., +/// "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR,CLANG_VERSION_PATCHLEVEL) +#else /// \brief Helper macro for CLANG_VERSION_STRING. #define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y) @@ -30,6 +44,16 @@ /// "1.0". #define CLANG_VERSION_STRING \ CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR) - +#endif + +namespace clang { + /// \brief Retrieves the Subversion path that identifies the particular + /// Clang branch, tag, or trunk from which this Clang was built. + const char *getClangSubversionPath(); + + /// \brief Retrieves the Subversion revision number from which this Clang + /// was built. + unsigned getClangSubversionRevision(); +} #endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h index 12b74d51473e..1871c8f206f3 100644 --- a/include/clang/CodeGen/ModuleBuilder.h +++ b/include/clang/CodeGen/ModuleBuilder.h @@ -26,13 +26,13 @@ namespace clang { class Diagnostic; class LangOptions; class CompileOptions; - + class CodeGenerator : public ASTConsumer { public: virtual llvm::Module* GetModule() = 0; - virtual llvm::Module* ReleaseModule() = 0; + virtual llvm::Module* ReleaseModule() = 0; }; - + CodeGenerator *CreateLLVMCodeGen(Diagnostic &Diags, const std::string &ModuleName, const CompileOptions &CO, diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index ceef189f7b7e..679704c39587 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -26,7 +26,7 @@ namespace clang { namespace driver { class Arg; -/// Action - Represent an abstract compilation step to perform. +/// Action - Represent an abstract compilation step to perform. /// /// An action represents an edge in the compilation graph; typically /// it is a job to transform an input using some tool. @@ -63,15 +63,15 @@ private: /// The output type of this action. types::ID Type; - + ActionList Inputs; protected: Action(ActionClass _Kind, types::ID _Type) : Kind(_Kind), Type(_Type) {} - Action(ActionClass _Kind, Action *Input, types::ID _Type) + Action(ActionClass _Kind, Action *Input, types::ID _Type) : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1) {} - Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) - : Kind(_Kind), Type(_Type), Inputs(_Inputs) {} + Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) + : Kind(_Kind), Type(_Type), Inputs(_Inputs) {} public: virtual ~Action(); @@ -90,7 +90,7 @@ public: const_iterator begin() const { return Inputs.begin(); } const_iterator end() const { return Inputs.end(); } - static bool classof(const Action *) { return true; } + static bool classof(const Action *) { return true; } }; class InputAction : public Action { @@ -100,8 +100,8 @@ public: const Arg &getInputArg() const { return Input; } - static bool classof(const Action *A) { - return A->getKind() == InputClass; + static bool classof(const Action *A) { + return A->getKind() == InputClass; } static bool classof(const InputAction *) { return true; } }; @@ -116,8 +116,8 @@ public: const char *getArchName() const { return ArchName; } - static bool classof(const Action *A) { - return A->getKind() == BindArchClass; + static bool classof(const Action *A) { + return A->getKind() == BindArchClass; } static bool classof(const BindArchAction *) { return true; } }; @@ -128,9 +128,9 @@ protected: JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); public: - static bool classof(const Action *A) { + static bool classof(const Action *A) { return (A->getKind() >= JobClassFirst && - A->getKind() <= JobClassLast); + A->getKind() <= JobClassLast); } static bool classof(const JobAction *) { return true; } }; @@ -139,7 +139,7 @@ class PreprocessJobAction : public JobAction { public: PreprocessJobAction(Action *Input, types::ID OutputType); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == PreprocessJobClass; } static bool classof(const PreprocessJobAction *) { return true; } @@ -149,7 +149,7 @@ class PrecompileJobAction : public JobAction { public: PrecompileJobAction(Action *Input, types::ID OutputType); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == PrecompileJobClass; } static bool classof(const PrecompileJobAction *) { return true; } @@ -159,7 +159,7 @@ class AnalyzeJobAction : public JobAction { public: AnalyzeJobAction(Action *Input, types::ID OutputType); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == AnalyzeJobClass; } static bool classof(const AnalyzeJobAction *) { return true; } @@ -169,7 +169,7 @@ class CompileJobAction : public JobAction { public: CompileJobAction(Action *Input, types::ID OutputType); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == CompileJobClass; } static bool classof(const CompileJobAction *) { return true; } @@ -179,7 +179,7 @@ class AssembleJobAction : public JobAction { public: AssembleJobAction(Action *Input, types::ID OutputType); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == AssembleJobClass; } static bool classof(const AssembleJobAction *) { return true; } @@ -189,7 +189,7 @@ class LinkJobAction : public JobAction { public: LinkJobAction(ActionList &Inputs, types::ID Type); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == LinkJobClass; } static bool classof(const LinkJobAction *) { return true; } @@ -199,7 +199,7 @@ class LipoJobAction : public JobAction { public: LipoJobAction(ActionList &Inputs, types::ID Type); - static bool classof(const Action *A) { + static bool classof(const Action *A) { return A->getKind() == LipoJobClass; } static bool classof(const LipoJobAction *) { return true; } diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h index 6bed2b8cbdef..ebf40d45de4c 100644 --- a/include/clang/Driver/Arg.h +++ b/include/clang/Driver/Arg.h @@ -49,7 +49,7 @@ namespace driver { /// The option this argument is an instance of. const Option *Opt; - + /// The argument this argument was derived from (during tool chain /// argument translation), if any. const Arg *BaseArg; @@ -66,7 +66,7 @@ namespace driver { protected: Arg(ArgClass Kind, const Option *Opt, unsigned Index, const Arg *BaseArg = 0); - + public: Arg(const Arg &); virtual ~Arg(); @@ -74,12 +74,12 @@ namespace driver { ArgClass getKind() const { return Kind; } const Option &getOption() const { return *Opt; } unsigned getIndex() const { return Index; } - + /// getBaseArg - Return the base argument which generated this /// arg; this is either the argument itself or the argument it was /// derived from during tool chain specific argument translation. - const Arg &getBaseArg() const { - return BaseArg ? *BaseArg : *this; + const Arg &getBaseArg() const { + return BaseArg ? *BaseArg : *this; } void setBaseArg(const Arg *_BaseArg) { BaseArg = _BaseArg; @@ -88,14 +88,14 @@ namespace driver { bool isClaimed() const { return getBaseArg().Claimed; } /// claim - Set the Arg claimed bit. - + // FIXME: We need to deal with derived arguments and set the bit // in the original argument; not the derived one. void claim() const { getBaseArg().Claimed = true; } virtual unsigned getNumValues() const = 0; virtual const char *getValue(const ArgList &Args, unsigned N=0) const = 0; - + /// render - Append the argument onto the given array as strings. virtual void render(const ArgList &Args, ArgStringList &Output) const = 0; @@ -105,7 +105,7 @@ namespace driver { /// (e.g., Xlinker). void renderAsInput(const ArgList &Args, ArgStringList &Output) const; - static bool classof(const Arg *) { return true; } + static bool classof(const Arg *) { return true; } void dump() const; @@ -124,8 +124,8 @@ namespace driver { virtual unsigned getNumValues() const { return 0; } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::FlagClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::FlagClass; } static bool classof(const FlagArg *) { return true; } }; @@ -140,8 +140,8 @@ namespace driver { virtual unsigned getNumValues() const { return 1; } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::PositionalClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::PositionalClass; } static bool classof(const PositionalArg *) { return true; } }; @@ -157,8 +157,8 @@ namespace driver { virtual unsigned getNumValues() const { return 1; } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::JoinedClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::JoinedClass; } static bool classof(const JoinedArg *) { return true; } }; @@ -169,7 +169,7 @@ namespace driver { unsigned NumValues; public: - SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues, + SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues, const Arg *BaseArg = 0); virtual void render(const ArgList &Args, ArgStringList &Output) const; @@ -177,8 +177,8 @@ namespace driver { virtual unsigned getNumValues() const { return NumValues; } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::SeparateClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::SeparateClass; } static bool classof(const SeparateArg *) { return true; } }; @@ -193,7 +193,7 @@ namespace driver { std::vector<std::string> Values; public: - CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str, + CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str, const Arg *BaseArg = 0); virtual void render(const ArgList &Args, ArgStringList &Output) const; @@ -201,8 +201,8 @@ namespace driver { virtual unsigned getNumValues() const { return Values.size(); } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::CommaJoinedClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::CommaJoinedClass; } static bool classof(const CommaJoinedArg *) { return true; } }; @@ -211,7 +211,7 @@ namespace driver { /// values. class JoinedAndSeparateArg : public Arg { public: - JoinedAndSeparateArg(const Option *Opt, unsigned Index, + JoinedAndSeparateArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0); virtual void render(const ArgList &Args, ArgStringList &Output) const; @@ -219,8 +219,8 @@ namespace driver { virtual unsigned getNumValues() const { return 2; } virtual const char *getValue(const ArgList &Args, unsigned N=0) const; - static bool classof(const Arg *A) { - return A->getKind() == Arg::JoinedAndSeparateClass; + static bool classof(const Arg *A) { + return A->getKind() == Arg::JoinedAndSeparateClass; } static bool classof(const JoinedAndSeparateArg *) { return true; } }; diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index a9c890b0b899..dcb60381a467 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -14,8 +14,14 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include <list> +#include <string> + +namespace llvm { + class Twine; +} namespace clang { namespace driver { @@ -64,17 +70,17 @@ namespace driver { const_iterator begin() const { return Args.begin(); } const_iterator end() const { return Args.end(); } - + const_reverse_iterator rbegin() const { return Args.rbegin(); } const_reverse_iterator rend() const { return Args.rend(); } /// hasArg - Does the arg list contain any option matching \arg Id. /// /// \arg Claim Whether the argument should be claimed, if it exists. - bool hasArg(options::ID Id, bool Claim=true) const { + bool hasArg(options::ID Id, bool Claim=true) const { return getLastArg(Id, Claim) != 0; } - bool hasArg(options::ID Id0, options::ID Id1, bool Claim=true) const { + bool hasArg(options::ID Id0, options::ID Id1, bool Claim=true) const { return getLastArg(Id0, Id1, Claim) != 0; } @@ -104,15 +110,15 @@ namespace driver { /// AddAllArgs - Render all arguments matching the given ids. void AddAllArgs(ArgStringList &Output, options::ID Id0) const; - void AddAllArgs(ArgStringList &Output, options::ID Id0, + void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1) const; - void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1, + void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1, options::ID Id2) const; /// AddAllArgValues - Render the argument values of all arguments /// matching the given ids. void AddAllArgValues(ArgStringList &Output, options::ID Id0) const; - void AddAllArgValues(ArgStringList &Output, options::ID Id0, + void AddAllArgValues(ArgStringList &Output, options::ID Id0, options::ID Id1) const; /// AddAllArgsTranslated - Render all the arguments matching the @@ -122,7 +128,7 @@ namespace driver { /// \param Joined - If true, render the argument as joined with /// the option specifier. void AddAllArgsTranslated(ArgStringList &Output, options::ID Id0, - const char *Translation, + const char *Translation, bool Joined = false) const; /// ClaimAllArgs - Claim all arguments which match the given @@ -135,7 +141,14 @@ namespace driver { /// MakeArgString - Construct a constant string pointer whose /// lifetime will match that of the ArgList. - virtual const char *MakeArgString(const char *Str) const = 0; + virtual const char *MakeArgString(llvm::StringRef Str) const = 0; + const char *MakeArgString(const char *Str) const { + return MakeArgString(llvm::StringRef(Str)); + } + const char *MakeArgString(std::string Str) const { + return MakeArgString(llvm::StringRef(Str)); + } + const char *MakeArgString(const llvm::Twine &Str) const; /// @} }; @@ -167,8 +180,8 @@ namespace driver { InputArgList(const ArgList &); ~InputArgList(); - virtual const char *getArgString(unsigned Index) const { - return ArgStrings[Index]; + virtual const char *getArgString(unsigned Index) const { + return ArgStrings[Index]; } /// getNumInputArgStrings - Return the number of original input @@ -180,10 +193,10 @@ namespace driver { public: /// MakeIndex - Get an index for the given string(s). - unsigned MakeIndex(const char *String0) const; - unsigned MakeIndex(const char *String0, const char *String1) const; + unsigned MakeIndex(llvm::StringRef String0) const; + unsigned MakeIndex(llvm::StringRef String0, llvm::StringRef String1) const; - virtual const char *MakeArgString(const char *Str) const; + virtual const char *MakeArgString(llvm::StringRef Str) const; /// @} }; @@ -211,13 +224,13 @@ namespace driver { ~DerivedArgList(); virtual const char *getArgString(unsigned Index) const { - return BaseArgs.getArgString(Index); + return BaseArgs.getArgString(Index); } /// @name Arg Synthesis /// @{ - virtual const char *MakeArgString(const char *Str) const; + virtual const char *MakeArgString(llvm::StringRef Str) const; /// MakeFlagArg - Construct a new FlagArg for the given option /// \arg Id. @@ -225,18 +238,18 @@ namespace driver { /// MakePositionalArg - Construct a new Positional arg for the /// given option \arg Id, with the provided \arg Value. - Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const; + Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const; /// MakeSeparateArg - Construct a new Positional arg for the /// given option \arg Id, with the provided \arg Value. - Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const; + Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const; /// MakeJoinedArg - Construct a new Positional arg for the /// given option \arg Id, with the provided \arg Value. - Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const; + Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const; /// @} }; diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h index 6414ef13692b..56786a7ae2a3 100644 --- a/include/clang/Driver/Compilation.h +++ b/include/clang/Driver/Compilation.h @@ -47,7 +47,8 @@ class Compilation { JobList Jobs; /// Cache of translated arguments for a particular tool chain. - llvm::DenseMap<const ToolChain*, DerivedArgList*> TCArgs; + llvm::DenseMap<std::pair<const ToolChain*, const char*>, + DerivedArgList*> TCArgs; /// Temporary files which should be removed on exit. ArgStringList TempFiles; @@ -56,7 +57,7 @@ class Compilation { ArgStringList ResultFiles; public: - Compilation(const Driver &D, const ToolChain &DefaultToolChain, + Compilation(const Driver &D, const ToolChain &DefaultToolChain, InputArgList *Args); ~Compilation(); @@ -79,12 +80,15 @@ public: /// getArgsForToolChain - Return the derived argument list for the /// tool chain \arg TC (or the default tool chain, if TC is not /// specified). - const DerivedArgList &getArgsForToolChain(const ToolChain *TC = 0); + /// + /// \param BoundArch - The bound architecture name, or 0. + const DerivedArgList &getArgsForToolChain(const ToolChain *TC, + const char *BoundArch); /// addTempFile - Add a file to remove on exit, and returns its /// argument. - const char *addTempFile(const char *Name) { - TempFiles.push_back(Name); + const char *addTempFile(const char *Name) { + TempFiles.push_back(Name); return Name; } @@ -99,7 +103,7 @@ public: /// /// \param IssueErrors - Report failures as errors. /// \return Whether all files were removed successfully. - bool CleanupFileList(const ArgStringList &Files, + bool CleanupFileList(const ArgStringList &Files, bool IssueErrors=false) const; /// PrintJob - Print one job in -### format. @@ -108,7 +112,7 @@ public: /// \param J - The job to print. /// \param Terminator - A string to print at the end of the line. /// \param Quote - Should separate arguments be quoted. - void PrintJob(llvm::raw_ostream &OS, const Job &J, + void PrintJob(llvm::raw_ostream &OS, const Job &J, const char *Terminator, bool Quote) const; /// ExecuteCommand - Execute an actual command. diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index c0def2bcca29..c0327a2f1d1c 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -15,12 +15,16 @@ #include "clang/Driver/Phases.h" #include "clang/Driver/Util.h" +#include "llvm/ADT/Triple.h" #include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo // lands. #include <list> #include <set> #include <string> +namespace llvm { + class raw_ostream; +} namespace clang { namespace driver { class Action; @@ -51,11 +55,11 @@ public: public: /// The name the driver was invoked as. std::string Name; - + /// The path the driver executable was in, as invoked from the /// command line. std::string Dir; - + /// Default host triple. std::string DefaultHostTriple; @@ -71,7 +75,7 @@ public: /// Whether the driver should follow g++ like behavior. bool CCCIsCXX : 1; - + /// Echo commands while executing (in -v style). bool CCCEcho : 1; @@ -99,11 +103,11 @@ public: private: /// Only use clang for the given architectures (only used when /// non-empty). - std::set<std::string> CCCClangArchs; + std::set<llvm::Triple::ArchType> CCCClangArchs; /// Certain options suppress the 'no input files' warning. bool SuppressMissingInputWarning : 1; - + std::list<std::string> TempFiles; std::list<std::string> ResultFiles; @@ -111,7 +115,7 @@ public: Driver(const char *_Name, const char *_Dir, const char *_DefaultHostTriple, const char *_DefaultImageName, - Diagnostic &_Diags); + bool IsProduction, Diagnostic &_Diags); ~Driver(); /// @name Accessors @@ -185,14 +189,15 @@ public: void PrintOptions(const ArgList &Args) const; /// PrintVersion - Print the driver version. - void PrintVersion(const Compilation &C) const; + void PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const; /// GetFilePath - Lookup \arg Name in the list of file search paths. /// /// \arg TC - The tool chain for additional information on /// directories to search. + // // FIXME: This should be in CompilationInfo. - llvm::sys::Path GetFilePath(const char *Name, const ToolChain &TC) const; + std::string GetFilePath(const char *Name, const ToolChain &TC) const; /// GetProgramPath - Lookup \arg Name in the list of program search /// paths. @@ -202,9 +207,10 @@ public: /// /// \arg WantFile - False when searching for an executable file, otherwise /// true. Defaults to false. + // // FIXME: This should be in CompilationInfo. - llvm::sys::Path GetProgramPath(const char *Name, const ToolChain &TC, - bool WantFile = false) const; + std::string GetProgramPath(const char *Name, const ToolChain &TC, + bool WantFile = false) const; /// HandleImmediateArgs - Handle any arguments which should be /// treated before building actions or binding tools. @@ -225,6 +231,7 @@ public: void BuildJobsForAction(Compilation &C, const Action *A, const ToolChain *TC, + const char *BoundArch, bool CanAcceptPipe, bool AtTopLevel, const char *LinkingOutput, @@ -239,7 +246,7 @@ public: /// \param BaseInput - The original input file that this action was /// triggered by. /// \param AtTopLevel - Whether this is a "top-level" action. - const char *GetNamedOutputPath(Compilation &C, + const char *GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, bool AtTopLevel) const; @@ -249,15 +256,15 @@ public: /// /// GCC goes to extra lengths here to be a bit more robust. std::string GetTemporaryPath(const char *Suffix) const; - + /// GetHostInfo - Construct a new host info object for the given /// host triple. const HostInfo *GetHostInfo(const char *HostTriple) const; /// ShouldUseClangCompilar - Should the clang compiler be used to /// handle this action. - bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, - const std::string &ArchName) const; + bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, + const llvm::Triple &ArchName) const; /// @} @@ -268,7 +275,7 @@ public: /// \return True if the entire string was parsed (9.2), or all /// groups were parsed (10.3.5extrastuff). HadExtra is true if all /// groups were parsed but extra characters remain at the end. - static bool GetReleaseVersion(const char *Str, unsigned &Major, + static bool GetReleaseVersion(const char *Str, unsigned &Major, unsigned &Minor, unsigned &Micro, bool &HadExtra); }; diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h index 705c3422cda3..d4a9da7b6d80 100644 --- a/include/clang/Driver/DriverDiagnostic.h +++ b/include/clang/Driver/DriverDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define DRIVERSTART diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h index b5e80b0c3bfe..bf67c343f326 100644 --- a/include/clang/Driver/HostInfo.h +++ b/include/clang/Driver/HostInfo.h @@ -20,13 +20,13 @@ namespace driver { class Driver; class ToolChain; -/// HostInfo - Config information about a particular host which may -/// interact with driver behavior. -/// -/// The host information is used for controlling the parts of the -/// driver which interact with the platform the driver is ostensibly -/// being run from. For testing purposes, the HostInfo used by the -/// driver may differ from the actual host. +/// HostInfo - Config information about a particular host which may interact +/// with driver behavior. +/// +/// The host information is used for controlling the parts of the driver which +/// interact with the platform the driver is ostensibly being run from. For +/// testing purposes, the HostInfo used by the driver may differ from the actual +/// host. class HostInfo { protected: const Driver &TheDriver; @@ -38,46 +38,49 @@ public: virtual ~HostInfo(); const Driver &getDriver() const { return TheDriver; } - + const llvm::Triple& getTriple() const { return Triple; } std::string getArchName() const { return Triple.getArchName(); } std::string getPlatformName() const { return Triple.getVendorName(); } std::string getOSName() const { return Triple.getOSName(); } - /// useDriverDriver - Whether the driver should act as a driver - /// driver for this host and support -arch, -Xarch, etc. + /// useDriverDriver - Whether the driver should act as a driver driver for + /// this host and support -arch, -Xarch, etc. virtual bool useDriverDriver() const = 0; - /// lookupTypeForExtension - Return the default language type to use - /// for the given extension. + /// lookupTypeForExtension - Return the default language type to use for the + /// given extension. virtual types::ID lookupTypeForExtension(const char *Ext) const = 0; - /// getToolChain - Construct the toolchain to use for this host. + /// CreateToolChain - Construct the toolchain to use for this host (which the + /// host retains ownership of). /// - /// \param Args - The argument list, which may be used to alter the - /// default toolchain, for example in the presence of -m32 or -m64. + /// \param Args - The argument list, which may be used to alter the default + /// toolchain, for example in the presence of -m32 or -m64. /// - /// \param ArchName - The architecture to return a toolchain for, or - /// 0 if unspecified. This will only ever be non-zero for hosts - /// which support a driver driver. + /// \param ArchName - The architecture to return a toolchain for, or 0 if + /// unspecified. This will only ever be non-zero for hosts which support a + /// driver driver. // FIXME: Pin down exactly what the HostInfo is allowed to use Args // for here. Currently this is for -m32 / -m64 defaulting. - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName=0) const = 0; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName=0) const = 0; }; -const HostInfo *createDarwinHostInfo(const Driver &D, +const HostInfo *createAuroraUXHostInfo(const Driver &D, + const llvm::Triple& Triple); +const HostInfo *createDarwinHostInfo(const Driver &D, const llvm::Triple& Triple); -const HostInfo *createOpenBSDHostInfo(const Driver &D, +const HostInfo *createOpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple); -const HostInfo *createFreeBSDHostInfo(const Driver &D, +const HostInfo *createFreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple); -const HostInfo *createDragonFlyHostInfo(const Driver &D, +const HostInfo *createDragonFlyHostInfo(const Driver &D, const llvm::Triple& Triple); -const HostInfo *createLinuxHostInfo(const Driver &D, +const HostInfo *createLinuxHostInfo(const Driver &D, const llvm::Triple& Triple); -const HostInfo *createUnknownHostInfo(const Driver &D, +const HostInfo *createUnknownHostInfo(const Driver &D, const llvm::Triple& Triple); } // end namespace driver diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index a23babdbb31a..906d73128b7d 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -46,7 +46,7 @@ public: /// either a piped job or a job list. void addCommand(Command *C); - static bool classof(const Job *) { return true; } + static bool classof(const Job *) { return true; } }; /// Command - An executable path/name and argument vector to @@ -63,7 +63,7 @@ class Command : public Job { ArgStringList Arguments; public: - Command(const Action &_Source, const char *_Executable, + Command(const Action &_Source, const char *_Executable, const ArgStringList &_Arguments); /// getSource - Return the Action which caused the creation of this job. @@ -73,8 +73,8 @@ public: const ArgStringList &getArguments() const { return Arguments; } - static bool classof(const Job *J) { - return J->getKind() == CommandClass; + static bool classof(const Job *J) { + return J->getKind() == CommandClass; } static bool classof(const Command *) { return true; } }; @@ -97,15 +97,15 @@ public: void addCommand(Command *C) { Commands.push_back(C); } const list_type &getCommands() const { return Commands; } - + size_type size() const { return Commands.size(); } iterator begin() { return Commands.begin(); } const_iterator begin() const { return Commands.begin(); } iterator end() { return Commands.end(); } const_iterator end() const { return Commands.end(); } - static bool classof(const Job *J) { - return J->getKind() == PipedJobClass; + static bool classof(const Job *J) { + return J->getKind() == PipedJobClass; } static bool classof(const PipedJob *) { return true; } }; @@ -133,13 +133,13 @@ public: const_iterator begin() const { return Jobs.begin(); } iterator end() { return Jobs.end(); } const_iterator end() const { return Jobs.end(); } - - static bool classof(const Job *J) { - return J->getKind() == JobListClass; + + static bool classof(const Job *J) { + return J->getKind() == JobListClass; } static bool classof(const JobList *) { return true; } }; - + } // end namespace driver } // end namespace clang diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h index c59faef897ae..c70b6482167b 100644 --- a/include/clang/Driver/Option.h +++ b/include/clang/Driver/Option.h @@ -24,7 +24,7 @@ namespace driver { class Arg; class InputArgList; class OptionGroup; - + /// Option - Abstract representation for a single form of driver /// argument. /// @@ -57,10 +57,10 @@ namespace driver { options::ID ID; /// The option name. - const char *Name; + const char *Name; /// Group this option is a member of, if any. - const OptionGroup *Group; + const OptionGroup *Group; /// Option that this is an alias for, if any. const Option *Alias; @@ -70,7 +70,7 @@ namespace driver { /// Treat this option like a linker input? bool LinkerInput : 1; - + /// When rendering as an input, don't render the option. // FIXME: We should ditch the render/renderAsInput distinction. @@ -78,18 +78,18 @@ namespace driver { /// Always render this option as separate form its value. bool ForceSeparateRender : 1; - + /// Always render this option joined with its value. - bool ForceJoinedRender : 1; + bool ForceJoinedRender : 1; /// This option is only consumed by the driver. - bool DriverOption : 1; + bool DriverOption : 1; /// This option should not report argument unused errors. - bool NoArgumentUnused : 1; + bool NoArgumentUnused : 1; protected: - Option(OptionClass Kind, options::ID ID, const char *Name, + Option(OptionClass Kind, options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); public: virtual ~Option(); @@ -108,13 +108,13 @@ namespace driver { bool hasNoOptAsInput() const { return NoOptAsInput; } void setNoOptAsInput(bool Value) { NoOptAsInput = Value; } - + bool hasForceSeparateRender() const { return ForceSeparateRender; } void setForceSeparateRender(bool Value) { ForceSeparateRender = Value; } - + bool hasForceJoinedRender() const { return ForceJoinedRender; } void setForceJoinedRender(bool Value) { ForceJoinedRender = Value; } - + bool isDriverOption() const { return DriverOption; } void setDriverOption(bool Value) { DriverOption = Value; } @@ -125,7 +125,7 @@ namespace driver { /// getUnaliasedOption - Return the final option this option /// aliases (itself, if the option has no alias). - const Option *getUnaliasedOption() const { + const Option *getUnaliasedOption() const { if (Alias) return Alias->getUnaliasedOption(); return this; } @@ -149,12 +149,12 @@ namespace driver { /// Index to the position where argument parsing should resume /// (even if the argument is missing values). virtual Arg *accept(const InputArgList &Args, unsigned &Index) const = 0; - + void dump() const; static bool classof(const Option *) { return true; } }; - + /// OptionGroup - A set of options which are can be handled uniformly /// by the driver. class OptionGroup : public Option { @@ -163,14 +163,14 @@ namespace driver { virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::GroupClass; + static bool classof(const Option *O) { + return O->getKind() == Option::GroupClass; } static bool classof(const OptionGroup *) { return true; } }; - + // Dummy option classes. - + /// InputOption - Dummy option class for representing driver inputs. class InputOption : public Option { public: @@ -178,8 +178,8 @@ namespace driver { virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::InputClass; + static bool classof(const Option *O) { + return O->getKind() == Option::InputClass; } static bool classof(const InputOption *) { return true; } }; @@ -191,8 +191,8 @@ namespace driver { virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::UnknownClass; + static bool classof(const Option *O) { + return O->getKind() == Option::UnknownClass; } static bool classof(const UnknownOption *) { return true; } }; @@ -201,52 +201,52 @@ namespace driver { class FlagOption : public Option { public: - FlagOption(options::ID ID, const char *Name, const OptionGroup *Group, + FlagOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::FlagClass; + static bool classof(const Option *O) { + return O->getKind() == Option::FlagClass; } static bool classof(const FlagOption *) { return true; } }; class JoinedOption : public Option { public: - JoinedOption(options::ID ID, const char *Name, const OptionGroup *Group, + JoinedOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::JoinedClass; + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedClass; } static bool classof(const JoinedOption *) { return true; } }; class SeparateOption : public Option { public: - SeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, + SeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::SeparateClass; + static bool classof(const Option *O) { + return O->getKind() == Option::SeparateClass; } static bool classof(const SeparateOption *) { return true; } }; class CommaJoinedOption : public Option { public: - CommaJoinedOption(options::ID ID, const char *Name, + CommaJoinedOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::CommaJoinedClass; + static bool classof(const Option *O) { + return O->getKind() == Option::CommaJoinedClass; } static bool classof(const CommaJoinedOption *) { return true; } }; @@ -259,15 +259,15 @@ namespace driver { unsigned NumArgs; public: - MultiArgOption(options::ID ID, const char *Name, const OptionGroup *Group, + MultiArgOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias, unsigned NumArgs); unsigned getNumArgs() const { return NumArgs; } virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::MultiArgClass; + static bool classof(const Option *O) { + return O->getKind() == Option::MultiArgClass; } static bool classof(const MultiArgOption *) { return true; } }; @@ -276,13 +276,13 @@ namespace driver { /// prefixes its (non-empty) value, or is follwed by a value. class JoinedOrSeparateOption : public Option { public: - JoinedOrSeparateOption(options::ID ID, const char *Name, + JoinedOrSeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::JoinedOrSeparateClass; + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedOrSeparateClass; } static bool classof(const JoinedOrSeparateOption *) { return true; } }; @@ -291,13 +291,13 @@ namespace driver { /// value and is followed by another value. class JoinedAndSeparateOption : public Option { public: - JoinedAndSeparateOption(options::ID ID, const char *Name, + JoinedAndSeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; - static bool classof(const Option *O) { - return O->getKind() == Option::JoinedAndSeparateClass; + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedAndSeparateClass; } static bool classof(const JoinedAndSeparateOption *) { return true; } }; diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index af108a85ebdd..4084be6c0b42 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -223,6 +223,8 @@ OPTION("--print-prog-name", _print_prog_name, Separate, INVALID, print_prog_name OPTION("--print-search-dirs", _print_search_dirs, Flag, INVALID, print_search_dirs, "", 0, 0, 0) OPTION("--profile-blocks", _profile_blocks, Flag, INVALID, a, "", 0, 0, 0) OPTION("--profile", _profile, Flag, INVALID, p, "", 0, 0, 0) +OPTION("--relocatable-pch", _relocatable_pch, Flag, INVALID, INVALID, "", 0, + "Build a relocatable precompiled header", 0) OPTION("--resource=", _resource_EQ, Joined, INVALID, fcompile_resource_EQ, "", 0, 0, 0) OPTION("--resource", _resource, Separate, INVALID, fcompile_resource_EQ, "J", 0, 0, 0) OPTION("--save-temps", _save_temps, Flag, INVALID, save_temps, "", 0, 0, 0) @@ -322,6 +324,7 @@ OPTION("-Z", Z_Joined, Joined, INVALID, INVALID, "", 0, 0, 0) OPTION("-all_load", all__load, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-allowable_client", allowable__client, Separate, INVALID, INVALID, "", 0, 0, 0) OPTION("-ansi", ansi, Flag, a_Group, INVALID, "", 0, 0, 0) +OPTION("-arch_errors_fatal", arch__errors__fatal, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-arch", arch, Separate, INVALID, INVALID, "d", 0, 0, 0) OPTION("-a", a, Joined, a_Group, INVALID, "", 0, 0, 0) OPTION("-bind_at_load", bind__at__load, Flag, INVALID, INVALID, "", 0, 0, 0) @@ -351,6 +354,8 @@ OPTION("-dynamiclib", dynamiclib, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-dynamic", dynamic, Flag, INVALID, INVALID, "q", 0, 0, 0) OPTION("-d", d_Flag, Flag, d_Group, INVALID, "", 0, 0, 0) OPTION("-d", d_Joined, Joined, d_Group, INVALID, "", 0, 0, 0) +OPTION("-emit-ast", emit_ast, Flag, INVALID, INVALID, "", 0, + "Emit Clang AST files for source inputs", 0) OPTION("-emit-llvm", emit_llvm, Flag, INVALID, INVALID, "", 0, "Use the LLVM representation for assembler and object files", 0) OPTION("-exported_symbols_list", exported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0) @@ -365,12 +370,15 @@ OPTION("-fast", fast, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fasynchronous-unwind-tables", fasynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fblocks", fblocks, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fbootclasspath=", fbootclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fbuiltin-strcat", fbuiltin_strcat, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fbuiltin-strcpy", fbuiltin_strcpy, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fbuiltin", fbuiltin, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fclasspath=", fclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcolor-diagnostics", fcolor_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcommon", fcommon, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcompile-resource=", fcompile_resource_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fconstant-cfstrings", fconstant_cfstrings, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fconstant-string-class=", fconstant_string_class_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcreate-profile", fcreate_profile, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fdebug-pass-arguments", fdebug_pass_arguments, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fdebug-pass-structure", fdebug_pass_structure, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -404,6 +412,8 @@ OPTION("-fnested-functions", fnested_functions, Flag, f_Group, INVALID, "", 0, 0 OPTION("-fnext-runtime", fnext_runtime, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-asynchronous-unwind-tables", fno_asynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-blocks", fno_blocks, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-builtin-strcat", fno_builtin_strcat, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-builtin-strcpy", fno_builtin_strcpy, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-builtin", fno_builtin, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-caret-diagnostics", fno_caret_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-color-diagnostics", fno_color_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -413,11 +423,14 @@ OPTION("-fno-diagnostics-fixit-info", fno_diagnostics_fixit_info, Flag, f_Group, OPTION("-fno-diagnostics-show-option", fno_diagnostics_show_option, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-dollars-in-identifiers", fno_dollars_in_identifiers, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-eliminate-unused-debug-symbols", fno_eliminate_unused_debug_symbols, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-exceptions", fno_exceptions, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-inline-functions", fno_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-inline", fno_inline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-keep-inline-functions", fno_keep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-math-errno", fno_math_errno, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-omit-frame-pointer", fno_omit_frame_pointer, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-pascal-strings", fno_pascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-rtti", fno_rtti, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-show-column", fno_show_column, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-show-source-location", fno_show_source_location, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-stack-protector", fno_stack_protector, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -447,6 +460,7 @@ OPTION("-fpie", fpie, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fprofile-arcs", fprofile_arcs, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fprofile-generate", fprofile_generate, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-framework", framework, Separate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-frtti", frtti, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fshow-source-location", fshow_source_location, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fsigned-bitfields", fsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fsigned-char", fsigned_char, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -457,7 +471,6 @@ OPTION("-fsyntax-only", fsyntax_only, Flag, INVALID, INVALID, "d", 0, 0, 0) OPTION("-ftemplate-depth-", ftemplate_depth_, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fterminated-vtables", fterminated_vtables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-ftime-report", ftime_report, Flag, f_Group, INVALID, "", 0, 0, 0) -OPTION("-ftraditional", ftraditional, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-ftrapv", ftrapv, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-funit-at-a-time", funit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-funsigned-bitfields", funsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -497,10 +510,15 @@ OPTION("-m32", m32, Flag, m_Group, INVALID, "d", 0, 0, 0) OPTION("-m3dnowa", m3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-m3dnow", m3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-m64", m64, Flag, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-mabi=", mabi_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) OPTION("-march=", march_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-mcmodel=", mcmodel_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) OPTION("-mconstant-cfstrings", mconstant_cfstrings, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) +OPTION("-mcpu=", mcpu_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) OPTION("-mdynamic-no-pic", mdynamic_no_pic, Joined, m_Group, INVALID, "q", 0, 0, 0) OPTION("-mfix-and-continue", mfix_and_continue, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) +OPTION("-mfloat-abi=", mfloat_abi_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mhard-float", mhard_float, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-miphoneos-version-min=", miphoneos_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) OPTION("-mkernel", mkernel, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mllvm", mllvm, Separate, INVALID, INVALID, "", 0, 0, 0) @@ -519,6 +537,7 @@ OPTION("-mno-sse4a", mno_sse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0 OPTION("-mno-sse4", mno_sse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mno-sse", mno_sse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mno-ssse3", mno_ssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-thumb", mno_thumb, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mno-warn-nonportable-cfstrings", mno_warn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mpascal-strings", mpascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mred-zone", mred_zone, Flag, m_Group, INVALID, "", 0, 0, 0) @@ -529,6 +548,7 @@ OPTION("-msse4a", msse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-msse4", msse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-msse", msse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mssse3", mssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mthumb", mthumb, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mtune=", mtune_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) OPTION("-multi_module", multi__module, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-multiply_defined_unused", multiply__defined__unused, Separate, INVALID, INVALID, "", 0, 0, 0) @@ -546,6 +566,7 @@ OPTION("-nomultidefs", nomultidefs, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-noprebind", noprebind, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-noseglinkedit", noseglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostartfiles", nostartfiles, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nostdclanginc", nostdclanginc, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostdinc", nostdinc, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostdlib", nostdlib, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-object", object, Flag, INVALID, INVALID, "", 0, 0, 0) diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h index 8b959d369c0e..7fcaf3f497be 100644 --- a/include/clang/Driver/Options.h +++ b/include/clang/Driver/Options.h @@ -24,7 +24,7 @@ namespace options { #undef OPTION }; } - + class Arg; class InputArgList; class Option; @@ -36,7 +36,7 @@ namespace options { /// few options will be needed at runtime; the OptTable class /// maintains enough information to parse command lines without /// instantiating Options, while letting other parts of the driver - /// still use Option instances where convient. + /// still use Option instances where convient. class OptTable { /// The table of options which have been constructed, indexed by /// option::ID - 1. diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h index d8b37e9ead88..8a89f01e0f4b 100644 --- a/include/clang/Driver/Tool.h +++ b/include/clang/Driver/Tool.h @@ -22,7 +22,7 @@ namespace driver { class Job; class JobAction; class ToolChain; - + typedef llvm::SmallVector<InputInfo, 4> InputInfoList; /// Tool - Information on a specific compilation tool. @@ -57,9 +57,9 @@ public: /// linker, then this is the final output name of the linked image. virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const = 0; }; diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index c9d0ef197dae..b7630d8afdb8 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -68,18 +68,21 @@ public: // Tool access. - /// TranslateArgs - Create a new derived argument list for any - /// argument translations this ToolChain may wish to perform. - virtual DerivedArgList *TranslateArgs(InputArgList &Args) const = 0; + /// TranslateArgs - Create a new derived argument list for any argument + /// translations this ToolChain may wish to perform. + /// + /// \param BoundArch - The bound architecture name, or 0. + virtual DerivedArgList *TranslateArgs(InputArgList &Args, + const char *BoundArch) const = 0; /// SelectTool - Choose a tool to use to handle the action \arg JA. virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const = 0; // Helper methods - llvm::sys::Path GetFilePath(const Compilation &C, const char *Name) const; - llvm::sys::Path GetProgramPath(const Compilation &C, const char *Name, - bool WantFile = false) const; + std::string GetFilePath(const Compilation &C, const char *Name) const; + std::string GetProgramPath(const Compilation &C, const char *Name, + bool WantFile = false) const; // Platform defaults information diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index 8d24e5013fb0..e01a04c67ae1 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -67,8 +67,9 @@ TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u") TYPE("java", Java, INVALID, 0, "u") // Misc. -TYPE("llvm-asm", LLVMAsm, INVALID, "s", "") -TYPE("llvm-bc", LLVMBC, INVALID, "o", "") +TYPE("ast", AST, INVALID, "ast", "u") +TYPE("llvm-asm", LLVMAsm, INVALID, "s", "") +TYPE("llvm-bc", LLVMBC, INVALID, "o", "") TYPE("plist", Plist, INVALID, "plist", "") TYPE("precompiled-header", PCH, INVALID, "gch", "A") TYPE("object", Object, INVALID, "o", "") diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index be4520262558..f59a0a7d481e 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -14,11 +14,10 @@ #ifndef DRIVER_ASTCONSUMERS_H #define DRIVER_ASTCONSUMERS_H -#include "llvm/Support/raw_ostream.h" #include <string> -#include <iosfwd> namespace llvm { + class raw_ostream; class Module; class LLVMContext; namespace sys { class Path; } @@ -30,20 +29,20 @@ class Diagnostic; class FileManager; class Preprocessor; class PreprocessorFactory; -struct CompileOptions; +class CompileOptions; class LangOptions; // AST pretty-printer: prints out the AST in a format that is close to the // original C code. The output is intended to be in a format such that // clang could re-parse the output back into the same AST, but the // implementation is still incomplete. -ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS); +ASTConsumer *CreateASTPrinter(llvm::raw_ostream *OS); -// AST XML-printer: prints out the AST in a XML format +// AST XML-printer: prints out the AST in a XML format // The output is intended to be in a format such that -// clang or any other tool could re-parse the output back into the same AST, +// clang or any other tool could re-parse the output back into the same AST, // but the implementation is still incomplete. -ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream* OS); +ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream *OS); // AST dumper: dumps the raw AST in human-readable form to stderr; this is // intended for debugging. @@ -58,10 +57,14 @@ ASTConsumer *CreateASTViewer(); // to stderr; this is intended for debugging. ASTConsumer *CreateDeclContextPrinter(); +// RecordLayout dumper: prints out the record layout information for all records +// in the translation unit; this is intended for debugging. +ASTConsumer *CreateRecordLayoutDumper(); + // ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code. // This is considered experimental, and only works with Apple's ObjC runtime. -ASTConsumer *CreateObjCRewriter(const std::string& InFile, - llvm::raw_ostream* OS, +ASTConsumer *CreateObjCRewriter(const std::string &InFile, + llvm::raw_ostream *OS, Diagnostic &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning); @@ -92,7 +95,8 @@ ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, // used later with the PCHReader (clang-cc option -include-pch) // to speed up compile times. ASTConsumer *CreatePCHGenerator(const Preprocessor &PP, - llvm::raw_ostream *OS); + llvm::raw_ostream *OS, + const char *isysroot = 0); // Block rewriter: rewrites code using the Apple blocks extension to pure // C code. Output is always sent to stdout. diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 68c06f5dcee6..89eb3b8821ca 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H #define LLVM_CLANG_FRONTEND_ASTUNIT_H +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/OwningPtr.h" #include <string> @@ -21,7 +22,6 @@ namespace clang { class FileManager; class FileEntry; class SourceManager; - class DiagnosticClient; class Diagnostic; class HeaderSearch; class TargetInfo; @@ -32,40 +32,49 @@ namespace clang { /// \brief Utility class for loading a ASTContext from a PCH file. /// class ASTUnit { - llvm::OwningPtr<SourceManager> SourceMgr; - llvm::OwningPtr<DiagnosticClient> DiagClient; - llvm::OwningPtr<Diagnostic> Diags; + Diagnostic &Diags; + SourceManager SourceMgr; llvm::OwningPtr<HeaderSearch> HeaderInfo; llvm::OwningPtr<TargetInfo> Target; llvm::OwningPtr<Preprocessor> PP; llvm::OwningPtr<ASTContext> Ctx; - ASTUnit(const ASTUnit&); // do not implement - ASTUnit &operator=(const ASTUnit &); // do not implement - ASTUnit(); - + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT + ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT + ASTUnit(Diagnostic &_Diag); + public: ~ASTUnit(); - const SourceManager &getSourceManager() const { return *SourceMgr.get(); } - SourceManager &getSourceManager() { return *SourceMgr.get(); } + const SourceManager &getSourceManager() const { return SourceMgr; } + SourceManager &getSourceManager() { return SourceMgr; } const Preprocessor &getPreprocessor() const { return *PP.get(); } Preprocessor &getPreprocessor() { return *PP.get(); } - + const ASTContext &getASTContext() const { return *Ctx.get(); } ASTContext &getASTContext() { return *Ctx.get(); } + const Diagnostic &getDiagnostic() const { return Diags; } + Diagnostic &getDiagnostic() { return Diags; } + + FileManager &getFileManager(); + const std::string &getOriginalSourceFileName(); + /// \brief Create a ASTUnit from a PCH file. /// - /// \param Filename PCH filename + /// \param Filename - The PCH file to load. + /// + /// \param Diags - The Diagnostic implementation to use. /// - /// \param FileMgr The FileManager to use + /// \param FileMgr - The FileManager to use. /// - /// \param ErrMsg Error message to report if the PCH file could not be loaded + /// \param ErrMsg - Error message to report if the PCH file could not be + /// loaded. /// - /// \returns the initialized ASTUnit or NULL if the PCH failed to load + /// \returns - The initialized ASTUnit or null if the PCH failed to load. static ASTUnit *LoadFromPCHFile(const std::string &Filename, + Diagnostic &Diags, FileManager &FileMgr, std::string *ErrMsg = 0); }; diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index ad799c3a8b25..d5e408020a98 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -24,6 +24,10 @@ ANALYSIS(CFGView, "cfg-view", ANALYSIS(DisplayLiveVariables, "dump-live-variables", "Print results of live variable analysis", Code) +ANALYSIS(SecuritySyntacticChecks, "warn-security-syntactic", + "Perform quick security checks that require no data flow", + Code) + ANALYSIS(WarnDeadStores, "warn-dead-stores", "Warn about stores to dead variables", Code) @@ -44,6 +48,10 @@ ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars", ANALYSIS(CheckerCFRef, "checker-cfref", "Run the [Core] Foundation reference count checker", Code) +ANALYSIS(InlineCall, "inline-call", + "Experimental transfer function inling callees when its definition" + " is available.", TranslationUnit) + #ifndef ANALYSIS_STORE #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif @@ -64,6 +72,7 @@ ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of conc ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", CreateHTMLDiagnosticClient, false) ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", CreatePlistDiagnosticClient, true) +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", CreatePlistHTMLDiagnosticClient, true) #undef ANALYSIS #undef ANALYSIS_STORE diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h index 1eaa958995f5..59f70ede9129 100644 --- a/include/clang/Frontend/CommandLineSourceLoc.h +++ b/include/clang/Frontend/CommandLineSourceLoc.h @@ -34,46 +34,45 @@ namespace llvm { /// /// Source locations are of the form filename:line:column. template<> - class parser<clang::ParsedSourceLocation> + class parser<clang::ParsedSourceLocation> : public basic_parser<clang::ParsedSourceLocation> { public: - bool parse(Option &O, const char *ArgName, - const std::string &ArgValue, + bool parse(Option &O, StringRef ArgName, StringRef ArgValue, clang::ParsedSourceLocation &Val); }; - bool + bool parser<clang::ParsedSourceLocation>:: - parse(Option &O, const char *ArgName, const std::string &ArgValue, + parse(Option &O, StringRef ArgName, StringRef ArgValue, clang::ParsedSourceLocation &Val) { using namespace clang; - const char *ExpectedFormat + const char *ExpectedFormat = "source location must be of the form filename:line:column"; - std::string::size_type SecondColon = ArgValue.rfind(':'); + StringRef::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()) { + + unsigned Column; + if (ArgValue.substr(SecondColon + 1).getAsInteger(10, Column)) { std::fprintf(stderr, "%s\n", ExpectedFormat); return true; } + ArgValue = ArgValue.substr(0, SecondColon); - std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1); + StringRef::size_type FirstColon = ArgValue.rfind(':'); 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) { + unsigned Line; + if (ArgValue.substr(FirstColon + 1).getAsInteger(10, Line)) { std::fprintf(stderr, "%s\n", ExpectedFormat); return true; } - + Val.FileName = ArgValue.substr(0, FirstColon); Val.Line = Line; Val.Column = Column; diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h index 75dec00f747f..508af537b1fa 100644 --- a/include/clang/Frontend/CompileOptions.h +++ b/include/clang/Frontend/CompileOptions.h @@ -67,7 +67,7 @@ public: Inlining = NoInlining; DisableRedZone = 0; NoImplicitFloat = 0; - } + } }; } // end namespace clang diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index 956d9719f9f4..36323c260c9a 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -91,8 +91,8 @@ NODE_XML(FunctionDecl, "Function") ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") - TYPE_ATTRIBUTE_XML(getType()->getAsFunctionType()->getResultType()) - ATTRIBUTE_XML(getType()->getAsFunctionType(), "function_type") + TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) + ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") ATTRIBUTE_ENUM_OPT_XML(getStorageClass(), "storage_class") ENUM_XML(FunctionDecl::None, "") ENUM_XML(FunctionDecl::Extern, "extern") @@ -111,8 +111,8 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl") ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") - TYPE_ATTRIBUTE_XML(getType()->getAsFunctionType()->getResultType()) - ATTRIBUTE_XML(getType()->getAsFunctionType(), "function_type") + TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) + ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") ATTRIBUTE_OPT_XML(isInline(), "inline") ATTRIBUTE_OPT_XML(isStatic(), "static") ATTRIBUTE_OPT_XML(isVirtual(), "virtual") diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h index 4ed11e153ce3..6693ddbac57d 100644 --- a/include/clang/Frontend/DocumentXML.h +++ b/include/clang/Frontend/DocumentXML.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the XML document class, which provides the means to +// This file implements the XML document class, which provides the means to // dump out the AST in a XML form that exposes type details and other fields. // //===----------------------------------------------------------------------===// @@ -32,10 +32,9 @@ class NamedDecl; class FunctionDecl; class ASTContext; class LabelStmt; - -//--------------------------------------------------------- -namespace XML -{ + +//--------------------------------------------------------- +namespace XML { // id maps: template<class T> struct IdMap : llvm::DenseMap<T, unsigned> {}; @@ -47,9 +46,8 @@ namespace XML struct IdMap<std::string> : std::map<std::string, unsigned> {}; } -//--------------------------------------------------------- -class DocumentXML -{ +//--------------------------------------------------------- +class DocumentXML { public: DocumentXML(const std::string& rootName, llvm::raw_ostream& out); @@ -62,24 +60,22 @@ public: DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this DocumentXML& toParent(); // returns *this - void addAttribute(const char* pName, const QualType& pType); + void addAttribute(const char* pName, const QualType& pType); void addAttribute(const char* pName, bool value); template<class T> - void addAttribute(const char* pName, const T* value) - { + void addAttribute(const char* pName, const T* value) { addPtrAttribute(pName, value); } template<class T> - void addAttribute(const char* pName, T* value) - { + void addAttribute(const char* pName, T* value) { addPtrAttribute(pName, value); } template<class T> void addAttribute(const char* pName, const T& value); - + template<class T> void addAttributeOptional(const char* pName, const T& value); @@ -114,7 +110,7 @@ private: void Indent(); // forced pointer dispatch: - void addPtrAttribute(const char* pName, const Type* pType); + void addPtrAttribute(const char* pName, const Type* pType); void addPtrAttribute(const char* pName, const NamedDecl* D); void addPtrAttribute(const char* pName, const DeclContext* D); void addPtrAttribute(const char* pName, const NamespaceDecl* D); // disambiguation @@ -136,47 +132,43 @@ private: // for addAttributeOptional: static bool isDefault(unsigned value) { return value == 0; } static bool isDefault(bool value) { return !value; } + static bool isDefault(Qualifiers::GC value) { return value == Qualifiers::GCNone; } static bool isDefault(const std::string& value) { return value.empty(); } }; //--------------------------------------------------------- inlines -inline void DocumentXML::initialize(ASTContext &Context) -{ - Ctx = &Context; +inline void DocumentXML::initialize(ASTContext &Context) { + Ctx = &Context; } -//--------------------------------------------------------- +//--------------------------------------------------------- template<class T> -inline void DocumentXML::addAttribute(const char* pName, const T& value) -{ +inline void DocumentXML::addAttribute(const char* pName, const T& value) { Out << ' ' << pName << "=\"" << value << "\""; } -//--------------------------------------------------------- -inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) -{ +//--------------------------------------------------------- +inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) { Out << ' ' << pName << "=\"" << text << "\""; } -//--------------------------------------------------------- -inline void DocumentXML::addAttribute(const char* pName, bool value) -{ +//--------------------------------------------------------- +inline void DocumentXML::addAttribute(const char* pName, bool value) { addPtrAttribute(pName, value ? "1" : "0"); } -//--------------------------------------------------------- +//--------------------------------------------------------- template<class T> -inline void DocumentXML::addAttributeOptional(const char* pName, const T& value) -{ - if (!isDefault(value)) - { +inline void DocumentXML::addAttributeOptional(const char* pName, + const T& value) { + if (!isDefault(value)) { addAttribute(pName, value); } } -//--------------------------------------------------------- +//--------------------------------------------------------- -} //namespace clang +} //namespace clang #endif //LLVM_CLANG_DOCUMENTXML_H diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h index 7fcd682bf66c..fac87afadef2 100644 --- a/include/clang/Frontend/FixItRewriter.h +++ b/include/clang/Frontend/FixItRewriter.h @@ -51,7 +51,7 @@ class FixItRewriter : public DiagnosticClient { unsigned NumFailures; /// \brief Locations at which we should perform fix-its. - /// + /// /// When empty, perform fix-it modifications everywhere. llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations; @@ -72,7 +72,7 @@ public: /// \brief Write the modified source file. /// /// \returns true if there was an error, false otherwise. - bool WriteFixedFile(const std::string &InFileName, + bool WriteFixedFile(const std::string &InFileName, const std::string &OutFileName = std::string()); /// IncludeInDiagnosticCounts - This method (whose default implementation diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h index 079abae3eee1..a044586a8c0a 100644 --- a/include/clang/Frontend/FrontendDiagnostic.h +++ b/include/clang/Frontend/FrontendDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define FRONTENDSTART diff --git a/include/clang/Frontend/InitHeaderSearch.h b/include/clang/Frontend/InitHeaderSearch.h index 51516661c99e..a90b4eaf9e2b 100644 --- a/include/clang/Frontend/InitHeaderSearch.h +++ b/include/clang/Frontend/InitHeaderSearch.h @@ -14,11 +14,12 @@ #ifndef LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_ #define LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_ +#include "clang/Lex/DirectoryLookup.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" #include <string> #include <vector> -#include "clang/Lex/DirectoryLookup.h" - namespace clang { class HeaderSearch; @@ -48,7 +49,7 @@ public: : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} /// AddPath - Add the specified path to the specified group list. - void AddPath(const std::string &Path, IncludeDirGroup Group, + void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); @@ -56,13 +57,26 @@ public: /// header search list. void AddEnvVarPaths(const char *Name); + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu + /// libstdc++. + void AddGnuCPlusPlusIncludePaths(const std::string &Base, const char *Dir32, + const char *Dir64, + const llvm::Triple &triple); + + /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW + /// libstdc++. + void AddMinGWCPlusPlusIncludePaths(const std::string &Base, + const char *Arch, + const char *Version); + /// AddDefaultEnvVarPaths - Adds list of paths from default environment /// variables such as CPATH. void AddDefaultEnvVarPaths(const LangOptions &Lang); /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. - void AddDefaultSystemIncludePaths(const LangOptions &Lang); + void AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. diff --git a/include/clang/Frontend/ManagerRegistry.h b/include/clang/Frontend/ManagerRegistry.h index ecab67a3b676..f05cfe6df6b8 100644 --- a/include/clang/Frontend/ManagerRegistry.h +++ b/include/clang/Frontend/ManagerRegistry.h @@ -43,7 +43,7 @@ public: class RegisterConstraintManager { public: RegisterConstraintManager(ConstraintManagerCreator CMC) { - assert(ManagerRegistry::ConstraintMgrCreator == 0 + assert(ManagerRegistry::ConstraintMgrCreator == 0 && "ConstraintMgrCreator already set!"); ManagerRegistry::ConstraintMgrCreator = CMC; } diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 80aa248a78e6..716780e68a52 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -29,7 +29,11 @@ namespace clang { /// incompatible with previous versions (such that a reader /// designed for the previous version could not support reading /// the new version), this number should be increased. - const unsigned VERSION_MAJOR = 1; + /// + /// Version 3 of PCH files also requires that the Subversion branch and + /// revision match exactly, since there is no backward compatibility of + /// PCH files at this time. + const unsigned VERSION_MAJOR = 3; /// \brief PCH minor version number supported by this version of /// Clang. @@ -65,7 +69,7 @@ namespace clang { typedef uint32_t IdentID; typedef uint32_t SelectorID; - + /// \brief Describes the various kinds of blocks that occur within /// a PCH file. enum BlockIDs { @@ -106,7 +110,7 @@ namespace clang { /// TYPE_OFFSET block to determine the offset of that type's /// corresponding record within the TYPES_BLOCK_ID block. TYPE_OFFSET = 1, - + /// \brief Record code for the offsets of each decl. /// /// The DECL_OFFSET constant describes the record that occurs @@ -182,7 +186,7 @@ namespace clang { /// \brief Record code for the array of locally-scoped external /// declarations. LOCALLY_SCOPED_EXTERNAL_DECLS = 11, - + /// \brief Record code for the table of offsets into the /// Objective-C method pool. SELECTOR_OFFSETS = 12, @@ -212,17 +216,17 @@ namespace clang { /// \brief Record code for the set of ext_vector type names. EXT_VECTOR_DECLS = 18, - /// \brief Record code for the set of Objective-C category - /// implementations. - OBJC_CATEGORY_IMPLEMENTATIONS = 19, - /// \brief Record code for the original file that was used to /// generate the precompiled header. - ORIGINAL_FILE_NAME = 20, - + ORIGINAL_FILE_NAME = 19, + /// \brief Record code for the sorted array of source ranges where /// comments were encountered in the source code. - COMMENT_RANGES = 21 + COMMENT_RANGES = 20, + + /// \brief Record code for the Subversion branch and revision information + /// of the compiler used to build this PCH file. + SVN_BRANCH_REVISION = 21 }; /// \brief Record types used within a source manager block. @@ -247,7 +251,7 @@ namespace clang { /// ControllingMacro is optional. SM_HEADER_FILE_INFO = 6 }; - + /// \brief Record types used within a preprocessor block. enum PreprocessorRecordTypes { // The macros in the PP section are a PP_MACRO_* instance followed by a @@ -261,7 +265,7 @@ namespace clang { /// [PP_MACRO_FUNCTION_LIKE, <ObjectLikeStuff>, IsC99Varargs, IsGNUVarars, /// NumArgs, ArgIdentInfoID* ] PP_MACRO_FUNCTION_LIKE = 2, - + /// \brief Describes one token. /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] PP_TOKEN = 3 @@ -329,7 +333,15 @@ namespace clang { /// \brief The '__int128_t' type. PREDEF_TYPE_INT128_ID = 22, /// \brief The type of 'nullptr'. - PREDEF_TYPE_NULLPTR_ID = 23 + PREDEF_TYPE_NULLPTR_ID = 23, + /// \brief The C++ 'char16_t' type. + PREDEF_TYPE_CHAR16_ID = 24, + /// \brief The C++ 'char32_t' type. + PREDEF_TYPE_CHAR32_ID = 25, + /// \brief The ObjC 'id' type. + PREDEF_TYPE_OBJC_ID = 26, + /// \brief The ObjC 'Class' type. + PREDEF_TYPE_OBJC_CLASS = 27 }; /// \brief The number of predefined type IDs that are reserved for @@ -388,12 +400,18 @@ namespace clang { TYPE_ENUM = 20, /// \brief An ObjCInterfaceType record. TYPE_OBJC_INTERFACE = 21, - /// \brief An ObjCQualifiedInterfaceType record. - TYPE_OBJC_QUALIFIED_INTERFACE = 22, /// \brief An ObjCObjectPointerType record. - TYPE_OBJC_OBJECT_POINTER = 23, + TYPE_OBJC_OBJECT_POINTER = 22, + /// \brief An ObjCProtocolListType record. + TYPE_OBJC_PROTOCOL_LIST = 23, /// \brief a DecltypeType record. - TYPE_DECLTYPE = 24 + TYPE_DECLTYPE = 24, + /// \brief A ConstantArrayWithExprType record. + TYPE_CONSTANT_ARRAY_WITH_EXPR = 25, + /// \brief A ConstantArrayWithoutExprType record. + TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 26, + /// \brief An ElaboratedType record. + TYPE_ELABORATED = 27 }; /// \brief The type IDs for special types constructed by semantic @@ -415,7 +433,17 @@ namespace clang { /// \brief CFConstantString type SPECIAL_TYPE_CF_CONSTANT_STRING = 5, /// \brief Objective-C fast enumeration state type - SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6 + SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6, + /// \brief C FILE typedef type + SPECIAL_TYPE_FILE = 7, + /// \brief C jmp_buf typedef type + SPECIAL_TYPE_jmp_buf = 8, + /// \brief C sigjmp_buf typedef type + SPECIAL_TYPE_sigjmp_buf = 9, + /// \brief Objective-C "id" redefinition type + SPECIAL_TYPE_OBJC_ID_REDEFINITION = 10, + /// \brief Objective-C "Class" redefinition type + SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 11 }; /// \brief Record codes for each kind of declaration. @@ -611,7 +639,7 @@ namespace clang { EXPR_BLOCK_DECL_REF, // Objective-C - + /// \brief An ObjCStringLiteral record. EXPR_OBJC_STRING_LITERAL, /// \brief An ObjCEncodeExpr record. @@ -624,25 +652,34 @@ namespace clang { EXPR_OBJC_IVAR_REF_EXPR, /// \brief An ObjCPropertyRefExpr record. EXPR_OBJC_PROPERTY_REF_EXPR, - /// \brief An ObjCKVCRefExpr record. + /// \brief An ObjCImplicitSetterGetterRefExpr record. EXPR_OBJC_KVC_REF_EXPR, /// \brief An ObjCMessageExpr record. EXPR_OBJC_MESSAGE_EXPR, /// \brief An ObjCSuperExpr record. EXPR_OBJC_SUPER_EXPR, + /// \brief An ObjCIsa Expr record. + EXPR_OBJC_ISA, - /// \brief An ObjCForCollectionStmt record. + /// \brief An ObjCForCollectionStmt record. STMT_OBJC_FOR_COLLECTION, - /// \brief An ObjCAtCatchStmt record. + /// \brief An ObjCAtCatchStmt record. STMT_OBJC_CATCH, - /// \brief An ObjCAtFinallyStmt record. + /// \brief An ObjCAtFinallyStmt record. STMT_OBJC_FINALLY, - /// \brief An ObjCAtTryStmt record. + /// \brief An ObjCAtTryStmt record. STMT_OBJC_AT_TRY, - /// \brief An ObjCAtSynchronizedStmt record. + /// \brief An ObjCAtSynchronizedStmt record. STMT_OBJC_AT_SYNCHRONIZED, - /// \brief An ObjCAtThrowStmt record. - STMT_OBJC_AT_THROW + /// \brief An ObjCAtThrowStmt record. + STMT_OBJC_AT_THROW, + + // C++ + + /// \brief A CXXOperatorCallExpr record. + EXPR_CXX_OPERATOR_CALL, + /// \brief A CXXConstructExpr record. + EXPR_CXX_CONSTRUCT }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 8291f4697a8e..1230e3753e04 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -30,6 +30,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/DataTypes.h" +#include <deque> #include <map> #include <string> #include <utility> @@ -54,7 +55,7 @@ class Preprocessor; class Sema; class SwitchCase; class PCHReader; -class HeaderFileInfo; +struct HeaderFileInfo; /// \brief Abstract interface for callback invocations by the PCHReader. /// @@ -65,21 +66,21 @@ class HeaderFileInfo; class PCHReaderListener { public: virtual ~PCHReaderListener(); - + /// \brief Receives the language options. /// /// \returns true to indicate the options are invalid or false otherwise. virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { return false; } - + /// \brief Receives the target triple. /// /// \returns true to indicate the target triple is invalid or false otherwise. virtual bool ReadTargetTriple(const std::string &Triple) { return false; } - + /// \brief Receives the contents of the predefines buffer. /// /// \param PCHPredef The start of the predefines buffer in the PCH @@ -94,16 +95,16 @@ public: /// here. /// /// \returns true to indicate the predefines are invalid or false otherwise. - virtual bool ReadPredefinesBuffer(const char *PCHPredef, + virtual bool ReadPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, FileID PCHBufferID, std::string &SuggestedPredefines) { return false; } - + /// \brief Receives a HeaderFileInfo entry. virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {} - + /// \brief Receives __COUNTER__ value. virtual void ReadCounter(unsigned Value) {} }; @@ -113,16 +114,16 @@ public: class PCHValidator : public PCHReaderListener { Preprocessor &PP; PCHReader &Reader; - + unsigned NumHeaderInfos; - + public: PCHValidator(Preprocessor &PP, PCHReader &Reader) : PP(PP), Reader(Reader), NumHeaderInfos(0) {} - + virtual bool ReadLanguageOptions(const LangOptions &LangOpts); virtual bool ReadTargetTriple(const std::string &Triple); - virtual bool ReadPredefinesBuffer(const char *PCHPredef, + virtual bool ReadPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, FileID PCHBufferID, std::string &SuggestedPredefines); @@ -142,8 +143,8 @@ public: /// The PCH reader provides lazy de-serialization of declarations, as /// required when traversing the AST. Only those AST nodes that are /// actually required will be de-serialized. -class PCHReader - : public ExternalSemaSource, +class PCHReader + : public ExternalSemaSource, public IdentifierInfoLookup, public ExternalIdentifierLookup, public ExternalSLocEntrySource { @@ -153,11 +154,11 @@ public: private: /// \ brief The receiver of some callbacks invoked by PCHReader. llvm::OwningPtr<PCHReaderListener> Listener; - + SourceManager &SourceMgr; FileManager &FileMgr; Diagnostic &Diags; - + /// \brief The semantic analysis object that will be processing the /// PCH file and the translation unit that uses it. Sema *SemaObj; @@ -202,10 +203,10 @@ private: const uint32_t *TypeOffsets; /// \brief Types that have already been loaded from the PCH file. - /// - /// When the pointer at index I is non-NULL, the type with + /// + /// When the pointer at index I is non-NULL, the type with /// ID = (I + 1) << 3 has already been loaded from the PCH file. - std::vector<Type *> TypesLoaded; + std::vector<QualType> TypesLoaded; /// \brief Offset of each declaration within the bitstream, indexed /// by the declaration ID (-1). @@ -272,7 +273,7 @@ private: /// \brief The total number of selectors stored in the PCH file. unsigned TotalNumSelectors; - /// \brief A vector containing selectors that have already been loaded. + /// \brief A vector containing selectors that have already been loaded. /// /// This vector is indexed by the Selector ID (-1). NULL selector /// entries indicate that the particular selector ID has not yet @@ -281,10 +282,10 @@ private: /// \brief A sorted array of source ranges containing comments. SourceRange *Comments; - + /// \brief The number of source ranges in the Comments array. unsigned NumComments; - + /// \brief The set of external definitions stored in the the PCH /// file. llvm::SmallVector<uint64_t, 16> ExternalDefinitions; @@ -309,6 +310,13 @@ private: /// file. std::string OriginalFileName; + /// \brief Whether this precompiled header is a relocatable PCH file. + bool RelocatablePCH; + + /// \brief The system include root to be used when loading the + /// precompiled header. + const char *isysroot; + /// \brief Mapping from switch-case IDs in the PCH file to /// switch-case statements. std::map<unsigned, SwitchCase *> SwitchCaseStmts; @@ -362,6 +370,40 @@ private: /// Number of visible decl contexts read/total. unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts; + /// \brief When a type or declaration is being loaded from the PCH file, an + /// instantance of this RAII object will be available on the stack to + /// indicate when we are in a recursive-loading situation. + class LoadingTypeOrDecl { + PCHReader &Reader; + LoadingTypeOrDecl *Parent; + + LoadingTypeOrDecl(const LoadingTypeOrDecl&); // do not implement + LoadingTypeOrDecl &operator=(const LoadingTypeOrDecl&); // do not implement + + public: + explicit LoadingTypeOrDecl(PCHReader &Reader); + ~LoadingTypeOrDecl(); + }; + friend class LoadingTypeOrDecl; + + /// \brief If we are currently loading a type or declaration, points to the + /// most recent LoadingTypeOrDecl object on the stack. + LoadingTypeOrDecl *CurrentlyLoadingTypeOrDecl; + + /// \brief An IdentifierInfo that has been loaded but whose top-level + /// declarations of the same name have not (yet) been loaded. + struct PendingIdentifierInfo { + IdentifierInfo *II; + llvm::SmallVector<uint32_t, 4> DeclIDs; + }; + + /// \brief The set of identifiers that were read while the PCH reader was + /// (recursively) loading declarations. + /// + /// The declarations on the identifier chain for these identifiers will be + /// loaded once the recursive loading has completed. + std::deque<PendingIdentifierInfo> PendingIdentifierInfos; + /// \brief FIXME: document! llvm::SmallVector<uint64_t, 4> SpecialTypes; @@ -392,14 +434,17 @@ private: /// there are differences that the PCH reader can work around, this /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; - + + void MaybeAddSystemRootToFilename(std::string &Filename); + PCHReadResult ReadPCHBlock(); - bool CheckPredefinesBuffer(const char *PCHPredef, + bool CheckPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, FileID PCHBufferID); + bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record); PCHReadResult ReadSourceManagerBlock(); PCHReadResult ReadSLocEntryRecord(unsigned ID); - + bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record); QualType ReadTypeRecord(uint64_t Offset); void LoadedDecl(unsigned Index, Decl *D); @@ -413,39 +458,62 @@ private: PCHReader(const PCHReader&); // do not implement PCHReader &operator=(const PCHReader &); // do not implement - public: typedef llvm::SmallVector<uint64_t, 64> RecordData; /// \brief Load the PCH file and validate its contents against the given /// Preprocessor. - PCHReader(Preprocessor &PP, ASTContext *Context); - + /// + /// \param PP the preprocessor associated with the context in which this + /// precompiled header will be loaded. + /// + /// \param Context the AST context that this precompiled header will be + /// loaded into. + /// + /// \param isysroot If non-NULL, the system include path specified by the + /// user. This is only used with relocatable PCH files. If non-NULL, + /// a relocatable PCH file will use the default path "/". + PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0); + /// \brief Load the PCH file without using any pre-initialized Preprocessor. /// /// The necessary information to initialize a Preprocessor later can be /// obtained by setting a PCHReaderListener. - PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags); + /// + /// \param SourceMgr the source manager into which the precompiled header + /// will be loaded. + /// + /// \param FileMgr the file manager into which the precompiled header will + /// be loaded. + /// + /// \param Diags the diagnostics system to use for reporting errors and + /// warnings relevant to loading the precompiled header. + /// + /// \param isysroot If non-NULL, the system include path specified by the + /// user. This is only used with relocatable PCH files. If non-NULL, + /// a relocatable PCH file will use the default path "/". + PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags, const char *isysroot = 0); ~PCHReader(); /// \brief Load the precompiled header designated by the given file /// name. PCHReadResult ReadPCH(const std::string &FileName); - + /// \brief Set the PCH callbacks listener. void setListener(PCHReaderListener *listener) { Listener.reset(listener); } - + /// \brief Set the Preprocessor to use. void setPreprocessor(Preprocessor &pp) { PP = &pp; } - + /// \brief Sets and initializes the given Context. void InitializeContext(ASTContext &Context); - /// \brief Retrieve the name of the original source file name + /// \brief Retrieve the name of the original source file name const std::string &getOriginalSourceFile() { return OriginalFileName; } /// \brief Retrieve the name of the original source file name @@ -465,7 +533,7 @@ public: /// replaced with the sorted set of source ranges corresponding to /// comments in the source code. virtual void ReadComments(std::vector<SourceRange> &Comments); - + /// \brief Resolve a type ID into a type, potentially building a new /// type. virtual QualType GetType(pch::TypeID ID); @@ -551,10 +619,13 @@ public: /// /// \returns a pair of Objective-C methods lists containing the /// instance and factory methods, respectively, with this selector. - virtual std::pair<ObjCMethodList, ObjCMethodList> + virtual std::pair<ObjCMethodList, ObjCMethodList> ReadMethodPool(Selector Sel); void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); + void SetGloballyVisibleDecls(IdentifierInfo *II, + const llvm::SmallVectorImpl<uint32_t> &DeclIDs, + bool Nonrecursive = false); /// \brief Report a diagnostic. DiagnosticBuilder Diag(unsigned DiagID); @@ -563,11 +634,11 @@ public: DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); IdentifierInfo *DecodeIdentifierInfo(unsigned Idx); - + IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) { return DecodeIdentifierInfo(Record[Idx++]); } - + virtual IdentifierInfo *GetIdentifier(unsigned ID) { return DecodeIdentifierInfo(ID); } @@ -576,7 +647,7 @@ public: virtual void ReadSLocEntry(unsigned ID); Selector DecodeSelector(unsigned Idx); - + Selector GetSelector(const RecordData &Record, unsigned &Idx) { return DecodeSelector(Record[Idx++]); } @@ -599,13 +670,13 @@ public: /// \brief ReadDeclExpr - Reads an expression from the current decl cursor. Expr *ReadDeclExpr(); - + /// \brief ReadTypeExpr - Reads an expression from the current type cursor. Expr *ReadTypeExpr(); /// \brief Reads a statement from the specified cursor. Stmt *ReadStmt(llvm::BitstreamCursor &Cursor); - + /// \brief Read a statement from the current DeclCursor. Stmt *ReadDeclStmt() { return ReadStmt(DeclsCursor); @@ -670,16 +741,16 @@ public: struct SavedStreamPosition { explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } - + ~SavedStreamPosition() { Cursor.JumpToBit(Offset); } - + private: llvm::BitstreamCursor &Cursor; uint64_t Offset; }; - + } // end namespace clang #endif diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index c663442e64d8..a807cd7c4d1f 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -40,6 +40,24 @@ class SourceManager; class SwitchCase; class TargetInfo; +/// A structure for putting "fast"-unqualified QualTypes into a +/// DenseMap. This uses the standard pointer hash function. +struct UnsafeQualTypeDenseMapInfo { + static inline bool isEqual(QualType A, QualType B) { return A == B; } + static inline bool isPod() { return true; } + static inline QualType getEmptyKey() { + return QualType::getFromOpaquePtr((void*) 1); + } + static inline QualType getTombstoneKey() { + return QualType::getFromOpaquePtr((void*) 2); + } + static inline unsigned getHashValue(QualType T) { + assert(!T.getFastQualifiers() && "hash invalid for types with fast quals"); + uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); + } +}; + /// \brief Writes a precompiled header containing the contents of a /// translation unit. /// @@ -76,9 +94,11 @@ private: /// /// The ID numbers of types are consecutive (in order of discovery) /// and start at 1. 0 is reserved for NULL. When types are actually - /// stored in the stream, the ID number is shifted by 3 bits to - /// allow for the const/volatile/restrict qualifiers. - llvm::DenseMap<const Type *, pch::TypeID> TypeIDs; + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + llvm::DenseMap<QualType, pch::TypeID, UnsafeQualTypeDenseMapInfo> TypeIDs; /// \brief Offset of each type in the bitstream, indexed by /// the type's ID. @@ -89,7 +109,7 @@ private: /// \brief Queue containing the types that we still need to /// emit. - std::queue<const Type *> TypesToEmit; + std::queue<QualType> TypesToEmit; /// \brief Map that provides the ID numbers of each identifier in /// the output stream. @@ -98,21 +118,21 @@ private: /// discovery), starting at 1. An ID of zero refers to a NULL /// IdentifierInfo. llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs; - + /// \brief Offsets of each of the identifier IDs into the identifier /// table. std::vector<uint32_t> IdentifierOffsets; /// \brief Map that provides the ID numbers of each Selector. llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs; - + /// \brief Offset of each selector within the method pool/selector /// table, indexed by the Selector ID (-1). std::vector<uint32_t> SelectorOffsets; /// \brief A vector of all Selectors (ordered by ID). std::vector<Selector> SelVector; - + /// \brief Offsets of each of the macro identifiers into the /// bitstream. /// @@ -141,7 +161,7 @@ private: /// \brief Mapping from SwitchCase statements to IDs. std::map<SwitchCase *, unsigned> SwitchCaseIDs; - + /// \brief Mapping from LabelStmt statements to IDs. std::map<LabelStmt *, unsigned> LabelIDs; @@ -160,18 +180,19 @@ private: unsigned NumVisibleDeclContexts; void WriteBlockInfoBlock(); - void WriteMetadata(ASTContext &Context); + void WriteMetadata(ASTContext &Context, const char *isysroot); void WriteLanguageOptions(const LangOptions &LangOpts); - void WriteStatCache(MemorizeStatCalls &StatCalls); - void WriteSourceManagerBlock(SourceManager &SourceMgr, - const Preprocessor &PP); + void WriteStatCache(MemorizeStatCalls &StatCalls, const char* isysroot); + void WriteSourceManagerBlock(SourceManager &SourceMgr, + const Preprocessor &PP, + const char* isysroot); void WritePreprocessor(const Preprocessor &PP); void WriteComments(ASTContext &Context); - void WriteType(const Type *T); + void WriteType(QualType T); void WriteTypesBlock(ASTContext &Context); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); - + void WriteDeclsBlock(ASTContext &Context); void WriteMethodPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP); @@ -179,14 +200,24 @@ private: unsigned ParmVarDeclAbbrev; void WriteDeclsBlockAbbrevs(); - + public: /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. PCHWriter(llvm::BitstreamWriter &Stream); - + /// \brief Write a precompiled header for the given semantic analysis. - void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls); + /// + /// \param SemaRef a reference to the semantic analysis object that processed + /// the AST to be written into the precompiled header. + /// + /// \param StatCalls the object that cached all of the stat() calls made while + /// searching for source files and headers. + /// + /// \param isysroot if non-NULL, write a relocatable PCH file whose headers + /// are relative to the given system root. + void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, + const char* isysroot); /// \brief Emit a source location. void AddSourceLocation(SourceLocation Loc, RecordData &Record); @@ -205,7 +236,7 @@ public: /// \brief Emit a Selector (which is a smart pointer reference) void AddSelectorRef(const Selector, RecordData &Record); - + /// \brief Get the unique number used to refer to the given /// identifier. pch::IdentID getIdentifierRef(const IdentifierInfo *II); @@ -215,7 +246,7 @@ public: /// /// The identifier must refer to a macro. uint64_t getMacroOffset(const IdentifierInfo *II) { - assert(MacroOffsets.find(II) != MacroOffsets.end() && + assert(MacroOffsets.find(II) != MacroOffsets.end() && "Identifier does not name a macro"); return MacroOffsets[II]; } diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h index 028cd8549272..8cb6898d7598 100644 --- a/include/clang/Frontend/PathDiagnosticClients.h +++ b/include/clang/Frontend/PathDiagnosticClients.h @@ -14,7 +14,9 @@ #ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H #define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H +#include <memory> #include <string> +#include "llvm/ADT/SmallVector.h" namespace clang { @@ -22,13 +24,31 @@ class PathDiagnosticClient; class Preprocessor; class PreprocessorFactory; -PathDiagnosticClient* CreateHTMLDiagnosticClient(const std::string& prefix, - Preprocessor* PP = 0, - PreprocessorFactory* PPF = 0); - -PathDiagnosticClient* CreatePlistDiagnosticClient(const std::string& prefix, - Preprocessor* PP, - PreprocessorFactory* PPF); -} +class PathDiagnosticClientFactory { +public: + PathDiagnosticClientFactory() {} + virtual ~PathDiagnosticClientFactory() {} + virtual const char *getName() const = 0; + + virtual PathDiagnosticClient* + createPathDiagnosticClient(llvm::SmallVectorImpl<std::string> *FilesMade) = 0; +}; + +PathDiagnosticClient* +CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP = 0, + PreprocessorFactory* PPF = 0, + llvm::SmallVectorImpl<std::string>* FilesMade = 0); + +PathDiagnosticClientFactory* +CreateHTMLDiagnosticClientFactory(const std::string& prefix, + Preprocessor* PP = 0, + PreprocessorFactory* PPF = 0); + +PathDiagnosticClient* +CreatePlistDiagnosticClient(const std::string& prefix, Preprocessor* PP, + PreprocessorFactory* PPF, + PathDiagnosticClientFactory *PF = 0); + +} // end clang namespace #endif diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def index 26430f740d91..fd79cf0c6ccb 100644 --- a/include/clang/Frontend/StmtXML.def +++ b/include/clang/Frontend/StmtXML.def @@ -78,6 +78,9 @@ # define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context") #endif +NODE_XML(Stmt, "Stmt_Unsupported") // fallback for unsupproted statements + ATTRIBUTE_FILE_LOCATION_XML +END_NODE_XML NODE_XML(NullStmt, "NullStmt") ATTRIBUTE_FILE_LOCATION_XML diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index f8408bdbd742..0fd8d44f72bc 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -52,7 +52,7 @@ public: unsigned messageLength = 0, bool useColors = false) : OS(os), LangOpts(0), - LastCaretDiagnosticWasNote(false), ShowColumn(showColumn), + LastCaretDiagnosticWasNote(false), ShowColumn(showColumn), CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation), PrintRangeInfo(printRangeInfo), PrintDiagnosticOption(printDiagnosticOption), @@ -63,7 +63,7 @@ public: void setLangOptions(const LangOptions *LO) { LangOpts = LO; } - + void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM); void HighlightRange(const SourceRange &R, @@ -72,13 +72,13 @@ public: std::string &CaretLine, const std::string &SourceLine); - void EmitCaretDiagnostic(SourceLocation Loc, + void EmitCaretDiagnostic(SourceLocation Loc, SourceRange *Ranges, unsigned NumRanges, SourceManager &SM, const CodeModificationHint *Hints, unsigned NumHints, unsigned Columns); - + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info); }; diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def index 2a78fd9f75b1..6aca15a75427 100644 --- a/include/clang/Frontend/TypeXML.def +++ b/include/clang/Frontend/TypeXML.def @@ -68,17 +68,8 @@ NODE_XML(QualType, "CvQualifiedType") ATTRIBUTE_OPT_XML(isConstQualified(), "const") // boolean ATTRIBUTE_OPT_XML(isVolatileQualified(), "volatile") // boolean ATTRIBUTE_OPT_XML(isRestrictQualified(), "restrict") // boolean -END_NODE_XML - -NODE_XML(ExtQualType, "ExtQualType") - ID_ATTRIBUTE_XML - TYPE_ATTRIBUTE_XML(getBaseType()) - ATTRIBUTE_OPT_XML(getAddressSpace(), "adress_space") // unsigned: Address Space ID - The address space ID this type is qualified with. - ATTRIBUTE_ENUM_OPT_XML(getObjCGCAttr(), "objc_gc") // GC __weak/__strong attributes - ENUM_XML(QualType::GCNone, "") - ENUM_XML(QualType::Weak, "weak") - ENUM_XML(QualType::Strong, "strong") - END_ENUM_XML + ATTRIBUTE_OPT_XML(getObjCGCAttr(), "objc_gc") // Qualifiers::GC + ATTRIBUTE_OPT_XML(getAddressSpace(), "address_space") // unsigned END_NODE_XML NODE_XML(BuiltinType, "FundamentalType") @@ -104,6 +95,8 @@ NODE_XML(BuiltinType, "FundamentalType") ENUM_XML(BuiltinType::Double, "double"); ENUM_XML(BuiltinType::LongDouble, "long double"); ENUM_XML(BuiltinType::WChar, "wchar_t"); + ENUM_XML(BuiltinType::Char16, "char16_t"); + ENUM_XML(BuiltinType::Char32, "char32_t"); ENUM_XML(BuiltinType::NullPtr, "nullptr_t"); // This is the type of C++0x 'nullptr'. ENUM_XML(BuiltinType::Overload, "overloaded"); ENUM_XML(BuiltinType::Dependent, "dependent"); @@ -173,7 +166,7 @@ NODE_XML(ConstantArrayType, "ArrayType") ENUM_XML(ArrayType::Static, "static") ENUM_XML(ArrayType::Star, "star") END_ENUM_XML - ATTRIBUTE_OPT_XML(getIndexTypeQualifier(), "index_type_qualifier") // unsigned + ATTRIBUTE_OPT_XML(getIndexTypeCVRQualifiers(), "index_type_qualifier") // unsigned END_NODE_XML NODE_XML(IncompleteArrayType, "IncompleteArrayType") @@ -254,10 +247,6 @@ NODE_XML(ObjCInterfaceType, "ObjCInterfaceType") ID_ATTRIBUTE_XML END_NODE_XML -NODE_XML(ObjCQualifiedInterfaceType, "ObjCQualifiedInterfaceType") - ID_ATTRIBUTE_XML -END_NODE_XML - NODE_XML(ObjCObjectPointerType, "ObjCObjectPointerType") ID_ATTRIBUTE_XML END_NODE_XML diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index 77df60cd7210..9cbcf8e3e93e 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -34,8 +34,6 @@ 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. @@ -59,7 +57,7 @@ void RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream* OS); /// RewriteMacrosInInput - A simple test for the TokenRewriter class. void DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS); - + /// CreatePrintParserActionsAction - Return the actions implementation that /// implements the -parse-print-callbacks option. MinimalAction *CreatePrintParserActionsAction(Preprocessor &PP, @@ -78,33 +76,6 @@ 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 diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h new file mode 100644 index 000000000000..9620ec5dbd4f --- /dev/null +++ b/include/clang/Index/ASTLocation.h @@ -0,0 +1,174 @@ +//===--- ASTLocation.h - A <Decl, Stmt> pair --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTLocation is Decl or a Stmt and its immediate Decl parent. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_ASTLOCATION_H +#define LLVM_CLANG_INDEX_ASTLOCATION_H + +#include "clang/AST/TypeLoc.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class Decl; + class Stmt; + class NamedDecl; + +namespace idx { + class TranslationUnit; + +/// \brief Represents a Decl or a Stmt and its immediate Decl parent. It's +/// immutable. +/// +/// ASTLocation is intended to be used as a "pointer" into the AST. It is either +/// just a Decl, or a Stmt and its Decl parent. Since a single Stmt is devoid +/// of context, its parent Decl provides all the additional missing information +/// like the declaration context, ASTContext, etc. +/// +class ASTLocation { +public: + enum NodeKind { + N_Decl, N_NamedRef, N_Stmt, N_Type + }; + + struct NamedRef { + NamedDecl *ND; + SourceLocation Loc; + + NamedRef() : ND(0) { } + NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { } + }; + +private: + llvm::PointerIntPair<Decl *, 2, NodeKind> ParentDecl; + + union { + Decl *D; + Stmt *Stm; + struct { + NamedDecl *ND; + unsigned RawLoc; + } NDRef; + struct { + void *TyPtr; + void *Data; + } Ty; + }; + +public: + ASTLocation() { } + + explicit ASTLocation(const Decl *d) + : ParentDecl(const_cast<Decl*>(d), N_Decl), D(const_cast<Decl*>(d)) { } + + ASTLocation(const Decl *parentDecl, const Stmt *stm) + : ParentDecl(const_cast<Decl*>(parentDecl), N_Stmt), + Stm(const_cast<Stmt*>(stm)) { + if (!stm) ParentDecl.setPointer(0); + } + + ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc) + : ParentDecl(const_cast<Decl*>(parentDecl), N_NamedRef) { + if (ndRef) { + NDRef.ND = ndRef; + NDRef.RawLoc = loc.getRawEncoding(); + } else + ParentDecl.setPointer(0); + } + + ASTLocation(const Decl *parentDecl, TypeLoc tyLoc) + : ParentDecl(const_cast<Decl*>(parentDecl), N_Type) { + if (tyLoc) { + Ty.TyPtr = tyLoc.getSourceType().getAsOpaquePtr(); + Ty.Data = tyLoc.getOpaqueData(); + } else + ParentDecl.setPointer(0); + } + + bool isValid() const { return ParentDecl.getPointer() != 0; } + bool isInvalid() const { return !isValid(); } + + NodeKind getKind() const { + assert(isValid()); + return (NodeKind)ParentDecl.getInt(); + } + + Decl *getParentDecl() const { return ParentDecl.getPointer(); } + + Decl *AsDecl() const { + assert(getKind() == N_Decl); + return D; + } + Stmt *AsStmt() const { + assert(getKind() == N_Stmt); + return Stm; + } + NamedRef AsNamedRef() const { + assert(getKind() == N_NamedRef); + return NamedRef(NDRef.ND, SourceLocation::getFromRawEncoding(NDRef.RawLoc)); + } + TypeLoc AsTypeLoc() const { + assert(getKind() == N_Type); + return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data); + } + + Decl *dyn_AsDecl() const { return getKind() == N_Decl ? D : 0; } + Stmt *dyn_AsStmt() const { return getKind() == N_Stmt ? Stm : 0; } + NamedRef dyn_AsNamedRef() const { + return getKind() == N_Type ? AsNamedRef() : NamedRef(); + } + TypeLoc dyn_AsTypeLoc() const { + return getKind() == N_Type ? AsTypeLoc() : TypeLoc(); + } + + bool isDecl() const { return isValid() && getKind() == N_Decl; } + bool isStmt() const { return isValid() && getKind() == N_Stmt; } + bool isNamedRef() const { return isValid() && getKind() == N_NamedRef; } + bool isType() const { return isValid() && getKind() == N_Type; } + + /// \brief Returns the declaration that this ASTLocation references. + /// + /// If this points to a Decl, that Decl is returned. + /// If this points to an Expr that references a Decl, that Decl is returned, + /// otherwise it returns NULL. + Decl *getReferencedDecl(); + const Decl *getReferencedDecl() const { + return const_cast<ASTLocation*>(this)->getReferencedDecl(); + } + + SourceRange getSourceRange() const; + + void print(llvm::raw_ostream &OS) const; +}; + +/// \brief Like ASTLocation but also contains the TranslationUnit that the +/// ASTLocation originated from. +class TULocation : public ASTLocation { + TranslationUnit *TU; + +public: + TULocation(TranslationUnit *tu, ASTLocation astLoc) + : ASTLocation(astLoc), TU(tu) { + assert(tu && "Passed null translation unit"); + } + + TranslationUnit *getTU() const { return TU; } +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/Analyzer.h b/include/clang/Index/Analyzer.h new file mode 100644 index 000000000000..f6b5465148e6 --- /dev/null +++ b/include/clang/Index/Analyzer.h @@ -0,0 +1,56 @@ +//===--- Analyzer.h - Analysis for indexing information ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Analyzer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_ANALYZER_H +#define LLVM_CLANG_INDEX_ANALYZER_H + +namespace clang { + class Decl; + class ObjCMessageExpr; + +namespace idx { + class Program; + class IndexProvider; + class TULocationHandler; + +/// \brief Provides indexing information, like finding all references of an +/// Entity across translation units. +class Analyzer { + Program &Prog; + IndexProvider &Idxer; + + Analyzer(const Analyzer&); // do not implement + Analyzer &operator=(const Analyzer &); // do not implement + +public: + explicit Analyzer(Program &prog, IndexProvider &idxer) + : Prog(prog), Idxer(idxer) { } + + /// \brief Find all TULocations for declarations of the given Decl and pass + /// them to Handler. + void FindDeclarations(Decl *D, TULocationHandler &Handler); + + /// \brief Find all TULocations for references of the given Decl and pass + /// them to Handler. + void FindReferences(Decl *D, TULocationHandler &Handler); + + /// \brief Find methods that may respond to the given message and pass them + /// to Handler. + void FindObjCMethods(ObjCMessageExpr *MsgE, TULocationHandler &Handler); +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/DeclReferenceMap.h b/include/clang/Index/DeclReferenceMap.h new file mode 100644 index 000000000000..73f2fe50b3b6 --- /dev/null +++ b/include/clang/Index/DeclReferenceMap.h @@ -0,0 +1,50 @@ +//===--- DeclReferenceMap.h - Map Decls to their references -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// DeclReferenceMap creates a mapping from Decls to the ASTLocations that +// reference them. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_DECLREFERENCEMAP_H +#define LLVM_CLANG_INDEX_DECLREFERENCEMAP_H + +#include "clang/Index/ASTLocation.h" +#include "clang/Index/STLExtras.h" +#include <map> + +namespace clang { + class ASTContext; + class NamedDecl; + +namespace idx { + +/// \brief Maps NamedDecls with the ASTLocations that reference them. +/// +/// References are mapped and retrieved using the canonical decls. +class DeclReferenceMap { +public: + explicit DeclReferenceMap(ASTContext &Ctx); + + typedef std::multimap<NamedDecl*, ASTLocation> MapTy; + typedef pair_value_iterator<MapTy::iterator> astlocation_iterator; + + astlocation_iterator refs_begin(NamedDecl *D) const; + astlocation_iterator refs_end(NamedDecl *D) const; + bool refs_empty(NamedDecl *D) const; + +private: + mutable MapTy Map; +}; + +} // end idx namespace + +} // end clang namespace + +#endif diff --git a/include/clang/Index/Entity.h b/include/clang/Index/Entity.h new file mode 100644 index 000000000000..4533a1a0ac08 --- /dev/null +++ b/include/clang/Index/Entity.h @@ -0,0 +1,143 @@ +//===--- Entity.h - Cross-translation-unit "token" for decls ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Entity is a ASTContext-independent way to refer to declarations that are +// visible across translation units. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_ENTITY_H +#define LLVM_CLANG_INDEX_ENTITY_H + +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/DenseMap.h" +#include <string> + +namespace clang { + class ASTContext; + class Decl; + +namespace idx { + class Program; + class EntityImpl; + +/// \brief A ASTContext-independent way to refer to declarations. +/// +/// Entity is basically the link for declarations that are semantically the same +/// in multiple ASTContexts. A client will convert a Decl into an Entity and +/// later use that Entity to find the "same" Decl into another ASTContext. +/// Declarations that are semantically the same and visible across translation +/// units will be associated with the same Entity. +/// +/// An Entity may also refer to declarations that cannot be visible across +/// translation units, e.g. static functions with the same name in multiple +/// translation units will be associated with different Entities. +/// +/// Entities can be checked for equality but note that the same Program object +/// should be used when getting Entities. +/// +class Entity { + /// \brief Stores the Decl directly if it is not visible outside of its own + /// translation unit, otherwise it stores the associated EntityImpl. + llvm::PointerUnion<Decl *, EntityImpl *> Val; + + explicit Entity(Decl *D); + explicit Entity(EntityImpl *impl) : Val(impl) { } + friend class EntityGetter; + +public: + Entity() { } + + /// \brief Find the Decl that can be referred to by this entity. + Decl *getDecl(ASTContext &AST) const; + + /// \brief If this Entity represents a declaration that is internal to its + /// translation unit, getInternalDecl() returns it. + Decl *getInternalDecl() const { + assert(isInternalToTU() && "This Entity is not internal!"); + return Val.get<Decl *>(); + } + + /// \brief Get a printable name for debugging purpose. + std::string getPrintableName() const; + + /// \brief Get an Entity associated with the given Decl. + /// \returns invalid Entity if an Entity cannot refer to this Decl. + static Entity get(Decl *D, Program &Prog); + + /// \brief true if the Entity is not visible outside the trasnlation unit. + bool isInternalToTU() const { + assert(isValid() && "This Entity is not valid!"); + return Val.is<Decl *>(); + } + + bool isValid() const { return !Val.isNull(); } + bool isInvalid() const { return !isValid(); } + + void *getAsOpaquePtr() const { return Val.getOpaqueValue(); } + static Entity getFromOpaquePtr(void *Ptr) { + Entity Ent; + Ent.Val = llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue(Ptr); + return Ent; + } + + friend bool operator==(const Entity &LHS, const Entity &RHS) { + return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr(); + } + + // For use in a std::map. + friend bool operator < (const Entity &LHS, const Entity &RHS) { + return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr(); + } + + // For use in DenseMap/DenseSet. + static Entity getEmptyMarker() { + Entity Ent; + Ent.Val = + llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-1); + return Ent; + } + static Entity getTombstoneMarker() { + Entity Ent; + Ent.Val = + llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-2); + return Ent; + } +}; + +} // namespace idx + +} // namespace clang + +namespace llvm { +/// Define DenseMapInfo so that Entities can be used as keys in DenseMap and +/// DenseSets. +template<> +struct DenseMapInfo<clang::idx::Entity> { + static inline clang::idx::Entity getEmptyKey() { + return clang::idx::Entity::getEmptyMarker(); + } + + static inline clang::idx::Entity getTombstoneKey() { + return clang::idx::Entity::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::idx::Entity); + + static inline bool + isEqual(clang::idx::Entity LHS, clang::idx::Entity RHS) { + return LHS == RHS; + } + + static inline bool isPod() { return true; } +}; + +} // end namespace llvm + +#endif diff --git a/include/clang/Index/GlobalSelector.h b/include/clang/Index/GlobalSelector.h new file mode 100644 index 000000000000..51f98267f356 --- /dev/null +++ b/include/clang/Index/GlobalSelector.h @@ -0,0 +1,99 @@ +//===--- GlobalSelector.h - Cross-translation-unit "token" for selectors --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// GlobalSelector is a ASTContext-independent way to refer to selectors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_GLOBALSELECTOR_H +#define LLVM_CLANG_INDEX_GLOBALSELECTOR_H + +#include "llvm/ADT/DenseMap.h" +#include <string> + +namespace clang { + class ASTContext; + class Selector; + +namespace idx { + class Program; + +/// \brief A ASTContext-independent way to refer to selectors. +class GlobalSelector { + void *Val; + + explicit GlobalSelector(void *val) : Val(val) { } + +public: + GlobalSelector() : Val(0) { } + + /// \brief Get the ASTContext-specific selector. + Selector getSelector(ASTContext &AST) const; + + bool isValid() const { return Val != 0; } + bool isInvalid() const { return !isValid(); } + + /// \brief Get a printable name for debugging purpose. + std::string getPrintableName() const; + + /// \brief Get a GlobalSelector for the ASTContext-specific selector. + static GlobalSelector get(Selector Sel, Program &Prog); + + void *getAsOpaquePtr() const { return Val; } + + static GlobalSelector getFromOpaquePtr(void *Ptr) { + return GlobalSelector(Ptr); + } + + friend bool operator==(const GlobalSelector &LHS, const GlobalSelector &RHS) { + return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr(); + } + + // For use in a std::map. + friend bool operator< (const GlobalSelector &LHS, const GlobalSelector &RHS) { + return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr(); + } + + // For use in DenseMap/DenseSet. + static GlobalSelector getEmptyMarker() { return GlobalSelector((void*)-1); } + static GlobalSelector getTombstoneMarker() { + return GlobalSelector((void*)-2); + } +}; + +} // namespace idx + +} // namespace clang + +namespace llvm { +/// Define DenseMapInfo so that GlobalSelectors can be used as keys in DenseMap +/// and DenseSets. +template<> +struct DenseMapInfo<clang::idx::GlobalSelector> { + static inline clang::idx::GlobalSelector getEmptyKey() { + return clang::idx::GlobalSelector::getEmptyMarker(); + } + + static inline clang::idx::GlobalSelector getTombstoneKey() { + return clang::idx::GlobalSelector::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::idx::GlobalSelector); + + static inline bool + isEqual(clang::idx::GlobalSelector LHS, clang::idx::GlobalSelector RHS) { + return LHS == RHS; + } + + static inline bool isPod() { return true; } +}; + +} // end namespace llvm + +#endif diff --git a/include/clang/Index/Handlers.h b/include/clang/Index/Handlers.h new file mode 100644 index 000000000000..655aef901cd1 --- /dev/null +++ b/include/clang/Index/Handlers.h @@ -0,0 +1,81 @@ +//===--- Handlers.h - Interfaces for receiving information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Abstract interfaces for receiving information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_HANDLERS_H +#define LLVM_CLANG_INDEX_HANDLERS_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +namespace idx { + class Entity; + class TranslationUnit; + class TULocation; + +/// \brief Abstract interface for receiving Entities. +class EntityHandler { +public: + typedef Entity receiving_type; + + virtual ~EntityHandler(); + virtual void Handle(Entity Ent) = 0; +}; + +/// \brief Abstract interface for receiving TranslationUnits. +class TranslationUnitHandler { +public: + typedef TranslationUnit* receiving_type; + + virtual ~TranslationUnitHandler(); + virtual void Handle(TranslationUnit *TU) = 0; +}; + +/// \brief Abstract interface for receiving TULocations. +class TULocationHandler { +public: + typedef TULocation receiving_type; + + virtual ~TULocationHandler(); + virtual void Handle(TULocation TULoc) = 0; +}; + +/// \brief Helper for the Handler classes. Stores the objects into a vector. +/// example: +/// @code +/// Storing<TranslationUnitHandler> TURes; +/// IndexProvider.GetTranslationUnitsFor(Entity, TURes); +/// for (Storing<TranslationUnitHandler>::iterator +/// I = TURes.begin(), E = TURes.end(); I != E; ++I) { .... +/// @endcode +template <typename handler_type> +class Storing : public handler_type { + typedef typename handler_type::receiving_type receiving_type; + typedef llvm::SmallVector<receiving_type, 8> StoreTy; + StoreTy Store; + +public: + virtual void Handle(receiving_type Obj) { + Store.push_back(Obj); + } + + typedef typename StoreTy::const_iterator iterator; + iterator begin() const { return Store.begin(); } + iterator end() const { return Store.end(); } +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/IndexProvider.h b/include/clang/Index/IndexProvider.h new file mode 100644 index 000000000000..187dd9393cbb --- /dev/null +++ b/include/clang/Index/IndexProvider.h @@ -0,0 +1,38 @@ +//===--- IndexProvider.h - Maps information to translation units -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Maps information to TranslationUnits. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXPROVIDER_H +#define LLVM_CLANG_INDEX_INDEXPROVIDER_H + +namespace clang { + +namespace idx { + class Entity; + class TranslationUnitHandler; + class GlobalSelector; + +/// \brief Maps information to TranslationUnits. +class IndexProvider { +public: + virtual ~IndexProvider(); + virtual void GetTranslationUnitsFor(Entity Ent, + TranslationUnitHandler &Handler) = 0; + virtual void GetTranslationUnitsFor(GlobalSelector Sel, + TranslationUnitHandler &Handler) = 0; +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/Indexer.h b/include/clang/Index/Indexer.h new file mode 100644 index 000000000000..8b1d2dd38bff --- /dev/null +++ b/include/clang/Index/Indexer.h @@ -0,0 +1,75 @@ +//===--- Indexer.h - IndexProvider implementation ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// IndexProvider implementation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXER_H +#define LLVM_CLANG_INDEX_INDEXER_H + +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Index/IndexProvider.h" +#include "clang/Index/Entity.h" +#include "clang/Index/GlobalSelector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/DenseMap.h" +#include "clang/Basic/FileManager.h" +#include <map> + +namespace clang { + class ASTContext; + +namespace idx { + class Program; + class TranslationUnit; + +/// \brief Maps information to TranslationUnits. +class Indexer : public IndexProvider { +public: + typedef llvm::SmallPtrSet<TranslationUnit *, 4> TUSetTy; + typedef llvm::DenseMap<ASTContext *, TranslationUnit *> CtxTUMapTy; + typedef std::map<Entity, TUSetTy> MapTy; + typedef std::map<GlobalSelector, TUSetTy> SelMapTy; + + explicit Indexer(Program &prog) : + Prog(prog), Diags(&DiagClient) { } + + Program &getProgram() const { return Prog; } + + Diagnostic &getDiagnostics() { return Diags; } + const Diagnostic &getDiagnostics() const { return Diags; } + + FileManager &getFileManager() { return FileMgr; } + const FileManager &getFileManager() const { return FileMgr; } + + /// \brief Find all Entities and map them to the given translation unit. + void IndexAST(TranslationUnit *TU); + + virtual void GetTranslationUnitsFor(Entity Ent, + TranslationUnitHandler &Handler); + virtual void GetTranslationUnitsFor(GlobalSelector Sel, + TranslationUnitHandler &Handler); + +private: + Program &Prog; + TextDiagnosticBuffer DiagClient; + Diagnostic Diags; + FileManager FileMgr; + + MapTy Map; + CtxTUMapTy CtxTUMap; + SelMapTy SelMap; +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/Program.h b/include/clang/Index/Program.h new file mode 100644 index 000000000000..8039192512d6 --- /dev/null +++ b/include/clang/Index/Program.h @@ -0,0 +1,45 @@ +//===--- Program.h - Cross-translation unit information ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the idx::Program interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_PROGRAM_H +#define LLVM_CLANG_INDEX_PROGRAM_H + +namespace clang { + class ASTContext; + +namespace idx { + class EntityHandler; + +/// \brief Top level object that owns and maintains information +/// that is common across translation units. +class Program { + void *Impl; + + Program(const Program&); // do not implement + Program &operator=(const Program &); // do not implement + friend class Entity; + friend class GlobalSelector; + +public: + Program(); + ~Program(); + + /// \brief Traverses the AST and passes all the entities to the Handler. + void FindEntities(ASTContext &Ctx, EntityHandler &Handler); +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/STLExtras.h b/include/clang/Index/STLExtras.h new file mode 100644 index 000000000000..a3693c6c79a6 --- /dev/null +++ b/include/clang/Index/STLExtras.h @@ -0,0 +1,63 @@ +//===--- STLExtras.h - Helper STL related templates -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper templates for using with the STL. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_STLEXTRAS_H +#define LLVM_CLANG_INDEX_STLEXTRAS_H + +namespace clang { + +namespace idx { + +/// \brief Wraps an iterator whose value_type is a pair, and provides +/// pair's second object as the value. +template <typename iter_type> +class pair_value_iterator { + iter_type I; + +public: + typedef typename iter_type::value_type::second_type value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef typename iter_type::iterator_category iterator_category; + typedef typename iter_type::difference_type difference_type; + + pair_value_iterator() { } + pair_value_iterator(iter_type i) : I(i) { } + + reference operator*() const { return I->second; } + pointer operator->() const { return &I->second; } + + pair_value_iterator& operator++() { + ++I; + return *this; + } + + pair_value_iterator operator++(int) { + pair_value_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(pair_value_iterator L, pair_value_iterator R) { + return L.I == R.I; + } + friend bool operator!=(pair_value_iterator L, pair_value_iterator R) { + return L.I != R.I; + } +}; + +} // end idx namespace + +} // end clang namespace + +#endif diff --git a/include/clang/Index/SelectorMap.h b/include/clang/Index/SelectorMap.h new file mode 100644 index 000000000000..be01702fcbdb --- /dev/null +++ b/include/clang/Index/SelectorMap.h @@ -0,0 +1,57 @@ +//===--- SelectorMap.h - Maps selectors to methods and messages -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// SelectorMap creates a mapping from selectors to ObjC method declarations +// and ObjC message expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_SELECTORMAP_H +#define LLVM_CLANG_INDEX_SELECTORMAP_H + +#include "clang/Index/ASTLocation.h" +#include "clang/Index/STLExtras.h" +#include "clang/Basic/IdentifierTable.h" +#include <map> + +namespace clang { + class ASTContext; + class ObjCMethodDecl; + +namespace idx { + +/// \brief Maps NamedDecls with the ASTLocations that reference them. +/// +/// References are mapped and retrieved using the canonical decls. +class SelectorMap { +public: + explicit SelectorMap(ASTContext &Ctx); + + typedef std::multimap<Selector, ObjCMethodDecl *> SelMethMapTy; + typedef std::multimap<Selector, ASTLocation> SelRefMapTy; + + typedef pair_value_iterator<SelMethMapTy::iterator> method_iterator; + typedef pair_value_iterator<SelRefMapTy::iterator> astlocation_iterator; + + method_iterator methods_begin(Selector Sel) const; + method_iterator methods_end(Selector Sel) const; + + astlocation_iterator refs_begin(Selector Sel) const; + astlocation_iterator refs_end(Selector Sel) const; + +private: + mutable SelMethMapTy SelMethMap; + mutable SelRefMapTy SelRefMap; +}; + +} // end idx namespace + +} // end clang namespace + +#endif diff --git a/include/clang/Index/TranslationUnit.h b/include/clang/Index/TranslationUnit.h new file mode 100644 index 000000000000..bf9e78f72892 --- /dev/null +++ b/include/clang/Index/TranslationUnit.h @@ -0,0 +1,37 @@ +//===--- TranslationUnit.h - Interface for a translation unit ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Abstract interface for a translation unit. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_TRANSLATIONUNIT_H +#define LLVM_CLANG_INDEX_TRANSLATIONUNIT_H + +namespace clang { + class ASTContext; + +namespace idx { + class DeclReferenceMap; + class SelectorMap; + +/// \brief Abstract interface for a translation unit. +class TranslationUnit { +public: + virtual ~TranslationUnit(); + virtual ASTContext &getASTContext() = 0; + virtual DeclReferenceMap &getDeclReferenceMap() = 0; + virtual SelectorMap &getSelectorMap() = 0; +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/include/clang/Index/Utils.h b/include/clang/Index/Utils.h new file mode 100644 index 000000000000..e78ef8a15563 --- /dev/null +++ b/include/clang/Index/Utils.h @@ -0,0 +1,35 @@ +//===--- Utils.h - Misc utilities for indexing-----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for indexing related +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_UTILS_H +#define LLVM_CLANG_INDEX_UTILS_H + +namespace clang { + class ASTContext; + class SourceLocation; + +namespace idx { + class ASTLocation; + +/// \brief Returns the ASTLocation that a source location points to. +/// +/// \returns the resolved ASTLocation or an invalid ASTLocation if the source +/// location could not be resolved. +ASTLocation ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc); + +} // end namespace idx + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h index 618de39233db..c94a99022415 100644 --- a/include/clang/Lex/DirectoryLookup.h +++ b/include/clang/Lex/DirectoryLookup.h @@ -38,20 +38,20 @@ private: /// Dir - This is the actual directory that we're referring to for a normal /// directory or a framework. const DirectoryEntry *Dir; - + /// Map - This is the HeaderMap if this is a headermap lookup. /// const HeaderMap *Map; } u; - + /// DirCharacteristic - The type of directory this is: this is an instance of /// SrcMgr::CharacteristicKind. unsigned DirCharacteristic : 2; - + /// UserSupplied - True if this is a user-supplied directory. /// bool UserSupplied : 1; - + /// LookupType - This indicates whether this DirectoryLookup object is a /// normal directory, a framework, or a headermap. unsigned LookupType : 2; @@ -62,25 +62,25 @@ public: bool isUser, bool isFramework) : DirCharacteristic(DT), UserSupplied(isUser), LookupType(isFramework ? LT_Framework : LT_NormalDir) { - u.Dir = dir; + u.Dir = dir; } - + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of /// 'map'. DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT, bool isUser) : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap) { - u.Map = map; + u.Map = map; } - + /// getLookupType - Return the kind of directory lookup that this is: either a /// normal directory, a framework path, or a HeaderMap. LookupType_t getLookupType() const { return (LookupType_t)LookupType; } - + /// getName - Return the directory or filename corresponding to this lookup /// object. const char *getName() const; - + /// getDir - Return the directory that this entry refers to. /// const DirectoryEntry *getDir() const { return isNormalDir() ? u.Dir : 0; } @@ -90,42 +90,42 @@ public: const DirectoryEntry *getFrameworkDir() const { return isFramework() ? u.Dir : 0; } - + /// getHeaderMap - Return the directory that this entry refers to. /// const HeaderMap *getHeaderMap() const { return isHeaderMap() ? u.Map : 0; } /// isNormalDir - Return true if this is a normal directory, not a header map. bool isNormalDir() const { return getLookupType() == LT_NormalDir; } - + /// isFramework - True if this is a framework directory. /// bool isFramework() const { return getLookupType() == LT_Framework; } - + /// isHeaderMap - Return true if this is a header map, not a normal directory. bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; } - + /// DirCharacteristic - The type of directory this is, one of the DirType enum /// values. SrcMgr::CharacteristicKind getDirCharacteristic() const { return (SrcMgr::CharacteristicKind)DirCharacteristic; } - + /// isUserSupplied - True if this is a user-supplied directory. /// bool isUserSupplied() const { return UserSupplied; } - - + + /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. const FileEntry *LookupFile(const char *FilenameStart, const char *FilenameEnd, HeaderSearch &HS) const; - + private: const FileEntry *DoFrameworkLookup(const char *FilenameStart, - const char *FilenameEnd, + const char *FilenameEnd, HeaderSearch &HS) const; - + }; } // end namespace clang diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h index d8033093bd8e..6bb7c25947d7 100644 --- a/include/clang/Lex/HeaderMap.h +++ b/include/clang/Lex/HeaderMap.h @@ -30,31 +30,31 @@ namespace clang { class HeaderMap { HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT void operator=(const HeaderMap&); // DO NOT IMPLEMENT - + const llvm::MemoryBuffer *FileBuffer; bool NeedsBSwap; - + HeaderMap(const llvm::MemoryBuffer *File, bool BSwap) : FileBuffer(File), NeedsBSwap(BSwap) { } public: ~HeaderMap(); - + /// HeaderMap::Create - This attempts to load the specified file as a header /// map. If it doesn't look like a HeaderMap, it gives up and returns null. static const HeaderMap *Create(const FileEntry *FE); - + /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd, FileManager &FM) const; - + /// getFileName - Return the filename of the headermap. const char *getFileName() const; - + /// dump - Print the contents of this headermap to stderr. void dump() const; - + private: unsigned getEndianAdjustedWord(unsigned X) const; const HMapHeader &getHeader() const; diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index f21aab1b4015..7517440983b1 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -30,17 +30,17 @@ class IdentifierInfo; struct HeaderFileInfo { /// isImport - True if this is a #import'd or #pragma once file. bool isImport : 1; - + /// DirInfo - Keep track of whether this is a system header, and if so, /// whether it is C++ clean or not. This can be set by the include paths or /// by #pragma gcc system_header. This is an instance of /// SrcMgr::CharacteristicKind. unsigned DirInfo : 2; - + /// NumIncludes - This is the number of times the file has been included /// already. unsigned short NumIncludes; - + /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard /// that protects the entire contents of the file, this is the identifier /// for the macro that controls whether or not it has any effect. @@ -51,14 +51,14 @@ struct HeaderFileInfo { /// external storage. const IdentifierInfo *ControllingMacro; - /// \brief The ID number of the controlling macro. + /// \brief The ID number of the controlling macro. /// /// This ID number will be non-zero when there is a controlling /// macro whose IdentifierInfo may not yet have been loaded from /// external storage. unsigned ControllingMacroID; - HeaderFileInfo() + HeaderFileInfo() : isImport(false), DirInfo(SrcMgr::C_User), NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {} @@ -71,7 +71,7 @@ struct HeaderFileInfo { /// file referenced by a #include or #include_next, (sub-)framework lookup, etc. class HeaderSearch { FileManager &FileMgr; - + /// #include search path information. Requests for #include "x" search the /// directory of the #including file first, then each directory in SearchDirs /// consequtively. Requests for <x> search the current dir first, then each @@ -81,7 +81,7 @@ class HeaderSearch { std::vector<DirectoryLookup> SearchDirs; unsigned SystemDirIdx; bool NoCurDirSearch; - + /// FileInfo - This contains all of the preprocessor-specific data about files /// that are included. The vector is indexed by the FileEntry's UID. /// @@ -94,13 +94,13 @@ class HeaderSearch { /// ignored. The second value is the entry in SearchDirs that satisfied the /// query. llvm::StringMap<std::pair<unsigned, unsigned> > LookupFileCache; - - + + /// FrameworkMap - This is a collection mapping a framework or subframework /// name like "Carbon" to the Carbon.framework directory. llvm::StringMap<const DirectoryEntry *> FrameworkMap; - /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing + /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing /// headermaps. This vector owns the headermap. std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; @@ -114,7 +114,7 @@ class HeaderSearch { unsigned NumFrameworkLookups, NumSubFrameworkLookups; // HeaderSearch doesn't support default or copy construction. - explicit HeaderSearch(); + explicit HeaderSearch(); explicit HeaderSearch(const HeaderSearch&); void operator=(const HeaderSearch&); public: @@ -132,12 +132,12 @@ public: NoCurDirSearch = noCurDirSearch; //LookupFileCache.clear(); } - + /// ClearFileInfo - Forget everything we know about headers so far. void ClearFileInfo() { FileInfo.clear(); } - + void SetExternalLookup(ExternalIdentifierLookup *EIL) { ExternalLookup = EIL; } @@ -155,7 +155,7 @@ public: const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, const FileEntry *CurFileEnt); - + /// LookupSubframeworkHeader - Look up a subframework for the specified /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox @@ -164,7 +164,7 @@ public: const FileEntry *LookupSubframeworkHeader(const char *FilenameStart, const char *FilenameEnd, const FileEntry *RelativeFileEnt); - + /// LookupFrameworkCache - Look up the specified framework name in our /// framework cache, returning the DirectoryEntry it is in if we know, /// otherwise, return null. @@ -172,19 +172,19 @@ public: const char *FWNameEnd) { return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue(); } - + /// ShouldEnterIncludeFile - Mark the specified file as a target of of a /// #include, #include_next, or #import directive. Return false if #including /// the file will have no effect or true if we should include it. bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport); - - + + /// getFileDirFlavor - Return whether the specified file is a normal header, /// a system header, or a C++ friendly system header. SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) { return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; } - + /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g. /// due to #pragma once. void MarkFileIncludeOnce(const FileEntry *File) { @@ -196,13 +196,13 @@ public: void MarkFileSystemHeader(const FileEntry *File) { getFileInfo(File).DirInfo = SrcMgr::C_System; } - + /// IncrementIncludeCount - Increment the count for the number of times the /// specified FileEntry has been entered. void IncrementIncludeCount(const FileEntry *File) { ++getFileInfo(File).NumIncludes; } - + /// SetFileControllingMacro - Mark the specified file as having a controlling /// macro. This is used by the multiple-include optimization to eliminate /// no-op #includes. @@ -210,11 +210,11 @@ public: const IdentifierInfo *ControllingMacro) { getFileInfo(File).ControllingMacro = ControllingMacro; } - + /// CreateHeaderMap - This method returns a HeaderMap for the specified /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. const HeaderMap *CreateHeaderMap(const FileEntry *FE); - + void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } typedef std::vector<HeaderFileInfo>::iterator header_file_iterator; @@ -223,10 +223,10 @@ public: // Used by PCHReader. void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID); - + void PrintStats(); private: - + /// getFileInfo - Return the HeaderFileInfo structure for the specified /// FileEntry. HeaderFileInfo &getFileInfo(const FileEntry *FE); diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h index 03d9b7b3bbb8..a470aa0924fb 100644 --- a/include/clang/Lex/LexDiagnostic.h +++ b/include/clang/Lex/LexDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define LEXSTART diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 3a73147152af..c2db4d357c51 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -39,11 +39,12 @@ class Lexer : public PreprocessorLexer { SourceLocation FileLoc; // Location for start of file. LangOptions Features; // Features enabled by this language (cache). bool Is_PragmaLexer; // True if lexer for _Pragma handling. + bool IsEofCodeCompletion; // True if EOF is treated as a code-completion. //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. // - + /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace /// and return them as tokens. This is used for -C and -CC modes, and /// whitespace preservation can be useful for some clients that want to lex @@ -52,7 +53,7 @@ class Lexer : public PreprocessorLexer { /// When this is set to 2 it returns comments and whitespace. When set to 1 /// it returns comments, when it is set to 0 it returns normal tokens only. unsigned char ExtendedTokenMode; - + //===--------------------------------------------------------------------===// // Context that changes as the file is lexed. // NOTE: any state that mutates when in raw mode must have save/restore code @@ -65,14 +66,14 @@ class Lexer : public PreprocessorLexer { // IsAtStartOfLine - True if the next lexed token should get the "start of // line" flag set on it. bool IsAtStartOfLine; - + Lexer(const Lexer&); // DO NOT IMPLEMENT void operator=(const Lexer&); // DO NOT IMPLEMENT friend class Preprocessor; - + void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); public: - + /// Lexer constructor - Create a new lexer object for the specified buffer /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will @@ -84,21 +85,21 @@ public: /// range will outlive it, so it doesn't take ownership of it. Lexer(SourceLocation FileLoc, const LangOptions &Features, const char *BufStart, const char *BufPtr, const char *BufEnd); - + /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer(FileID FID, const SourceManager &SM, const LangOptions &Features); - + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method /// sets up. It returns a new'd Lexer that must be delete'd when done. - static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, + static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, SourceLocation InstantiationLocStart, SourceLocation InstantiationLocEnd, unsigned TokLen, Preprocessor &PP); - - + + /// getFeatures - Return the language features currently enabled. NOTE: this /// lexer modifies features as a file is parsed! const LangOptions &getFeatures() const { return Features; } @@ -108,7 +109,7 @@ public: /// the virtual location encodes where we should *claim* the characters came /// from. Currently this is only used by _Pragma handling. SourceLocation getFileLoc() const { return FileLoc; } - + /// Lex - Return the next token in the file. If this is the end of file, it /// return the tok::eof token. Return true if an error occurred and /// compilation should terminate, false if normal. This implicitly involves @@ -116,14 +117,14 @@ public: void Lex(Token &Result) { // Start a new token. Result.startToken(); - - // NOTE, any changes here should also change code after calls to + + // NOTE, any changes here should also change code after calls to // Preprocessor::HandleDirective if (IsAtStartOfLine) { Result.setFlag(Token::StartOfLine); IsAtStartOfLine = false; } - + // Get a token. Note that this may delete the current lexer if the end of // file is reached. LexTokenInternal(Result); @@ -131,11 +132,11 @@ public: /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma. bool isPragmaLexer() const { return Is_PragmaLexer; } - + /// IndirectLex - An indirect call to 'Lex' that can be invoked via /// the PreprocessorLexer interface. void IndirectLex(Token &Result) { Lex(Result); } - + /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no /// associated preprocessor object. Return true if the 'next character to /// read' pointer points at the end of the lexer buffer, false otherwise. @@ -144,7 +145,7 @@ public: Lex(Result); // Note that lexing to the end of the buffer doesn't implicitly delete the // lexer when in raw mode. - return BufferPtr == BufferEnd; + return BufferPtr == BufferEnd; } /// isKeepWhitespaceMode - Return true if the lexer should return tokens for @@ -168,23 +169,32 @@ public: bool inKeepCommentMode() const { return ExtendedTokenMode > 0; } - + /// SetCommentRetentionMode - Change the comment retention mode of the lexer /// to the specified mode. This is really only useful when lexing in raw /// mode, because otherwise the lexer needs to manage this. - void SetCommentRetentionState(bool Mode) { + void SetCommentRetentionState(bool Mode) { assert(!isKeepWhitespaceMode() && "Can't play with comment retention state when retaining whitespace"); ExtendedTokenMode = Mode ? 1 : 0; } + + /// \brief Specify that end-of-file is to be considered a code-completion + /// token. + /// + /// When in this mode, the end-of-file token will be immediately preceded + /// by a code-completion token. + void SetEofIsCodeCompletion(bool Val = true) { + IsEofCodeCompletion = Val; + } const char *getBufferStart() const { return BufferStart; } - + /// ReadToEndOfLine - Read the rest of the current preprocessor line as an /// uninterpreted string. This switches the lexer out of directive mode. std::string ReadToEndOfLine(); - - + + /// Diag - Forwarding function for diagnostics. This translate a source /// position in the current buffer into a SourceLocation object for rendering. DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const; @@ -192,20 +202,20 @@ public: /// getSourceLocation - Return a source location identifier for the specified /// offset in the current file. SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const; - + /// getSourceLocation - Return a source location for the next character in /// the current file. SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); } - + /// Stringify - Convert the specified string into a C string by escaping '\' /// and " characters. This does not add surrounding ""'s to the string. /// If Charify is true, this escapes the ' character instead of ". static std::string Stringify(const std::string &Str, bool Charify = false); - + /// Stringify - Convert the specified string into a C string by escaping '\' /// and " characters. This does not add surrounding ""'s to the string. static void Stringify(llvm::SmallVectorImpl<char> &Str); - + /// MeasureTokenLength - Relex the token at the specified location and return /// its length in bytes in the input file. If the token needs cleaning (e.g. /// includes a trigraph or an escaped newline) then this count includes bytes @@ -213,7 +223,7 @@ public: static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts); - + //===--------------------------------------------------------------------===// // Internal implementation interfaces. private: @@ -228,7 +238,7 @@ private: /// takes that range and assigns it to the token as its location and size. In /// addition, since tokens cannot overlap, this also updates BufferPtr to be /// TokEnd. - void FormTokenWithChars(Token &Result, const char *TokEnd, + void FormTokenWithChars(Token &Result, const char *TokEnd, tok::TokenKind Kind) { unsigned TokLen = TokEnd-BufferPtr; Result.setLength(TokLen); @@ -236,7 +246,7 @@ private: Result.setKind(Kind); BufferPtr = TokEnd; } - + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a /// tok::l_paren token, 0 if it is something else and 2 if there are no more /// tokens in the buffer controlled by this lexer. @@ -245,7 +255,7 @@ private: //===--------------------------------------------------------------------===// // Lexer character reading interfaces. public: - + // This lexer is built on two interfaces for reading characters, both of which // automatically provide phase 1/2 translation. getAndAdvanceChar is used // when we know that we will be reading a character from the input buffer and @@ -260,7 +270,7 @@ public: // approach allows us to emit diagnostics for characters (e.g. warnings about // trigraphs), knowing that they only are emitted if the character is // consumed. - + /// isObviouslySimpleCharacter - Return true if the specified character is /// obviously the same in translation phase 1 and translation phase 3. This /// can return false for characters that end up being the same, but it will @@ -268,7 +278,7 @@ public: static bool isObviouslySimpleCharacter(char C) { return C != '?' && C != '\\'; } - + /// getAndAdvanceChar - Read a single 'character' from the specified buffer, /// advance over it, and return it. This is tricky in several cases. Here we /// just handle the trivial case and fall-back to the non-inlined @@ -277,13 +287,13 @@ public: // If this is not a trigraph and not a UCN or escaped newline, return // quickly. if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++; - + unsigned Size = 0; char C = getCharAndSizeSlow(Ptr, Size, &Tok); Ptr += Size; return C; } - + private: /// ConsumeChar - When a character (identified by PeekCharAndSize) is consumed /// and added to a given token, check to see if there are diagnostics that @@ -300,7 +310,7 @@ private: getCharAndSizeSlow(Ptr, Size, &Tok); return Ptr+Size; } - + /// getCharAndSize - Peek a single 'character' from the specified buffer, /// get its size, and return it. This is tricky in several cases. Here we /// just handle the trivial case and fall-back to the non-inlined @@ -312,16 +322,16 @@ private: Size = 1; return *Ptr; } - + Size = 0; return getCharAndSizeSlow(Ptr, Size); } - + /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize /// method. char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0); public: - + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever /// emit a warning. static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, @@ -332,30 +342,30 @@ public: Size = 1; return *Ptr; } - + Size = 0; return getCharAndSizeSlowNoWarn(Ptr, Size, Features); } - + /// getEscapedNewLineSize - Return the size of the specified escaped newline, /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry /// to this function. static unsigned getEscapedNewLineSize(const char *P); - + /// SkipEscapedNewLines - If P points to an escaped newline (or a series of /// them), skip over them and return the first non-escaped-newline found, /// otherwise return P. static const char *SkipEscapedNewLines(const char *P); private: - + /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a /// diagnostic. static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, const LangOptions &Features); - + //===--------------------------------------------------------------------===// // Other lexer functions. - + // Helper functions to lex the remainder of a token of the specific type. void LexIdentifier (Token &Result, const char *CurPtr); void LexNumericConstant (Token &Result, const char *CurPtr); @@ -363,7 +373,7 @@ private: void LexAngledStringLiteral(Token &Result, const char *CurPtr); void LexCharConstant (Token &Result, const char *CurPtr); bool LexEndOfFile (Token &Result, const char *CurPtr); - + bool SkipWhitespace (Token &Result, const char *CurPtr); bool SkipBCPLComment (Token &Result, const char *CurPtr); bool SkipBlockComment (Token &Result, const char *CurPtr); diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index 8ee8ecf7359f..97656f7d39d6 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -17,6 +17,7 @@ #include <string> #include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class APInt; @@ -31,22 +32,22 @@ class Preprocessor; class Token; class SourceLocation; class TargetInfo; - + /// NumericLiteralParser - This performs strict semantic analysis of the content /// of a ppnumber, classifying it as either integer, floating, or erroneous, /// determines the radix of the value and can convert it to a useful value. class NumericLiteralParser { Preprocessor &PP; // needed for diagnostics - + const char *const ThisTokBegin; const char *const ThisTokEnd; const char *DigitsBegin, *SuffixBegin; // markers const char *s; // cursor - + unsigned radix; - + bool saw_exponent, saw_period; - + public: NumericLiteralParser(const char *begin, const char *end, SourceLocation Loc, Preprocessor &PP); @@ -56,8 +57,9 @@ public: bool isLongLong; bool isFloat; // 1.0f bool isImaginary; // 1.0i - - bool isIntegerLiteral() const { + bool isMicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + + bool isIntegerLiteral() const { return !saw_period && !saw_exponent; } bool isFloatingLiteral() const { @@ -66,27 +68,27 @@ public: bool hasSuffix() const { return SuffixBegin != ThisTokEnd; } - + unsigned getRadix() const { return radix; } - + /// GetIntegerValue - Convert this numeric literal value to an APInt that /// matches Val's input width. If there is an overflow (i.e., if the unsigned /// value read is larger than the APInt's bits will hold), set Val to the low /// bits of the result and return true. Otherwise, return false. bool GetIntegerValue(llvm::APInt &Val); - + /// GetFloatValue - Convert this numeric literal to a floating value, using /// the specified APFloat fltSemantics (specifying float, double, etc). /// The optional bool isExact (passed-by-reference) has its value /// set to true if the returned APFloat can represent the number in the /// literal exactly, and false otherwise. - llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format, + llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format, bool* isExact = NULL); -private: - +private: + void ParseNumberStartingWithZero(SourceLocation TokLoc); - + /// SkipHexDigits - Read and skip over any hex digits, up to End. /// Return a pointer to the first non-hex digit or End. const char *SkipHexDigits(const char *ptr) { @@ -94,7 +96,7 @@ private: ptr++; return ptr; } - + /// SkipOctalDigits - Read and skip over any octal digits, up to End. /// Return a pointer to the first non-hex digit or End. const char *SkipOctalDigits(const char *ptr) { @@ -102,7 +104,7 @@ private: ptr++; return ptr; } - + /// SkipDigits - Read and skip over any digits, up to End. /// Return a pointer to the first non-hex digit or End. const char *SkipDigits(const char *ptr) { @@ -110,7 +112,7 @@ private: ptr++; return ptr; } - + /// SkipBinaryDigits - Read and skip over any binary digits, up to End. /// Return a pointer to the first non-binary digit or End. const char *SkipBinaryDigits(const char *ptr) { @@ -118,7 +120,7 @@ private: ptr++; return ptr; } - + }; /// CharLiteralParser - Perform interpretation and semantic analysis of a @@ -143,7 +145,7 @@ public: /// literals) (C99 5.1.1.2p1). class StringLiteralParser { Preprocessor &PP; - + unsigned MaxTokenLength; unsigned SizeBound; unsigned wchar_tByteWidth; @@ -155,7 +157,7 @@ public: bool hadError; bool AnyWide; bool Pascal; - + const char *GetString() { return &ResultBuf[0]; } unsigned GetStringLength() const { return ResultPtr-&ResultBuf[0]; } @@ -163,14 +165,14 @@ public: if (AnyWide) return GetStringLength() / wchar_tByteWidth; return GetStringLength(); - } + } /// getOffsetOfStringByte - This function returns the offset of the /// specified byte of the string data represented by Token. This handles /// advancing over escape sequences in the string. static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo, Preprocessor &PP); }; - + } // end namespace clang #endif diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index ccd13c80d354..5887041c46b9 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -22,7 +22,7 @@ namespace clang { class Preprocessor; - + /// MacroInfo - Each identifier that is #define'd has an instance of this class /// associated with it, used to implement macro expansion. class MacroInfo { @@ -39,7 +39,7 @@ class MacroInfo { /// includes the __VA_ARGS__ identifier on the list. IdentifierInfo **ArgumentList; unsigned NumArguments; - + /// ReplacementTokens - This is the list of tokens that the macro is defined /// to. llvm::SmallVector<Token, 8> ReplacementTokens; @@ -47,21 +47,21 @@ class MacroInfo { /// IsFunctionLike - True if this macro is a function-like macro, false if it /// is an object-like macro. bool IsFunctionLike : 1; - + /// IsC99Varargs - True if this macro is of the form "#define X(...)" or /// "#define X(Y,Z,...)". The __VA_ARGS__ token should be replaced with the /// contents of "..." in an invocation. bool IsC99Varargs : 1; - + /// IsGNUVarargs - True if this macro is of the form "#define X(a...)". The /// "a" identifier in the replacement list will be replaced with all arguments /// of the macro starting with the specified one. bool IsGNUVarargs : 1; - + /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if /// it has not yet been redefined or undefined. bool IsBuiltinMacro : 1; - + private: //===--------------------------------------------------------------------===// // State that changes as the macro is used. @@ -70,19 +70,19 @@ private: /// This disbles recursive expansion, which would be quite bad for things like /// #define A A. bool IsDisabled : 1; - + /// IsUsed - True if this macro is either defined in the main file and has - /// been used, or if it is not defined in the main file. This is used to + /// been used, or if it is not defined in the main file. This is used to /// emit -Wunused-macros diagnostics. bool IsUsed : 1; - + ~MacroInfo() { assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); } - + public: MacroInfo(SourceLocation DefLoc); - + /// FreeArgumentList - Free the argument list of the macro, restoring it to a /// state where it can be reused for other devious purposes. void FreeArgumentList(llvm::BumpPtrAllocator &PPAllocator) { @@ -90,13 +90,13 @@ public: ArgumentList = 0; NumArguments = 0; } - + /// Destroy - destroy this MacroInfo object. void Destroy(llvm::BumpPtrAllocator &PPAllocator) { FreeArgumentList(PPAllocator); this->~MacroInfo(); } - + /// getDefinitionLoc - Return the location that the macro was defined at. /// SourceLocation getDefinitionLoc() const { return Location; } @@ -112,13 +112,13 @@ public: /// this macro in spelling, arguments, and whitespace. This is used to emit /// duplicate definition warnings. This implements the rules in C99 6.10.3. bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const; - + /// setIsBuiltinMacro - Set or clear the isBuiltinMacro flag. /// void setIsBuiltinMacro(bool Val = true) { IsBuiltinMacro = Val; } - + /// setIsUsed - Set the value of the IsUsed flag. /// void setIsUsed(bool Val) { @@ -132,13 +132,13 @@ public: assert(ArgumentList == 0 && NumArguments == 0 && "Argument list already set!"); if (NumArgs == 0) return; - + NumArguments = NumArgs; ArgumentList = PPAllocator.Allocate<IdentifierInfo*>(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ArgumentList[i] = List[i]; } - + /// Arguments - The list of arguments for a function-like macro. This can be /// empty, for, e.g. "#define X()". typedef IdentifierInfo* const *arg_iterator; @@ -146,7 +146,7 @@ public: arg_iterator arg_begin() const { return ArgumentList; } arg_iterator arg_end() const { return ArgumentList+NumArguments; } unsigned getNumArgs() const { return NumArguments; } - + /// getArgumentNum - Return the argument number of the specified identifier, /// or -1 if the identifier is not a formal argument identifier. int getArgumentNum(IdentifierInfo *Arg) const { @@ -154,20 +154,20 @@ public: if (*I == Arg) return I-arg_begin(); return -1; } - + /// Function/Object-likeness. Keep track of whether this macro has formal /// parameters. void setIsFunctionLike() { IsFunctionLike = true; } bool isFunctionLike() const { return IsFunctionLike; } bool isObjectLike() const { return !IsFunctionLike; } - + /// Varargs querying methods. This can only be set for function-like macros. void setIsC99Varargs() { IsC99Varargs = true; } void setIsGNUVarargs() { IsGNUVarargs = true; } bool isC99Varargs() const { return IsC99Varargs; } bool isGNUVarargs() const { return IsGNUVarargs; } bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; } - + /// isBuiltinMacro - Return true if this macro is a builtin macro, such as /// __LINE__, which requires processing before expansion. bool isBuiltinMacro() const { return IsBuiltinMacro; } @@ -175,7 +175,7 @@ public: /// isUsed - Return false if this macro is defined in the main file and has /// not yet been used. bool isUsed() const { return IsUsed; } - + /// getNumTokens - Return the number of tokens that this macro expands to. /// unsigned getNumTokens() const { @@ -186,22 +186,22 @@ public: assert(Tok < ReplacementTokens.size() && "Invalid token #"); return ReplacementTokens[Tok]; } - + typedef llvm::SmallVector<Token, 8>::const_iterator tokens_iterator; tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); } tokens_iterator tokens_end() const { return ReplacementTokens.end(); } bool tokens_empty() const { return ReplacementTokens.empty(); } - + /// AddTokenToBody - Add the specified token to the replacement text for the /// macro. void AddTokenToBody(const Token &Tok) { ReplacementTokens.push_back(Tok); } - + /// isEnabled - Return true if this macro is enabled: in other words, that we /// are not currently in an expansion of this macro. bool isEnabled() const { return !IsDisabled; } - + void EnableMacro() { assert(IsDisabled && "Cannot enable an already-enabled macro!"); IsDisabled = false; @@ -212,7 +212,7 @@ public: IsDisabled = true; } }; - + } // end namespace clang #endif diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h index 94d4677f9d29..5d5d67329059 100644 --- a/include/clang/Lex/MultipleIncludeOpt.h +++ b/include/clang/Lex/MultipleIncludeOpt.h @@ -36,7 +36,7 @@ class MultipleIncludeOpt { /// to false, that way any tokens before the first #ifdef or after the last /// #endif can be easily detected. bool DidMacroExpansion; - + /// TheMacro - The controlling macro for a file, if valid. /// const IdentifierInfo *TheMacro; @@ -46,7 +46,7 @@ public: DidMacroExpansion = false; TheMacro = 0; } - + /// Invalidate - Permenantly mark this file as not being suitable for the /// include-file optimization. void Invalidate() { @@ -55,19 +55,19 @@ public: ReadAnyTokens = true; TheMacro = 0; } - + /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the /// top of the file when reading preprocessor directives. Otherwise, reading /// the "ifndef x" would count as reading tokens. bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } - + // If a token is read, remember that we have seen a side-effect in this file. void ReadToken() { ReadAnyTokens = true; } - + /// ExpandedMacro - When a macro is expanded with this lexer as the current /// buffer, this method is called to disable the MIOpt if needed. void ExpandedMacro() { DidMacroExpansion = true; } - + /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the /// "#if !defined" equivalent) without any preceding tokens, this method is /// called. @@ -80,14 +80,14 @@ public: // If the macro is already set, this is after the top-level #endif. if (TheMacro) return Invalidate(); - + // If we have already expanded a macro by the end of the #ifndef line, then // there is a macro expansion *in* the #ifndef line. This means that the // condition could evaluate differently when subsequently #included. Reject // this. if (DidMacroExpansion) return Invalidate(); - + // Remember that we're in the #if and that we have the macro. ReadAnyTokens = true; TheMacro = M; @@ -100,7 +100,7 @@ public: /// there is a chunk of the file not guarded by the controlling macro. Invalidate(); } - + /// ExitTopLevelConditional - This method is called when the lexer exits the /// top-level conditional. void ExitTopLevelConditional() { @@ -108,12 +108,12 @@ public: // back to "not having read any tokens" so we can detect anything after the // #endif. if (!TheMacro) return Invalidate(); - + // At this point, we haven't "read any tokens" but we do have a controlling // macro. ReadAnyTokens = false; } - + /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if /// there is a controlling macro, return it. const IdentifierInfo *GetControllingMacroAtEndOfFile() const { diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index e5cbeebd22aa..dd24fb7d7ba2 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -23,18 +23,18 @@ namespace clang { class Token; class IdentifierInfo; class MacroInfo; - + /// PPCallbacks - This interface provides a way to observe the actions of the /// preprocessor as it does its thing. Clients can define their hooks here to /// implement preprocessor level tools. class PPCallbacks { public: virtual ~PPCallbacks(); - + enum FileChangeReason { EnterFile, ExitFile, SystemHeaderPragma, RenameFile }; - + /// FileChanged - This callback is invoked whenever a source file is /// entered or exited. The SourceLocation indicates the new location, and /// EnteringFile indicates whether this is because we are entering a new @@ -43,25 +43,25 @@ public: virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType) { } - + /// Ident - This callback is invoked when a #ident or #sccs directive is read. /// virtual void Ident(SourceLocation Loc, const std::string &str) { } - + /// PragmaComment - This callback is invoked when a #pragma comment directive /// is read. /// - virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str) { } - + /// MacroExpands - This is called by /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is /// found. virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { } - + /// MacroDefined - This hook is called whenever a macro definition is seen. virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { } @@ -76,7 +76,7 @@ public: class PPChainedCallbacks : public PPCallbacks { PPCallbacks *First, *Second; -public: +public: PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second) : First(_First), Second(_Second) {} ~PPChainedCallbacks() { @@ -89,23 +89,23 @@ public: First->FileChanged(Loc, Reason, FileType); Second->FileChanged(Loc, Reason, FileType); } - + virtual void Ident(SourceLocation Loc, const std::string &str) { First->Ident(Loc, str); Second->Ident(Loc, str); } - - virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str) { First->PragmaComment(Loc, Kind, Str); Second->PragmaComment(Loc, Kind, Str); } - + virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { First->MacroExpands(Id, MI); Second->MacroExpands(Id, MI); } - + virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { First->MacroDefined(II, MI); Second->MacroDefined(II, MI); diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h index 369b818a1fc9..e96a8c514e6e 100644 --- a/include/clang/Lex/PTHLexer.h +++ b/include/clang/Lex/PTHLexer.h @@ -18,42 +18,42 @@ #include <vector> namespace clang { - + class PTHManager; class PTHSpellingSearch; - + class PTHLexer : public PreprocessorLexer { SourceLocation FileStartLoc; - + /// TokBuf - Buffer from PTH file containing raw token data. const unsigned char* TokBuf; - + /// CurPtr - Pointer into current offset of the token buffer where /// the next token will be read. const unsigned char* CurPtr; - + /// LastHashTokPtr - Pointer into TokBuf of the last processed '#' /// token that appears at the start of a line. const unsigned char* LastHashTokPtr; - + /// PPCond - Pointer to a side table in the PTH file that provides a /// a consise summary of the preproccessor conditional block structure. /// This is used to perform quick skipping of conditional blocks. const unsigned char* PPCond; - + /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry /// to process when doing quick skipping of preprocessor blocks. const unsigned char* CurPPCondPtr; PTHLexer(const PTHLexer&); // DO NOT IMPLEMENT void operator=(const PTHLexer&); // DO NOT IMPLEMENT - + /// ReadToken - Used by PTHLexer to read tokens TokBuf. void ReadToken(Token& T); /// PTHMgr - The PTHManager object that created this PTHLexer. PTHManager& PTHMgr; - + Token EofToken; protected: @@ -62,19 +62,19 @@ protected: /// Create a PTHLexer for the specified token stream. PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D, const unsigned char* ppcond, PTHManager &PM); -public: +public: ~PTHLexer() {} - + /// Lex - Return the next token. void Lex(Token &Tok); - + void getEOF(Token &Tok); - + /// DiscardToEndOfLine - Read the rest of the current preprocessor line as an /// uninterpreted string. This switches the lexer out of directive mode. void DiscardToEndOfLine(); - + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a /// tok::l_paren token, 0 if it is something else and 2 if there are no more /// tokens controlled by this lexer. @@ -85,12 +85,12 @@ public: // its kind. tok::TokenKind x = (tok::TokenKind)*CurPtr; return x == tok::eof ? 2 : x == tok::l_paren; - } + } /// IndirectLex - An indirect call to 'Lex' that can be invoked via /// the PreprocessorLexer interface. void IndirectLex(Token &Result) { Lex(Result); } - + /// getSourceLocation - Return a source location for the token in /// the current file. SourceLocation getSourceLocation(); diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h index 507576473f60..ff1a17259e8a 100644 --- a/include/clang/Lex/PTHManager.h +++ b/include/clang/Lex/PTHManager.h @@ -32,29 +32,29 @@ class FileEntry; class PTHLexer; class Diagnostic; class StatSysCallCache; - + class PTHManager : public IdentifierInfoLookup { friend class PTHLexer; - + /// The memory mapped PTH file. const llvm::MemoryBuffer* Buf; /// Alloc - Allocator used for IdentifierInfo objects. llvm::BumpPtrAllocator Alloc; - + /// IdMap - A lazily generated cache mapping from persistent identifiers to /// IdentifierInfo*. IdentifierInfo** PerIDCache; - + /// FileLookup - Abstract data structure used for mapping between files /// and token data in the PTH file. void* FileLookup; - + /// IdDataTable - Array representing the mapping from persistent IDs to the /// data offset within the PTH file containing the information to /// reconsitute an IdentifierInfo. const unsigned char* const IdDataTable; - + /// SortedIdTable - Abstract data structure mapping from strings to /// persistent IDs. This is used by get(). void* StringIdLookup; @@ -65,15 +65,15 @@ class PTHManager : public IdentifierInfoLookup { /// PP - The Preprocessor object that will use this PTHManager to create /// PTHLexer objects. Preprocessor* PP; - - /// SpellingBase - The base offset within the PTH memory buffer that + + /// SpellingBase - The base offset within the PTH memory buffer that /// contains the cached spellings for literals. const unsigned char* const SpellingBase; - + /// OriginalSourceFile - A null-terminated C-string that specifies the name /// if the file (if any) that was to used to generate the PTH cache. const char* OriginalSourceFile; - + /// This constructor is intended to only be called by the static 'Create' /// method. PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup, @@ -84,11 +84,11 @@ class PTHManager : public IdentifierInfoLookup { // Do not implement. PTHManager(); void operator=(const PTHManager&); - - /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached + + /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached /// spelling for a token. unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer); - + /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the /// PTH file. inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) { @@ -98,44 +98,44 @@ class PTHManager : public IdentifierInfoLookup { return LazilyCreateIdentifierInfo(PersistentID); } IdentifierInfo* LazilyCreateIdentifierInfo(unsigned PersistentID); - + public: // The current PTH version. enum { Version = 9 }; ~PTHManager(); - + /// getOriginalSourceFile - Return the full path to the original header /// file name that was used to generate the PTH cache. const char* getOriginalSourceFile() const { return OriginalSourceFile; } - + /// get - Return the identifier token info for the specified named identifier. /// Unlike the version in IdentifierTable, this returns a pointer instead /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. IdentifierInfo *get(const char *NameStart, const char *NameEnd); - + /// Create - This method creates PTHManager objects. The 'file' argument /// is the name of the PTH file. This method returns NULL upon failure. static PTHManager *Create(const std::string& file, Diagnostic* Diags = 0, Diagnostic::Level failureLevel=Diagnostic::Warning); - void setPreprocessor(Preprocessor *pp) { PP = pp; } - + void setPreprocessor(Preprocessor *pp) { PP = pp; } + /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the /// specified file. This method returns NULL if no cached tokens exist. /// It is the responsibility of the caller to 'delete' the returned object. - PTHLexer *CreateLexer(FileID FID); - + PTHLexer *CreateLexer(FileID FID); + /// createStatCache - Returns a StatSysCallCache object for use with /// FileManager objects. These objects use the PTH data to speed up /// calls to stat by memoizing their results from when the PTH file /// was generated. StatSysCallCache *createStatCache(); }; - + } // end namespace clang #endif diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h index 136dc6fabfb6..ef367feb84db 100644 --- a/include/clang/Lex/Pragma.h +++ b/include/clang/Lex/Pragma.h @@ -37,10 +37,10 @@ class PragmaHandler { public: PragmaHandler(const IdentifierInfo *name) : Name(name) {} virtual ~PragmaHandler(); - + const IdentifierInfo *getName() const { return Name; } virtual void HandlePragma(Preprocessor &PP, Token &FirstToken) = 0; - + /// getIfNamespace - If this is a namespace, return it. This is equivalent to /// using a dynamic_cast, but doesn't require RTTI. virtual PragmaNamespace *getIfNamespace() { return 0; } @@ -57,14 +57,14 @@ class PragmaNamespace : public PragmaHandler { public: PragmaNamespace(const IdentifierInfo *Name) : PragmaHandler(Name) {} virtual ~PragmaNamespace(); - + /// FindHandler - Check to see if there is already a handler for the /// specified name. If not, return the handler for the null identifier if it /// exists, otherwise return null. If IgnoreNull is true (the default) then /// the null handler isn't returned on failure to match. PragmaHandler *FindHandler(const IdentifierInfo *Name, bool IgnoreNull = true) const; - + /// AddPragma - Add a pragma to this namespace. /// void AddPragma(PragmaHandler *Handler) { @@ -75,12 +75,12 @@ public: /// namespace. void RemovePragmaHandler(PragmaHandler *Handler); - bool IsEmpty() { - return Handlers.empty(); + bool IsEmpty() { + return Handlers.empty(); } virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); - + virtual PragmaNamespace *getIfNamespace() { return this; } }; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 6d5ed72455b9..0765ac391be3 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -25,11 +25,12 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" #include <vector> namespace clang { - + class SourceManager; class FileManager; class FileEntry; @@ -41,7 +42,7 @@ class ScratchBuffer; class TargetInfo; class PPCallbacks; class DirectoryLookup; - + /// Preprocessor - This object engages in a tight little dance with the lexer to /// efficiently preprocess tokens. Lexers know only about tokens within a /// single source file, and don't know anything about preprocessor-level issues @@ -49,21 +50,21 @@ class DirectoryLookup; /// class Preprocessor { Diagnostic *Diags; - const LangOptions &Features; + LangOptions Features; TargetInfo &Target; FileManager &FileMgr; SourceManager &SourceMgr; ScratchBuffer *ScratchBuf; HeaderSearch &HeaderInfo; - + /// PTH - An optional PTHManager object used for getting tokens from /// a token cache rather than lexing the original source file. llvm::OwningPtr<PTHManager> PTH; - + /// BP - A BumpPtrAllocator object used to quickly allocate and release /// objects internal to the Preprocessor. llvm::BumpPtrAllocator BP; - + /// Identifiers for builtin macros and other builtins. IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ @@ -74,7 +75,7 @@ class Preprocessor { IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_builtin; // __has_builtin - + SourceLocation DATELoc, TIMELoc; unsigned CounterValue; // Next __COUNTER__ value. @@ -86,7 +87,7 @@ class Preprocessor { // State that is set before the preprocessor begins. bool KeepComments : 1; bool KeepMacroComments : 1; - + // State that changes while the preprocessor runs: bool DisableMacroExpansion : 1; // True if macro expansion is disabled. bool InMacroArgs : 1; // True if parsing fn macro invocation args. @@ -94,42 +95,42 @@ class Preprocessor { /// Identifiers - This is mapping/lookup information for all identifiers in /// the program, including program keywords. IdentifierTable Identifiers; - + /// Selectors - This table contains all the selectors in the program. Unlike /// IdentifierTable above, this table *isn't* populated by the preprocessor. - /// It is declared/instantiated here because it's role/lifetime is + /// It is declared/instantiated here because it's role/lifetime is /// conceptually similar the IdentifierTable. In addition, the current control - /// flow (in clang::ParseAST()), make it convenient to put here. + /// flow (in clang::ParseAST()), make it convenient to put here. /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to /// the lifetime fo the preprocessor. SelectorTable Selectors; /// BuiltinInfo - Information about builtins. Builtin::Context BuiltinInfo; - + /// PragmaHandlers - This tracks all of the pragmas that the client registered /// with this preprocessor. PragmaNamespace *PragmaHandlers; - - /// \brief Tracks all of the comment handlers that the client registered + + /// \brief Tracks all of the comment handlers that the client registered /// with this preprocessor. std::vector<CommentHandler *> CommentHandlers; - + /// CurLexer - This is the current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. llvm::OwningPtr<Lexer> CurLexer; - + /// CurPTHLexer - This is the current top of stack that we're lexing from if /// not expanding from a macro and we are lexing from a PTH cache. /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. llvm::OwningPtr<PTHLexer> CurPTHLexer; - + /// CurPPLexer - This is the current top of the stack what we're lexing from /// if not expanding a macro. This is an alias for either CurLexer or /// CurPTHLexer. PreprocessorLexer* CurPPLexer; - + /// CurLookup - The DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. This allows us to /// implement #include_next and find directory-specific properties. @@ -138,7 +139,7 @@ class Preprocessor { /// CurTokenLexer - This is the current macro we are expanding, if we are /// expanding a macro. One of CurLexer and CurTokenLexer must be null. llvm::OwningPtr<TokenLexer> CurTokenLexer; - + /// IncludeMacroStack - This keeps track of the stack of files currently /// #included, and macros currently being expanded from, not counting /// CurLexer/CurTokenLexer. @@ -146,7 +147,7 @@ class Preprocessor { Lexer *TheLexer; PTHLexer *ThePTHLexer; PreprocessorLexer *ThePPLexer; - TokenLexer *TheTokenLexer; + TokenLexer *TheTokenLexer; const DirectoryLookup *TheDirLookup; IncludeStackInfo(Lexer *L, PTHLexer* P, PreprocessorLexer* PPL, @@ -155,19 +156,19 @@ class Preprocessor { TheDirLookup(D) {} }; std::vector<IncludeStackInfo> IncludeMacroStack; - + /// Callbacks - These are actions invoked when some preprocessor activity is /// encountered (e.g. a file is #included, etc). PPCallbacks *Callbacks; - + /// Macros - For each IdentifierInfo with 'HasMacro' set, we keep a mapping /// to the actual definition of the macro. llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros; - + /// MICache - A "freelist" of MacroInfo objects that can be reused for quick /// allocation. std::vector<MacroInfo*> MICache; - + // Various statistics we track for performance analysis. unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma; unsigned NumIf, NumElse, NumEndif; @@ -175,18 +176,18 @@ class Preprocessor { unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; unsigned NumSkipped; - + /// Predefines - This string is the predefined macros that preprocessor /// should use from the command line etc. std::string Predefines; - + /// TokenLexerCache - Cache macro expanders to reduce malloc traffic. enum { TokenLexerCacheSize = 8 }; unsigned NumCachedTokenLexers; TokenLexer *TokenLexerCache[TokenLexerCacheSize]; private: // Cached tokens state. - typedef std::vector<Token> CachedTokensTy; + typedef llvm::SmallVector<Token, 1> CachedTokensTy; /// CachedTokens - Cached tokens are stored here when we do backtracking or /// lookahead. They are "lexed" by the CachingLex() method. @@ -223,9 +224,9 @@ public: SelectorTable &getSelectorTable() { return Selectors; } Builtin::Context &getBuiltinInfo() { return BuiltinInfo; } llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } - + void setPTHManager(PTHManager* pm); - + PTHManager *getPTHManager() { return PTH.get(); } /// SetCommentRetentionState - Control whether or not the preprocessor retains @@ -234,20 +235,20 @@ public: this->KeepComments = KeepComments | KeepMacroComments; this->KeepMacroComments = KeepMacroComments; } - + bool getCommentRetentionState() const { return KeepComments; } - + /// isCurrentLexer - Return true if we are lexing directly from the specified /// lexer. bool isCurrentLexer(const PreprocessorLexer *L) const { return CurPPLexer == L; } - + /// getCurrentLexer - Return the current file lexer being lexed from. Note /// that this ignores any potentially active macro expansions and _Pragma /// expansions going on at the time. PreprocessorLexer *getCurrentFileLexer() const; - + /// getPPCallbacks/setPPCallbacks - Accessors for preprocessor callbacks. /// Note that this class takes ownership of any PPCallbacks object given to /// it. @@ -257,32 +258,32 @@ public: C = new PPChainedCallbacks(C, Callbacks); Callbacks = C; } - + /// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to /// or null if it isn't #define'd. MacroInfo *getMacroInfo(IdentifierInfo *II) const { return II->hasMacroDefinition() ? Macros.find(II)->second : 0; } - + /// setMacroInfo - Specify a macro for this identifier. /// void setMacroInfo(IdentifierInfo *II, MacroInfo *MI); - + /// macro_iterator/macro_begin/macro_end - This allows you to walk the current /// state of the macro table. This visits every currently-defined macro. - typedef llvm::DenseMap<IdentifierInfo*, + typedef llvm::DenseMap<IdentifierInfo*, MacroInfo*>::const_iterator macro_iterator; macro_iterator macro_begin() const { return Macros.begin(); } macro_iterator macro_end() const { return Macros.end(); } - - - + + + const std::string &getPredefines() const { return Predefines; } /// setPredefines - Set the predefines for this Preprocessor. These /// predefines are automatically injected when parsing the main file. void setPredefines(const char *P) { Predefines = P; } void setPredefines(const std::string &P) { Predefines = P; } - + /// getIdentifierInfo - Return information about the specified preprocessor /// identifier token. The version of this method that takes two character /// pointers is preferred unless the identifier is already available as a @@ -295,7 +296,7 @@ public: IdentifierInfo *getIdentifierInfo(const char *NameStr) { return getIdentifierInfo(NameStr, NameStr+strlen(NameStr)); } - + /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". @@ -309,16 +310,16 @@ public: /// \brief Add the specified comment handler to the preprocessor. void AddCommentHandler(CommentHandler *Handler); - + /// \brief Remove the specified comment handler. /// /// It is an error to remove a handler that has not been registered. void RemoveCommentHandler(CommentHandler *Handler); - + /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. - void EnterMainSourceFile(); - + void EnterMainSourceFile(); + /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. If isMainFile /// is true, this is the main file for the translation unit. @@ -331,7 +332,7 @@ public: /// ILEnd specifies the location of the ')' for a function-like macro or the /// identifier for an object-like macro. void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args); - + /// EnterTokenStream - Add a "macro" context to the top of the include stack, /// which will cause the lexer to start returning the specified tokens. /// @@ -346,7 +347,7 @@ public: /// void EnterTokenStream(const Token *Toks, unsigned NumToks, bool DisableMacroExpansion, bool OwnsTokens); - + /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the /// lexer stack. This should only be used in situations where the current /// state of the top-of-stack lexer is known. @@ -371,7 +372,7 @@ public: void CommitBacktrackedTokens(); /// Backtrack - Make Preprocessor re-lex the tokens that were lexed since - /// EnableBacktrackAtThisPos() was previously called. + /// EnableBacktrackAtThisPos() was previously called. void Backtrack(); /// isBacktrackEnabled - True if EnableBacktrackAtThisPos() was called and @@ -390,7 +391,7 @@ public: else CachingLex(Result); } - + /// LexNonComment - Lex a token. If it's a comment, keep lexing until we get /// something not a comment. This is useful in -E -C mode where comments /// would foul up preprocessor directive handling. @@ -408,11 +409,11 @@ public: DisableMacroExpansion = true; // Lex the token. Lex(Result); - + // Reenable it. DisableMacroExpansion = OldVal; } - + /// LookAhead - This peeks ahead N tokens and returns that token without /// consuming any tokens. LookAhead(0) returns the next token that would be /// returned by Lex(), LookAhead(1) returns the token after it, etc. This @@ -461,7 +462,7 @@ public: AnnotatePreviousCachedTokens(Tok); } - /// \brief Replace the last token with an annotation token. + /// \brief Replace the last token with an annotation token. /// /// Like AnnotateCachedTokens(), this routine replaces an /// already-parsed (and resolved) token with an annotation @@ -481,19 +482,19 @@ public: DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { return Diags->Report(FullSourceLoc(Loc, getSourceManager()), DiagID); } - + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) { return Diags->Report(FullSourceLoc(Tok.getLocation(), getSourceManager()), DiagID); } - + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a /// token is the characters used to represent the token in the source file /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. std::string getSpelling(const Token &Tok) const; - + /// getSpelling - This method is used to get the spelling of a token into a /// preallocated buffer, instead of as an std::string. The caller is required /// to allocate enough space for the token, which is guaranteed to be at least @@ -521,7 +522,7 @@ public: // works. return *SourceMgr.getCharacterData(Tok.getLocation()); } - + /// CreateString - Plop the specified string into a scratch buffer and set the /// specified token's location and length to it. If specified, the source /// location provides a location of the instantiation point of the token. @@ -539,35 +540,35 @@ public: /// it points into a macro), this routine returns an invalid /// source location. SourceLocation getLocForEndOfToken(SourceLocation Loc); - + /// DumpToken - Print the token to stderr, used for debugging. /// void DumpToken(const Token &Tok, bool DumpFlags = false) const; void DumpLocation(SourceLocation Loc) const; void DumpMacro(const MacroInfo &MI) const; - + /// AdvanceToTokenCharacter - Given a location that specifies the start of a /// token, return a new location that specifies a character within the token. SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart,unsigned Char); - + /// IncrementPasteCounter - Increment the counters for the number of token /// paste operations performed. If fast was specified, this is a 'fast paste' /// case we handled. - /// + /// void IncrementPasteCounter(bool isFast) { if (isFast) ++NumFastTokenPaste; else ++NumTokenPaste; } - + void PrintStats(); /// HandleMicrosoftCommentPaste - When the macro expander pastes together a /// comment (/##/) in microsoft mode, this method handles updating the current /// state, returning the token on the next source line. void HandleMicrosoftCommentPaste(Token &Tok); - + //===--------------------------------------------------------------------===// // Preprocessor callback methods. These are invoked by a lexer as various // directives and events are found. @@ -576,26 +577,26 @@ public: /// identifier information for the token and install it into the token. IdentifierInfo *LookUpIdentifierInfo(Token &Identifier, const char *BufPtr = 0); - + /// HandleIdentifier - This callback is invoked when the lexer reads an /// identifier and has filled in the tokens IdentifierInfo member. This /// callback potentially macro expands it or turns it into a named token (like /// 'for'). void HandleIdentifier(Token &Identifier); - + /// HandleEndOfFile - This callback is invoked when the lexer hits the end of /// the current file. This either returns the EOF token and returns true, or /// pops a level off the include stack and returns false, at which point the /// client should call lex again. bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); - + /// HandleEndOfTokenLexer - This callback is invoked when the current /// TokenLexer hits the end of its token stream. bool HandleEndOfTokenLexer(Token &Result); - + /// HandleDirective - This callback is invoked when the lexer sees a # token - /// at the start of a line. This consumes the directive, modifies the + /// at the start of a line. This consumes the directive, modifies the /// lexer/preprocessor state, and advances the lexer(s) so that the next token /// read is the correct one. void HandleDirective(Token &Result); @@ -604,11 +605,11 @@ public: /// not, emit a diagnostic and consume up until the eom. If EnableMacros is /// true, then we consider macros that expand to zero tokens as being ok. void CheckEndOfDirective(const char *Directive, bool EnableMacros = false); - + /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the /// current line until the tok::eom token is found. void DiscardUntilEndOfDirective(); - + /// SawDateOrTime - This returns true if the preprocessor has seen a use of /// __DATE__ or __TIME__ in the file so far. bool SawDateOrTime() const { @@ -616,13 +617,13 @@ public: } unsigned getCounterValue() const { return CounterValue; } void setCounterValue(unsigned V) { CounterValue = V; } - + /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide /// SourceLocation. MacroInfo* AllocateMacroInfo(SourceLocation L); - + private: - + void PushIncludeMacroStack() { IncludeMacroStack.push_back(IncludeStackInfo(CurLexer.take(), CurPTHLexer.take(), @@ -631,7 +632,7 @@ private: CurDirLookup)); CurPPLexer = 0; } - + void PopIncludeMacroStack() { CurLexer.reset(IncludeMacroStack.back().TheLexer); CurPTHLexer.reset(IncludeMacroStack.back().ThePTHLexer); @@ -640,11 +641,11 @@ private: CurDirLookup = IncludeMacroStack.back().TheDirLookup; IncludeMacroStack.pop_back(); } - + /// ReleaseMacroInfo - Release the specified MacroInfo. This memory will /// be reused for allocating new MacroInfo objects. void ReleaseMacroInfo(MacroInfo* MI); - + /// isInPrimaryFile - Return true if we're in the top-level file, not in a /// #include. bool isInPrimaryFile() const; @@ -653,13 +654,13 @@ private: /// #define or #undef. This emits a diagnostic, sets the token kind to eom, /// and discards the rest of the macro line if the macro name is invalid. void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0); - + /// ReadMacroDefinitionArgList - The ( starting an argument list of a macro /// definition has just been read. Lex the rest of the arguments and the /// closing ), updating MI with what we learn. Return true if an error occurs /// parsing the arg list. bool ReadMacroDefinitionArgList(MacroInfo *MI); - + /// SkipExcludedConditionalBlock - We just read a #if or related directive and /// decided that the subsequent tokens are in the #if'd out portion of the /// file. Lex the rest of the file, until we see an #endif. If @@ -670,34 +671,34 @@ private: /// the caller can lex the first valid token. void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse); - + /// PTHSkipExcludedConditionalBlock - A fast PTH version of /// SkipExcludedConditionalBlock. void PTHSkipExcludedConditionalBlock(); - + /// EvaluateDirectiveExpression - Evaluate an integer constant expression that /// may occur after a #if or #elif directive and return it as a bool. If the /// expression is equivalent to "!defined(X)" return X in IfNDefMacro. bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); - + /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: /// #pragma GCC poison/system_header/dependency and #pragma once. void RegisterBuiltinPragmas(); - + /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the /// identifier table. void RegisterBuiltinMacros(); - + /// HandleMacroExpandedIdentifier - If an identifier token is read that is to /// be expanded as a macro, handle it and return the next token as 'Tok'. If /// the macro should not be expanded return true, otherwise return false. bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI); - + /// isNextPPTokenLParen - Determine whether the next preprocessor token to be /// lexed is a '('. If so, consume the token and return true, if not, this /// method should have no observable side-effect on the lexed tokens. bool isNextPPTokenLParen(); - + /// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is /// invoked to read all of the formal arguments specified for the macro /// invocation. This returns null on error. @@ -707,12 +708,12 @@ private: /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void ExpandBuiltinMacro(Token &Tok); - + /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Handle_Pragma(Token &Tok); - + /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and /// start lexing tokens from it instead of the current buffer. void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); @@ -720,7 +721,7 @@ private: /// EnterSourceFileWithPTH - Add a lexer to the top of the include stack and /// start getting tokens from it using the PTH cache. void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); - + /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully /// checked and spelled filename, e.g. as an operand of #include. This returns /// true if the input filename was in <>'s or false if it were in ""'s. The @@ -729,7 +730,7 @@ private: /// this method decides to use a different buffer. bool GetIncludeFilenameSpelling(SourceLocation Loc, const char *&BufStart, const char *&BufEnd); - + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). @@ -737,7 +738,7 @@ private: bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir); - + /// IsFileLexer - Returns true if we are lexing from a file and not a /// pragma or a macro. @@ -752,7 +753,7 @@ private: bool IsFileLexer() const { return IsFileLexer(CurLexer.get(), CurPPLexer); } - + //===--------------------------------------------------------------------===// // Caching stuff. void CachingLex(Token &Result); @@ -773,7 +774,7 @@ private: void HandleDigitDirective(Token &Tok); void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); void HandleIdentSCCSDirective(Token &Tok); - + // File inclusion. void HandleIncludeDirective(Token &Tok, const DirectoryLookup *LookupFrom = 0, @@ -781,13 +782,13 @@ private: void HandleIncludeNextDirective(Token &Tok); void HandleIncludeMacrosDirective(Token &Tok); void HandleImportDirective(Token &Tok); - + // Macro handling. void HandleDefineDirective(Token &Tok); void HandleUndefDirective(Token &Tok); // HandleAssertDirective(Token &Tok); // HandleUnassertDirective(Token &Tok); - + // Conditional Inclusion. void HandleIfdefDirective(Token &Tok, bool isIfndef, bool ReadAnyTokensBeforeDirective); @@ -795,7 +796,7 @@ private: void HandleEndifDirective(Token &Tok); void HandleElseDirective(Token &Tok); void HandleElifDirective(Token &Tok); - + // Pragmas. void HandlePragmaDirective(); public: @@ -813,18 +814,18 @@ public: class PreprocessorFactory { public: virtual ~PreprocessorFactory(); - virtual Preprocessor* CreatePreprocessor() = 0; + virtual Preprocessor* CreatePreprocessor() = 0; }; - -/// \brief Abstract base class that describes a handler that will receive + +/// \brief Abstract base class that describes a handler that will receive /// source ranges for each of the comments encountered in the source file. class CommentHandler { public: virtual ~CommentHandler(); - + virtual void HandleComment(Preprocessor &PP, SourceRange Comment) = 0; }; - + } // end namespace clang #endif diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h index f98b5599658f..85c44c5a0b80 100644 --- a/include/clang/Lex/PreprocessorLexer.h +++ b/include/clang/Lex/PreprocessorLexer.h @@ -18,7 +18,7 @@ #include "clang/Lex/Token.h" #include "llvm/ADT/SmallVector.h" #include <string> - + namespace clang { class Preprocessor; @@ -29,19 +29,19 @@ protected: /// The SourceManager FileID corresponding to the file being lexed. const FileID FID; - + //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. //===--------------------------------------------------------------------===// - + /// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns /// '\n' into a tok::eom token. bool ParsingPreprocessorDirective; - + /// ParsingFilename - True after #include: this turns <xx> into a /// tok::angle_string_literal token. bool ParsingFilename; - + /// LexingRawMode - True if in raw mode: This flag disables interpretation of /// tokens and is a far faster mode to lex in than non-raw-mode. This flag: /// 1. If EOF of the current lexer is found, the include stack isn't popped. @@ -54,40 +54,40 @@ protected: /// /// Note that in raw mode that the PP pointer may be null. bool LexingRawMode; - - /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file + + /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file /// idiom for the multiple-include optimization. MultipleIncludeOpt MIOpt; - + /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks /// we are currently in. llvm::SmallVector<PPConditionalInfo, 4> ConditionalStack; - + PreprocessorLexer(const PreprocessorLexer&); // DO NOT IMPLEMENT void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT friend class Preprocessor; - + PreprocessorLexer(Preprocessor *pp, FileID fid) : PP(pp), FID(fid), ParsingPreprocessorDirective(false), ParsingFilename(false), LexingRawMode(false) {} - + PreprocessorLexer() - : PP(0), + : PP(0), ParsingPreprocessorDirective(false), ParsingFilename(false), LexingRawMode(false) {} - + virtual ~PreprocessorLexer() {} - + virtual void IndirectLex(Token& Result) = 0; - + /// getSourceLocation - Return the source location for the next observable /// location. virtual SourceLocation getSourceLocation() = 0; - + //===--------------------------------------------------------------------===// // #if directive handling. - + /// pushConditionalLevel - When we enter a #if directive, this keeps track of /// what we are currently in for diagnostic emission (e.g. #if with missing /// #endif). @@ -102,8 +102,8 @@ protected: } void pushConditionalLevel(const PPConditionalInfo &CI) { ConditionalStack.push_back(CI); - } - + } + /// popConditionalLevel - Remove an entry off the top of the conditional /// stack, returning information about it. If the conditional stack is empty, /// this returns true and does not fill in the arguments. @@ -113,44 +113,44 @@ protected: ConditionalStack.pop_back(); return false; } - + /// peekConditionalLevel - Return the top of the conditional stack. This /// requires that there be a conditional active. PPConditionalInfo &peekConditionalLevel() { assert(!ConditionalStack.empty() && "No conditionals active!"); return ConditionalStack.back(); } - - unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } + + unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } public: - + //===--------------------------------------------------------------------===// // Misc. lexing methods. - + /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and /// (potentially) macro expand the filename. If the sequence parsed is not /// lexically legal, emit a diagnostic and return a result EOM token. void LexIncludeFilename(Token &Result); - + /// setParsingPreprocessorDirective - Inform the lexer whether or not /// we are currently lexing a preprocessor directive. void setParsingPreprocessorDirective(bool f) { ParsingPreprocessorDirective = f; } - + /// isLexingRawMode - Return true if this lexer is in raw mode or not. bool isLexingRawMode() const { return LexingRawMode; } /// getPP - Return the preprocessor object for this lexer. Preprocessor *getPP() const { return PP; } - - FileID getFileID() const { + + FileID getFileID() const { assert(PP && "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); return FID; } - + /// getFileEntry - Return the FileEntry corresponding to this FileID. Like /// getFileID(), this only works for lexers with attached preprocessors. const FileEntry *getFileEntry() const; diff --git a/include/clang/Lex/ScratchBuffer.h b/include/clang/Lex/ScratchBuffer.h index 6506f9262947..f03515ffc142 100644 --- a/include/clang/Lex/ScratchBuffer.h +++ b/include/clang/Lex/ScratchBuffer.h @@ -29,13 +29,13 @@ class ScratchBuffer { unsigned BytesUsed; public: ScratchBuffer(SourceManager &SM); - + /// getToken - Splat the specified text into a temporary MemoryBuffer and /// return a SourceLocation that refers to the token. This is just like the /// previous method, but returns a location that indicates the physloc of the /// token. SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr); - + private: void AllocScratchBuffer(unsigned RequestLen); }; diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 2c8f2ad3f2b6..8acdb30cc705 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -62,14 +62,14 @@ class Token { /// Kind - The actual flavor of token this is. /// - unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind'; + unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind'; // MSVC will treat it as a signed char and // TokenKinds > 127 won't be handled correctly. - + /// Flags - Bits we track about this token, members of the TokenFlags enum. unsigned Flags : 8; public: - + // Various flags set per token: enum TokenFlags { StartOfLine = 0x01, // At start of line or only after whitespace. @@ -80,7 +80,7 @@ public: tok::TokenKind getKind() const { return (tok::TokenKind)Kind; } void setKind(tok::TokenKind K) { Kind = K; } - + /// is/isNot - Predicates to check if this token is a specific kind, as in /// "if (Tok.is(tok::l_brace)) {...}". bool is(tok::TokenKind K) const { return Kind == (unsigned) K; } @@ -94,12 +94,12 @@ public: is(tok::angle_string_literal); } - bool isAnnotation() const { - return is(tok::annot_typename) || + bool isAnnotation() const { + return is(tok::annot_typename) || is(tok::annot_cxxscope) || is(tok::annot_template_id); } - + /// getLocation - Return a source location identifier for the specified /// offset in the current file. SourceLocation getLocation() const { return Loc; } @@ -132,11 +132,11 @@ public: setLocation(R.getBegin()); setAnnotationEndLoc(R.getEnd()); } - + const char *getName() const { return tok::getTokenName( (tok::TokenKind) Kind); } - + /// startToken - Reset all flags to cleared. /// void startToken() { @@ -145,7 +145,7 @@ public: PtrData = 0; Loc = SourceLocation(); } - + IdentifierInfo *getIdentifierInfo() const { assert(!isAnnotation() && "Used IdentInfo on annotation token!"); if (isLiteral()) return 0; @@ -154,7 +154,7 @@ public: void setIdentifierInfo(IdentifierInfo *II) { PtrData = (void*) II; } - + /// getLiteralData - For a literal token (numeric constant, string, etc), this /// returns a pointer to the start of it in the text buffer if known, null /// otherwise. @@ -166,7 +166,7 @@ public: assert(isLiteral() && "Cannot set literal data of non-literal"); PtrData = (void*)Ptr; } - + void *getAnnotationValue() const { assert(isAnnotation() && "Used AnnotVal on non-annotation token"); return PtrData; @@ -175,17 +175,17 @@ public: assert(isAnnotation() && "Used AnnotVal on non-annotation token"); PtrData = val; } - + /// setFlag - Set the specified flag. void setFlag(TokenFlags Flag) { Flags |= Flag; } - + /// clearFlag - Unset the specified flag. void clearFlag(TokenFlags Flag) { Flags &= ~Flag; } - + /// getFlags - Return the internal represtation of the flags. /// Only intended for low-level operations such as writing tokens to // disk. @@ -195,32 +195,32 @@ public: /// setFlagValue - Set a flag to either true or false. void setFlagValue(TokenFlags Flag, bool Val) { - if (Val) + if (Val) setFlag(Flag); else clearFlag(Flag); } - + /// isAtStartOfLine - Return true if this token is at the start of a line. /// bool isAtStartOfLine() const { return (Flags & StartOfLine) ? true : false; } - + /// hasLeadingSpace - Return true if this token has whitespace before it. /// bool hasLeadingSpace() const { return (Flags & LeadingSpace) ? true : false; } - + /// isExpandDisabled - Return true if this identifier token should never /// be expanded in the future, due to C99 6.10.3.4p2. bool isExpandDisabled() const { return (Flags & DisableExpand) ? true : false; } - - /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. + + /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; - + /// getObjCKeywordID - Return the ObjC keyword kind. tok::ObjCKeywordKind getObjCKeywordID() const; - + /// needsCleaning - Return true if this token has trigraphs or escaped /// newlines in it. /// @@ -233,15 +233,15 @@ struct PPConditionalInfo { /// IfLoc - Location where the conditional started. /// SourceLocation IfLoc; - + /// WasSkipping - True if this was contained in a skipping directive, e.g. /// in a "#if 0" block. bool WasSkipping; - + /// FoundNonSkip - True if we have emitted tokens already, and now we're in /// an #else block or something. Only useful in Skipping blocks. bool FoundNonSkip; - + /// FoundElse - True if we've seen a #else in this block. If so, /// #elif/#else directives are not allowed. bool FoundElse; @@ -263,41 +263,41 @@ struct TemplateIdAnnotation { /// The declaration of the template corresponding to the /// template-name. This is an Action::DeclTy*. - void *Template; + void *Template; /// The kind of template that Template refers to. TemplateNameKind Kind; /// The location of the '<' before the template argument - /// list. + /// list. SourceLocation LAngleLoc; /// The location of the '>' after the template argument - /// list. + /// list. SourceLocation RAngleLoc; /// NumArgs - The number of template arguments. - unsigned NumArgs; + unsigned NumArgs; /// \brief Retrieves a pointer to the template arguments void **getTemplateArgs() { return (void **)(this + 1); } /// \brief Retrieves a pointer to the array of template argument /// locations. - SourceLocation *getTemplateArgLocations() { + SourceLocation *getTemplateArgLocations() { return (SourceLocation *)(getTemplateArgs() + NumArgs); } /// \brief Retrieves a pointer to the array of flags that states /// whether the template arguments are types. - bool *getTemplateArgIsType() { + bool *getTemplateArgIsType() { return (bool *)(getTemplateArgLocations() + NumArgs); } static TemplateIdAnnotation* Allocate(unsigned NumArgs) { - TemplateIdAnnotation *TemplateId - = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + - sizeof(void*) * NumArgs + + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + + sizeof(void*) * NumArgs + sizeof(SourceLocation) * NumArgs + sizeof(bool) * NumArgs); TemplateId->NumArgs = NumArgs; diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h index dfc05f4074e0..d759e47e57fc 100644 --- a/include/clang/Lex/TokenConcatenation.h +++ b/include/clang/Lex/TokenConcatenation.h @@ -19,7 +19,7 @@ namespace clang { class Preprocessor; class Token; - + /// TokenConcatenation class, which answers the question of /// "Is it safe to emit two tokens without a whitespace between them, or /// would that cause implicit concatenation of the tokens?" @@ -30,40 +30,40 @@ namespace clang { /// class TokenConcatenation { Preprocessor &PP; - + enum AvoidConcatInfo { /// By default, a token never needs to avoid concatenation. Most tokens /// (e.g. ',', ')', etc) don't cause a problem when concatenated. aci_never_avoid_concat = 0, - + /// aci_custom_firstchar - AvoidConcat contains custom code to handle this /// token's requirements, and it needs to know the first character of the /// token. aci_custom_firstchar = 1, - + /// aci_custom - AvoidConcat contains custom code to handle this token's /// requirements, but it doesn't need to know the first character of the /// token. aci_custom = 2, - + /// aci_avoid_equal - Many tokens cannot be safely followed by an '=' /// character. For example, "<<" turns into "<<=" when followed by an =. aci_avoid_equal = 4 }; - + /// TokenInfo - This array contains information for each token on what /// action to take when avoiding concatenation of tokens in the AvoidConcat /// method. char TokenInfo[tok::NUM_TOKENS]; public: TokenConcatenation(Preprocessor &PP); - + bool AvoidConcat(const Token &PrevTok, const Token &Tok) const; private: /// StartsWithL - Return true if the spelling of this token starts with 'L'. bool StartsWithL(const Token &Tok) const; - + /// IsIdentifierL - Return true if the spelling of this token is literally /// 'L'. bool IsIdentifierL(const Token &Tok) const; diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h index c0a61cf93ee5..3f13e9cc1268 100644 --- a/include/clang/Lex/TokenLexer.h +++ b/include/clang/Lex/TokenLexer.h @@ -21,7 +21,7 @@ namespace clang { class Preprocessor; class Token; class MacroArgs; - + /// TokenLexer - This implements a lexer that returns token from a macro body /// or token stream instead of lexing from a character buffer. This is used for /// macro expansion and _Pragma handling, for example. @@ -47,34 +47,34 @@ class TokenLexer { /// the preprocessor's bump pointer allocator, or some other buffer that we /// may or may not own (depending on OwnsTokens). const Token *Tokens; - + /// NumTokens - This is the length of the Tokens array. /// unsigned NumTokens; - + /// CurToken - This is the next token that Lex will return. /// unsigned CurToken; - + /// InstantiateLocStart/End - The source location range where this macro was /// instantiated. SourceLocation InstantiateLocStart, InstantiateLocEnd; - + /// Lexical information about the expansion point of the macro: the identifier /// that the macro expanded from had these properties. bool AtStartOfLine : 1; bool HasLeadingSpace : 1; - + /// OwnsTokens - This is true if this TokenLexer allocated the Tokens /// array, and thus needs to free it when destroyed. For simple object-like /// macros (for example) we just point into the token buffer of the macro /// definition, we don't make a copy of it. bool OwnsTokens : 1; - + /// DisableMacroExpansion - This is true when tokens lexed from the TokenLexer /// should not be subject to further macro expansion. bool DisableMacroExpansion : 1; - + TokenLexer(const TokenLexer&); // DO NOT IMPLEMENT void operator=(const TokenLexer&); // DO NOT IMPLEMENT public: @@ -87,13 +87,13 @@ public: : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { Init(Tok, ILEnd, ActualArgs); } - + /// Init - Initialize this TokenLexer to expand from the specified macro /// with the specified argument information. Note that this ctor takes /// ownership of the ActualArgs pointer. ILEnd specifies the location of the /// ')' for a function-like macro or the identifier for an object-like macro. void Init(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs); - + /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is /// specified, this takes ownership of the tokens and delete[]'s them when /// the token lexer is empty. @@ -102,45 +102,45 @@ public: : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { Init(TokArray, NumToks, DisableExpansion, ownsTokens); } - + /// Init - Initialize this TokenLexer with the specified token stream. /// This does not take ownership of the specified token vector. /// - /// DisableExpansion is true when macro expansion of tokens lexed from this + /// DisableExpansion is true when macro expansion of tokens lexed from this /// stream should be disabled. void Init(const Token *TokArray, unsigned NumToks, bool DisableMacroExpansion, bool OwnsTokens); - + ~TokenLexer() { destroy(); } - + /// isNextTokenLParen - If the next token lexed will pop this macro off the /// expansion stack, return 2. If the next unexpanded token is a '(', return /// 1, otherwise return 0. unsigned isNextTokenLParen() const; - + /// Lex - Lex and return a token from this macro stream. void Lex(Token &Tok); - + private: void destroy(); - + /// isAtEnd - Return true if the next lex call will pop this macro off the /// include stack. bool isAtEnd() const { return CurToken == NumTokens; } - + /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there /// are is another ## after it, chomp it iteratively. Return the result as /// Tok. If this returns true, the caller should immediately return the /// token. bool PasteTokens(Token &Tok); - + /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. void ExpandFunctionArguments(); - + /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes /// together to form a comment that comments out everything in the current /// macro, other active macros, and anything left on the current physical diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d969562977ea..1ee14701fa2d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -22,6 +22,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Ownership.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/ADT/PointerUnion.h" namespace clang { // Semantic. @@ -49,7 +50,7 @@ namespace clang { template<> struct IsResultPtrLowBitFree<3> { static const bool value = true;}; template<> struct IsResultPtrLowBitFree<4> { static const bool value = true;}; template<> struct IsResultPtrLowBitFree<5> { static const bool value = true;}; - + /// Action - As the parser reads the input file and recognizes the productions /// of the grammar, it invokes methods on this class to turn the parsed input /// into something useful: e.g. a parse tree. @@ -102,22 +103,22 @@ public: typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg; typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg; - class FullExprArg { + class FullExprArg { public: // FIXME: The const_cast here is ugly. RValue references would make this - // much nicer (or we could duplicate a bunch of the move semantics + // much nicer (or we could duplicate a bunch of the move semantics // emulation code from Ownership.h). FullExprArg(const FullExprArg& Other) : Expr(move(const_cast<FullExprArg&>(Other).Expr)) {} - + OwningExprResult release() { return move(Expr); } - + ExprArg* operator->() { return &Expr; } - + private: // FIXME: No need to make the entire Action class a friend when it's just // Action::FullExpr that needs access to the constructor below. @@ -128,7 +129,7 @@ public: ExprArg Expr; }; - + template<typename T> FullExprArg FullExpr(T &Arg) { return FullExprArg(ActOnFinishFullExpr(move(Arg))); @@ -149,31 +150,47 @@ public: virtual void PrintStats() const {} /// getDeclName - Return a pretty name for the specified decl if possible, or - /// an empty string if not. This is used for pretty crash reporting. + /// an empty string if not. This is used for pretty crash reporting. virtual std::string getDeclName(DeclPtrTy D) { return ""; } - + /// \brief Invoked for each comment in the source code, providing the source /// range that contains the comment. virtual void ActOnComment(SourceRange Comment) { } - + //===--------------------------------------------------------------------===// // Declaration Tracking Callbacks. //===--------------------------------------------------------------------===// - + /// ConvertDeclToDeclGroup - If the parser has one decl in a context where it /// needs a decl group, it calls this to convert between the two /// representations. virtual DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr) { return DeclGroupPtrTy(); } - + /// getTypeName - Return non-null if the specified identifier is a type name /// in the current scope. - /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or - /// namespace) that the identifier must be a member of. - /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". + /// + /// \param II the identifier for which we are performing name lookup + /// + /// \param NameLoc the location of the identifier + /// + /// \param S the scope in which this name lookup occurs + /// + /// \param SS if non-NULL, the C++ scope specifier that precedes the + /// identifier + /// + /// \param isClassName whether this is a C++ class-name production, in + /// which we can end up referring to a member of an unknown specialization + /// that we know (from the grammar) is supposed to be a type. For example, + /// this occurs when deriving from "std::vector<T>::allocator_type", where T + /// is a template parameter. + /// + /// \returns the type referred to by this identifier, or NULL if the type + /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS = 0) = 0; + Scope *S, const CXXScopeSpec *SS = 0, + bool isClassName = false) = 0; /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If @@ -183,20 +200,69 @@ public: virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S) { return DeclSpec::TST_unspecified; } - + + /// \brief Action called as part of error recovery when the parser has + /// determined that the given name must refer to a type, but + /// \c getTypeName() did not return a result. + /// + /// This callback permits the action to give a detailed diagnostic when an + /// unknown type name is encountered and, potentially, to try to recover + /// by producing a new type in \p SuggestedType. + /// + /// \param II the name that should be a type. + /// + /// \param IILoc the location of the name in the source. + /// + /// \param S the scope in which name lookup was performed. + /// + /// \param SS if non-NULL, the C++ scope specifier that preceded the name. + /// + /// \param SuggestedType if the action sets this type to a non-NULL type, + /// the parser will recovery by consuming the type name token and then + /// pretending that the given type was the type it parsed. + /// + /// \returns true if a diagnostic was emitted, false otherwise. When false, + /// the parser itself will emit a generic "unknown type name" diagnostic. + virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TypeTy *&SuggestedType) { + return false; + } + /// isCurrentClassName - Return true if the specified name is the /// name of the innermost C++ class type currently being defined. virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = 0) = 0; - /// \brief Determines whether the identifier II is a template name - /// in the current scope. If so, the kind of template name is - /// returned, and \p TemplateDecl receives the declaration. An - /// optional CXXScope can be passed to indicate the C++ scope in - /// which the identifier will be found. - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, - TemplateTy &Template, - const CXXScopeSpec *SS = 0) = 0; + /// \brief Determine whether the given identifier refers to the name of a + /// template. + /// + /// \param S the scope in which name lookup occurs + /// + /// \param II the identifier that we are querying to determine whether it + /// is a template. + /// + /// \param IdLoc the source location of the identifier + /// + /// \param SS the C++ scope specifier that precedes the template name, if + /// any. + /// + /// \param EnteringContext whether we are potentially entering the context + /// referred to by the scope specifier \p SS + /// + /// \param Template if the name does refer to a template, the declaration + /// of the template that the name refers to. + /// + /// \returns the kind of template that this name refers to. + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectType, + bool EnteringContext, + TemplateTy &Template) = 0; /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -205,17 +271,40 @@ public: return 0; } - /// ActOnCXXNestedNameSpecifier - Called during parsing of a - /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now - /// we want to resolve "bar::". 'SS' is empty or the previously parsed - /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', - /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. - /// Returns a CXXScopeTy* object representing the C++ scope. + /// \brief Parsed an identifier followed by '::' in a C++ + /// nested-name-specifier. + /// + /// \param S the scope in which the nested-name-specifier was parsed. + /// + /// \param SS the nested-name-specifier that precedes the identifier. For + /// example, if we are parsing "foo::bar::", \p SS will describe the "foo::" + /// that has already been parsed. + /// + /// \param IdLoc the location of the identifier we have just parsed (e.g., + /// the "bar" in "foo::bar::". + /// + /// \param CCLoc the location of the '::' at the end of the + /// nested-name-specifier. + /// + /// \param II the identifier that represents the scope that this + /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::". + /// + /// \param ObjectType if this nested-name-specifier occurs as part of a + /// C++ member access expression such as "x->Base::f", the type of the base + /// object (e.g., *x in the example, if "x" were a pointer). + /// + /// \param EnteringContext if true, then we intend to immediately enter the + /// context of this nested-name-specifier, e.g., for an out-of-line + /// definition of a class member. + /// + /// \returns a CXXScopeTy* object representing the C++ scope. virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, - IdentifierInfo &II) { + IdentifierInfo &II, + TypeTy *ObjectType, + bool EnteringContext) { return 0; } @@ -232,7 +321,7 @@ public: TypeTy *Type, SourceRange TypeRange, SourceLocation CCLoc) { - return 0; + return 0; } /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global @@ -241,7 +330,9 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + /// \returns true if an error occurred, false otherwise. + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + return false; } /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously @@ -281,14 +372,14 @@ public: return DeclPtrTy(); } - /// AddInitializerToDecl - This action is called immediately after - /// ActOnDeclarator (when an initializer is present). The code is factored + /// AddInitializerToDecl - This action is called immediately after + /// ActOnDeclarator (when an initializer is present). The code is factored /// this way to make sure we are able to handle the following: /// void func() { int xx = xx; } /// This allows ActOnDeclarator to register "xx" prior to parsing the - /// initializer. The declaration above should still result in a warning, + /// initializer. The declaration above should still result in a warning, /// since the reference to "xx" is uninitialized. - virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) { + virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) { return; } @@ -302,7 +393,10 @@ public: /// ActOnUninitializedDecl - This action is called immediately after /// ActOnDeclarator (when an initializer is *not* present). - virtual void ActOnUninitializedDecl(DeclPtrTy Dcl) { + /// If TypeContainsUndeducedAuto is true, then the type of the declarator + /// has an undeduced 'auto' type somewhere. + virtual void ActOnUninitializedDecl(DeclPtrTy Dcl, + bool TypeContainsUndeducedAuto) { return; } @@ -314,7 +408,7 @@ public: return DeclGroupPtrTy(); } - + /// @brief Indicates that all K&R-style parameter declarations have /// been parsed prior to a function definition. /// @param S The function prototype scope. @@ -352,7 +446,7 @@ public: ExprArg AsmString) { return DeclPtrTy(); } - + /// ActOnPopScope - This callback is called immediately before the specified /// scope is popped and deleted. virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {} @@ -360,7 +454,7 @@ public: /// ActOnTranslationUnitScope - This callback is called once, immediately /// after creating the translation unit scope (in Parser::Initialize). virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {} - + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { @@ -397,7 +491,7 @@ public: /// translation unit when EOF is reached and all but the top-level scope is /// popped. virtual void ActOnEndOfTranslationUnit() {} - + //===--------------------------------------------------------------------===// // Type Parsing Callbacks. //===--------------------------------------------------------------------===// @@ -406,24 +500,90 @@ public: virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { return TypeResult(); } - - enum TagKind { - TK_Reference, // Reference to a tag: 'struct foo *X;' - TK_Declaration, // Fwd decl of a tag: 'struct foo;' - TK_Definition // Definition of a tag: 'struct foo { int X; } Y;' + + enum TagUseKind { + TUK_Reference, // Reference to a tag: 'struct foo *X;' + TUK_Declaration, // Fwd decl of a tag: 'struct foo;' + TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' + TUK_Friend // Friend declaration: 'friend struct foo;' }; - virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + + /// \brief The parser has encountered a tag (e.g., "class X") that should be + /// turned into a declaration by the action module. + /// + /// \param S the scope in which this tag occurs. + /// + /// \param TagSpec an instance of DeclSpec::TST, indicating what kind of tag + /// this is (struct/union/enum/class). + /// + /// \param TUK how the tag we have encountered is being used, which + /// can be a reference to a (possibly pre-existing) tag, a + /// declaration of that tag, or the beginning of a definition of + /// that tag. + /// + /// \param KWLoc the location of the "struct", "class", "union", or "enum" + /// keyword. + /// + /// \param SS C++ scope specifier that precedes the name of the tag, e.g., + /// the "std::" in "class std::type_info". + /// + /// \param Name the name of the tag, e.g., "X" in "struct X". This parameter + /// may be NULL, to indicate an anonymous class/struct/union/enum type. + /// + /// \param NameLoc the location of the name of the tag. + /// + /// \param Attr the set of attributes that appertain to the tag. + /// + /// \param AS when this tag occurs within a C++ class, provides the + /// current access specifier (AS_public, AS_private, AS_protected). + /// Otherwise, it will be AS_none. + /// + /// \param TemplateParameterLists the set of C++ template parameter lists + /// that apply to this tag, if the tag is a declaration or definition (see + /// the \p TK parameter). The action module is responsible for determining, + /// based on the template parameter lists and the scope specifier, whether + /// the declared tag is a class template or not. + /// + /// \param OwnedDecl the callee should set this flag true when the returned + /// declaration is "owned" by this reference. Ownership is handled entirely + /// by the action module. + /// + /// \returns the declaration to which this tag refers. + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, - bool &OwnedDecl) { - // TagType is an instance of DeclSpec::TST, indicating what kind of tag this - // is (struct/union/enum/class). + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent) { return DeclPtrTy(); } - + + /// Acts on a reference to a dependent tag name. This arises in + /// cases like: + /// + /// template <class T> class A; + /// template <class T> class B { + /// friend class A<T>::M; // here + /// }; + /// + /// \param TagSpec an instance of DeclSpec::TST corresponding to the + /// tag specifier. + /// + /// \param TUK the tag use kind (either TUK_Friend or TUK_Reference) + /// + /// \param SS the scope specifier (always defined) + virtual TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation KWLoc, + SourceLocation NameLoc) { + return TypeResult(); + } + /// Act on @defs() element found when parsing a structure. ClassName is the - /// name of the referenced class. + /// name of the referenced class. virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclPtrTy> &Decls) {} @@ -432,19 +592,19 @@ public: Declarator &D, ExprTy *BitfieldWidth) { return DeclPtrTy(); } - + virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind visibility) { return DeclPtrTy(); } - + virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl, - DeclPtrTy *Fields, unsigned NumFields, + DeclPtrTy *Fields, unsigned NumFields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList) {} - + /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, /// struct, or union). @@ -452,7 +612,8 @@ public: /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). - virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl) { } + virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, + SourceLocation RBraceLoc) { } virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, DeclPtrTy LastEnumConstant, @@ -462,7 +623,8 @@ public: } virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, DeclPtrTy EnumDecl, - DeclPtrTy *Elements, unsigned NumElements) {} + DeclPtrTy *Elements, unsigned NumElements, + Scope *S, AttributeList *AttrList) {} //===--------------------------------------------------------------------===// // Statement Parsing Callbacks. @@ -496,10 +658,10 @@ public: SourceLocation ColonLoc) { return StmtEmpty(); } - + /// ActOnCaseStmtBody - This installs a statement as the body of a case. virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt) {} - + virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtArg SubStmt, Scope *CurScope){ @@ -513,8 +675,8 @@ public: return StmtEmpty(); } - virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { return StmtEmpty(); @@ -529,12 +691,12 @@ public: return StmtEmpty(); } - virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, + virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { return StmtEmpty(); } virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, + SourceLocation WhileLoc, SourceLocation CondLParen, ExprArg Cond, SourceLocation CondRParen) { @@ -572,11 +734,11 @@ public: return StmtEmpty(); } virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, - FullExprArg RetValExp) { + ExprArg RetValExp) { return StmtEmpty(); } virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, + bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, @@ -647,15 +809,15 @@ public: /// \brief The current expression and its subexpressions occur within an /// unevaluated operand (C++0x [expr]p8), such as a constant expression /// or the subexpression of \c sizeof, where the type or the value of the - /// expression may be significant but no code will be generated to evaluate + /// expression may be significant but no code will be generated to evaluate /// the value of the expression at run time. Unevaluated, - - /// \brief The current expression is potentially evaluated at run time, - /// which means that code may be generated to evaluate the value of the + + /// \brief The current expression is potentially evaluated at run time, + /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, - + /// \brief The current expression may be potentially evaluated or it may /// be unevaluated, but it is impossible to tell from the lexical context. /// This evaluation context is used primary for the operand of the C++ @@ -663,17 +825,17 @@ public: /// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2). PotentiallyPotentiallyEvaluated }; - + /// \brief The parser is entering a new expression evaluation context. /// /// \param NewContext is the new expression evaluation context. /// /// \returns the previous expression evaluation context. - virtual ExpressionEvaluationContext + virtual ExpressionEvaluationContext PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { return PotentiallyEvaluated; } - + /// \brief The parser is existing an expression evaluation context. /// /// \param OldContext the expression evaluation context that the parser is @@ -681,10 +843,10 @@ public: /// /// \param NewContext the expression evaluation context that the parser is /// returning to. - virtual void + virtual void PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, ExpressionEvaluationContext NewContext) { } - + // Primary Expressions. /// \brief Retrieve the source range that corresponds to the given @@ -756,6 +918,12 @@ public: return move(Val); // Default impl returns operand. } + virtual OwningExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val) { + return ExprEmpty(); + } + // Postfix Expressions. virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, @@ -773,7 +941,8 @@ public: tok::TokenKind OpKind, SourceLocation MemberLoc, IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl) { + DeclPtrTy ObjCImpDecl, + const CXXScopeSpec *SS = 0) { return ExprEmpty(); } @@ -811,8 +980,8 @@ public: SourceLocation RParenLoc) { return ExprEmpty(); } - /// @brief Parsed a C99 designated initializer. - /// + /// @brief Parsed a C99 designated initializer. + /// /// @param Desig Contains the designation with one or more designators. /// /// @param Loc The location of the '=' or ':' prior to the @@ -831,8 +1000,9 @@ public: return ExprEmpty(); } - virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprArg Op) { + virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + TypeTy *Ty, SourceLocation RParenLoc, + ExprArg Op) { return ExprEmpty(); } @@ -885,13 +1055,13 @@ public: } // __builtin_types_compatible_p(type1, type2) - virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, TypeTy *arg1, TypeTy *arg2, SourceLocation RPLoc) { return ExprEmpty(); } // __builtin_choose_expr(constExpr, expr1, expr2) - virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, ExprArg cond, ExprArg expr1, ExprArg expr2, SourceLocation RPLoc){ return ExprEmpty(); @@ -971,6 +1141,7 @@ public: /// ActOnUsingDirective - This is called when using-directive is parsed. virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, + AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation IdentLoc, @@ -978,7 +1149,7 @@ public: OverloadedOperatorKind Op, AttributeList *AttrList, bool IsTypeName); - + /// ActOnParamDefaultArgument - Parse default argument for function parameter virtual void ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, @@ -989,7 +1160,7 @@ public: /// argument for a function parameter, but we can't parse it yet /// because we're inside a class definition. Note that this default /// argument will be parsed later. - virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, SourceLocation ArgLoc) { } @@ -997,7 +1168,7 @@ public: /// the default argument for the parameter param failed. virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { } - /// AddCXXDirectInitializerToDecl - This action is called immediately after + /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. /// e.g: "int x(1);" virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, @@ -1063,13 +1234,22 @@ public: return DeclPtrTy(); } - /// ActOnFriendDecl - This action is called when a friend declaration is - /// encountered. Returns false on success. - virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, - DeclPtrTy Dcl) { - return false; + /// ActOnFriendFunctionDecl - Parsed a friend function declarator. + /// The name is actually a slight misnomer, because the declarator + /// is not necessarily a function declarator. + virtual DeclPtrTy ActOnFriendFunctionDecl(Scope *S, + Declarator &D, + bool IsDefinition, + MultiTemplateParamsArg TParams) { + return DeclPtrTy(); + } + + /// ActOnFriendTypeDecl - Parsed a friend type declaration. + virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S, + const DeclSpec &DS, + MultiTemplateParamsArg TParams) { + return DeclPtrTy(); } - //===------------------------- C++ Expressions --------------------------===// @@ -1171,6 +1351,119 @@ public: return ExprEmpty(); } + /// \brief Invoked when the parser is starting to parse a C++ member access + /// expression such as x.f or x->f. + /// + /// \param S the scope in which the member access expression occurs. + /// + /// \param Base the expression in which a member is being accessed, e.g., the + /// "x" in "x.f". + /// + /// \param OpLoc the location of the member access operator ("." or "->") + /// + /// \param OpKind the kind of member access operator ("." or "->") + /// + /// \param ObjectType originally NULL. The action should fill in this type + /// with the type into which name lookup should look to find the member in + /// the member access expression. + /// + /// \returns the (possibly modified) \p Base expression + virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + TypeTy *&ObjectType) { + return ExprEmpty(); + } + + /// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example: + /// + /// t->~T(); + virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + IdentifierInfo *ClassName, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + return ExprEmpty(); + } + + /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator + /// reference, for example: + /// + /// t.operator++(); + virtual OwningExprResult + ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + OverloadedOperatorKind OverOpKind, + const CXXScopeSpec *SS = 0) { + return ExprEmpty(); + } + + /// ActOnConversionOperatorReferenceExpr - Parsed an overloaded conversion + /// function reference, for example: + /// + /// t.operator int(); + virtual OwningExprResult + ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + TypeTy *Ty, + const CXXScopeSpec *SS = 0) { + return ExprEmpty(); + } + + /// \brief Parsed a reference to a member template-id. + /// + /// This callback will occur instead of ActOnMemberReferenceExpr() when the + /// member in question is a template for which the code provides an + /// explicitly-specified template argument list, e.g., + /// + /// \code + /// x.f<int>() + /// \endcode + /// + /// \param S the scope in which the member reference expression occurs + /// + /// \param Base the expression to the left of the "." or "->". + /// + /// \param OpLoc the location of the "." or "->". + /// + /// \param OpKind the kind of operator, which will be "." or "->". + /// + /// \param SS the scope specifier that precedes the template-id in, e.g., + /// \c x.Base::f<int>(). + /// + /// \param Template the declaration of the template that is being referenced. + /// + /// \param TemplateNameLoc the location of the template name referred to by + /// \p Template. + /// + /// \param LAngleLoc the location of the left angle bracket ('<') + /// + /// \param TemplateArgs the (possibly-empty) template argument list provided + /// as part of the member reference. + /// + /// \param RAngleLoc the location of the right angle bracket ('>') + virtual OwningExprResult + ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + // FIXME: "template" keyword? + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + return ExprEmpty(); + } /// ActOnFinishFullExpr - Called whenever a full expression has been parsed. /// (C++ [intro.execution]p12). @@ -1180,18 +1473,18 @@ public: //===---------------------------- C++ Classes ---------------------------===// /// ActOnBaseSpecifier - Parsed a base specifier - virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeTy *basetype, + TypeTy *basetype, SourceLocation BaseLoc) { return BaseResult(); } - virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, + virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, unsigned NumBases) { } - + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth' /// specifies the bitfield width if there is one and 'Init' specifies the @@ -1199,6 +1492,7 @@ public: /// specifier on the function. virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, bool Deleted = false) { @@ -1223,12 +1517,14 @@ public: /// is the function declaration (which will be a C++ constructor in /// a well-formed program), ColonLoc is the location of the ':' that /// starts the constructor initializer, and MemInit/NumMemInits - /// contains the individual member (and base) initializers. - virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, + /// contains the individual member (and base) initializers. + virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits){ } + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {} + /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators /// are parsed but *before* parsing of inline method definitions. virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -1242,17 +1538,17 @@ public: /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter - /// (otherwise, "class" was used), ellipsis specifies whether this is a + /// (otherwise, "class" was used), ellipsis specifies whether this is a /// C++0x parameter pack, EllipsisLoc specifies the start of the ellipsis, - /// and KeyLoc is the location of the "class" or "typename" keyword. - // ParamName is the name of the parameter (NULL indicates an unnamed template + /// and KeyLoc is the location of the "class" or "typename" keyword. + // ParamName is the name of the parameter (NULL indicates an unnamed template // parameter) and ParamNameLoc is the location of the parameter name (if any) /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. Depth and Position provide /// the number of enclosing templates (see /// ActOnTemplateParameterList) and the number of previous /// parameters within this template parameter list. - virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, @@ -1262,8 +1558,8 @@ public: } /// ActOnTypeParameterDefault - Adds a default argument (the type - /// Default) to the given template type parameter (TypeParam). - virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, + /// Default) to the given template type parameter (TypeParam). + virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, SourceLocation EqualLoc, SourceLocation DefaultLoc, TypeTy *Default) { @@ -1277,7 +1573,7 @@ public: /// ActOnTemplateParameterList) and the number of previous /// parameters within this template parameter list. virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, - unsigned Depth, + unsigned Depth, unsigned Position) { return DeclPtrTy(); } @@ -1335,7 +1631,7 @@ public: /// @endcode /// /// ExportLoc, if valid, is the position of the "export" - /// keyword. Otherwise, "export" was not specified. + /// keyword. Otherwise, "export" was not specified. /// TemplateLoc is the position of the template keyword, LAngleLoc /// is the position of the left angle bracket, and RAngleLoc is the /// position of the corresponding right angle bracket. @@ -1344,25 +1640,13 @@ public: virtual TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, - SourceLocation TemplateLoc, + SourceLocation TemplateLoc, SourceLocation LAngleLoc, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc) { return 0; } - /// \brief Process the declaration or definition of a class template - /// with the given template parameter lists. - virtual DeclResult - ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, - SourceLocation KWLoc, const CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists, - AccessSpecifier AS) { - return DeclResult(); - } - /// \brief Form a type from a template and a list of template /// arguments. /// @@ -1372,10 +1656,6 @@ public: /// /// \param Template A template whose specialization results in a /// type, e.g., a class template or template template parameter. - /// - /// \param IsSpecialization true when we are naming the class - /// template specialization as part of an explicit class - /// specialization or class template partial specialization. virtual TypeResult ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -1385,6 +1665,25 @@ public: return TypeResult(); }; + /// \brief Note that a template ID was used with a tag. + /// + /// \param Type The result of ActOnTemplateIdType. + /// + /// \param TUK Either TUK_Reference or TUK_Friend. Declarations and + /// definitions are interpreted as explicit instantiations or + /// specializations. + /// + /// \param TagSpec The tag keyword that was provided as part of the + /// elaborated-type-specifier; either class, struct, union, or enum. + /// + /// \param TagLoc The location of the tag keyword. + virtual TypeResult ActOnTagTemplateIdType(TypeResult Type, + TagUseKind TUK, + DeclSpec::TST TagSpec, + SourceLocation TagLoc) { + return TypeResult(); + } + /// \brief Form a reference to a template-id (that will refer to a function) /// from a template and a list of template arguments. /// @@ -1402,7 +1701,7 @@ public: SourceLocation RAngleLoc) { return ExprError(); } - + /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template @@ -1410,10 +1709,26 @@ public: /// example, given "MetaFun::template apply", the scope specifier \p /// SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. + /// + /// \param TemplateKWLoc the location of the "template" keyword (if any). + /// + /// \param Name the name of the template (an identifier) + /// + /// \param NameLoc the location of the identifier + /// + /// \param SS the nested-name-specifier that precedes the "template" keyword + /// or the template name. FIXME: If the dependent template name occurs in + /// a member access expression, e.g., "x.template f<T>", this + /// nested-name-specifier will be empty. + /// + /// \param ObjectType if this dependent template name occurs in the + /// context of a member access expression, the type of the object being + /// accessed. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS, + TypeTy *ObjectType) { return TemplateTy(); } @@ -1444,8 +1759,8 @@ public: /// \param TagSpec whether this declares a class, struct, or union /// (template) /// - /// \param TK whether this is a declaration or a definition - /// + /// \param TUK whether this is a declaration or a definition + /// /// \param KWLoc the location of the 'class', 'struct', or 'union' /// keyword. /// @@ -1464,8 +1779,8 @@ public: /// parameter lists (such as a missing \c template<> prior to a /// specialization); the parser does not check this condition. virtual DeclResult - ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, - SourceLocation KWLoc, + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, @@ -1482,22 +1797,22 @@ public: /// 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 + /// being created somehow involves a template, e.g., it is a template /// declaration or specialization. - virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S, + 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, + virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { return DeclPtrTy(); } - + /// \brief Process the explicit instantiation of a class template /// specialization. /// @@ -1513,6 +1828,9 @@ public: /// /// \param S the current scope /// + /// \param ExternLoc the location of the 'extern' keyword that specifies that + /// this is an extern template (if any). + /// /// \param TemplateLoc the location of the 'template' keyword that /// specifies that this is an explicit instantiation. /// @@ -1538,8 +1856,10 @@ public: /// /// \param Attr attributes that apply to this instantiation. virtual DeclResult - ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, @@ -1551,7 +1871,7 @@ public: AttributeList *Attr) { return DeclResult(); } - + /// \brief Process the explicit instantiation of a member class of a /// class template specialization. /// @@ -1568,6 +1888,9 @@ public: /// /// \param S the current scope /// + /// \param ExternLoc the location of the 'extern' keyword that specifies that + /// this is an extern template (if any). + /// /// \param TemplateLoc the location of the 'template' keyword that /// specifies that this is an explicit instantiation. /// @@ -1593,8 +1916,10 @@ public: /// /// \param Attr attributes that apply to this instantiation. virtual DeclResult - ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, - unsigned TagSpec, + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, @@ -1603,6 +1928,38 @@ public: return DeclResult(); } + /// \brief Process the explicit instantiation of a function template or a + /// member of a class template. + /// + /// This routine is invoked when an explicit instantiation of a + /// function template or member function of a class template specialization + /// is encountered. In the following example, + /// ActOnExplicitInstantiation will be invoked to force the + /// instantiation of X<int>: + /// + /// \code + /// template<typename T> void f(T); + /// template void f(int); // explicit instantiation + /// \endcode + /// + /// \param S the current scope + /// + /// \param ExternLoc the location of the 'extern' keyword that specifies that + /// this is an extern template (if any). + /// + /// \param TemplateLoc the location of the 'template' keyword that + /// specifies that this is an explicit instantiation. + /// + /// \param D the declarator describing the declaration to be implicitly + /// instantiated. + virtual DeclResult ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D) { + return DeclResult(); + } + + /// \brief Called when the parser has parsed a C++ typename /// specifier that ends in an identifier, e.g., "typename T::type". /// @@ -1617,7 +1974,7 @@ public: } /// \brief Called when the parser has parsed a C++ typename - /// specifier that ends in a template-id, e.g., + /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply<T1, T2>". /// /// \param TypenameLoc the location of the 'typename' keyword @@ -1631,22 +1988,22 @@ public: } //===----------------------- Obj-C Declarations -------------------------===// - + // ActOnStartClassInterface - this action is called immediately after parsing - // the prologue for a class interface (before parsing the instance + // the prologue for a class interface (before parsing the instance // variables). Instance variables are processed by ActOnFields(). virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, + IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperName, + IdentifierInfo *SuperName, SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, + const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, SourceLocation EndProtoLoc, AttributeList *AttrList) { return DeclPtrTy(); } - + /// ActOnCompatiblityAlias - this action is called after complete parsing of /// @compaatibility_alias declaration. It sets up the alias relationships. virtual DeclPtrTy ActOnCompatiblityAlias( @@ -1655,11 +2012,11 @@ public: IdentifierInfo *ClassName, SourceLocation ClassLocation) { return DeclPtrTy(); } - + // ActOnStartProtocolInterface - this action is called immdiately after // parsing the prologue for a protocol interface. virtual DeclPtrTy ActOnStartProtocolInterface(SourceLocation AtProtoLoc, - IdentifierInfo *ProtocolName, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, @@ -1670,9 +2027,9 @@ public: // ActOnStartCategoryInterface - this action is called immdiately after // parsing the prologue for a category interface. virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, + IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CategoryName, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, @@ -1680,13 +2037,13 @@ public: return DeclPtrTy(); } // ActOnStartClassImplementation - this action is called immdiately after - // parsing the prologue for a class implementation. Instance variables are + // parsing the prologue for a class implementation. Instance variables are // processed by ActOnFields(). virtual DeclPtrTy ActOnStartClassImplementation( SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, + IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, + IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc) { return DeclPtrTy(); } @@ -1694,12 +2051,12 @@ public: // parsing the prologue for a category implementation. virtual DeclPtrTy ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, + IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { return DeclPtrTy(); - } + } // ActOnPropertyImplDecl - called for every property implementation virtual DeclPtrTy ActOnPropertyImplDecl( SourceLocation AtLoc, // location of the @synthesize/@dynamic @@ -1711,7 +2068,7 @@ public: IdentifierInfo *propertyIvar) { // name of the ivar return DeclPtrTy(); } - + struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; @@ -1719,12 +2076,12 @@ public: // in this case. TypeTy *Type; ObjCDeclSpec DeclSpec; - + /// ArgAttrs - Attribute list for this argument. AttributeList *ArgAttrs; }; - // ActOnMethodDeclaration - called for all method declarations. + // ActOnMethodDeclaration - called for all method declarations. virtual DeclPtrTy ActOnMethodDeclaration( SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. @@ -1736,20 +2093,20 @@ public: ObjCArgInfo *ArgInfo, // ArgInfo: Has 'Sel.getNumArgs()' entries. llvm::SmallVectorImpl<Declarator> &Cdecls, // c-style args AttributeList *MethodAttrList, // optional - // tok::objc_not_keyword, tok::objc_optional, tok::objc_required + // tok::objc_not_keyword, tok::objc_optional, tok::objc_required tok::ObjCKeywordKind impKind, bool isVariadic = false) { return DeclPtrTy(); } // ActOnAtEnd - called to mark the @end. For declarations (interfaces, - // protocols, categories), the parser passes all methods/properties. + // protocols, categories), the parser passes all methods/properties. // For class implementations, these values default to 0. For implementations, // methods are processed incrementally (by ActOnMethodDeclaration above). - virtual void ActOnAtEnd(SourceLocation AtEndLoc, + virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, - DeclPtrTy *allMethods = 0, + DeclPtrTy *allMethods = 0, unsigned allNum = 0, - DeclPtrTy *allProperties = 0, + DeclPtrTy *allProperties = 0, unsigned pNum = 0, DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0) { @@ -1763,7 +2120,7 @@ public: tok::ObjCKeywordKind MethodImplKind) { return DeclPtrTy(); } - + virtual OwningExprResult ActOnClassPropertyRefExpr( IdentifierInfo &receiverName, IdentifierInfo &propertyName, @@ -1771,17 +2128,17 @@ public: SourceLocation &propertyNameLoc) { return ExprEmpty(); } - + // ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from NumArgs. virtual ExprResult ActOnClassMessage( Scope *S, - IdentifierInfo *receivingClassName, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation selectorLoc, - SourceLocation rbrac, + SourceLocation rbrac, ExprTy **ArgExprs, unsigned NumArgs) { return ExprResult(); } @@ -1790,7 +2147,7 @@ public: // is obtained from NumArgs. virtual ExprResult ActOnInstanceMessage( ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac, + SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac, ExprTy **ArgExprs, unsigned NumArgs) { return ExprResult(); } @@ -1807,7 +2164,7 @@ public: AttributeList *AttrList) { return DeclPtrTy(); } - + /// FindProtocolDeclaration - This routine looks up protocols and /// issues error if they are not declared. It returns list of valid /// protocols found. @@ -1819,7 +2176,7 @@ public: //===----------------------- Obj-C Expressions --------------------------===// - virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ExprTy **Strings, unsigned NumStrings) { return ExprResult(); @@ -1832,7 +2189,7 @@ public: SourceLocation RParenLoc) { return ExprResult(); } - + virtual ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, @@ -1840,37 +2197,38 @@ public: SourceLocation RParenLoc) { return ExprResult(); } - + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { return ExprResult(); - } + } //===---------------------------- Pragmas -------------------------------===// enum PragmaPackKind { - PPK_Default, // #pragma pack([n]) + PPK_Default, // #pragma pack([n]) PPK_Show, // #pragma pack(show), only supported by MSVC. PPK_Push, // #pragma pack(push, [identifier], [n]) PPK_Pop // #pragma pack(pop, [identifier], [n]) }; - + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, ExprTy *Alignment, - SourceLocation PragmaLoc, + SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { return; } - + /// ActOnPragmaUnused - Called on well formed #pragma unused(...). - virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, - SourceLocation PragmaLoc, + virtual void ActOnPragmaUnused(const Token *Identifiers, + unsigned NumIdentifiers, Scope *CurScope, + SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { return; @@ -1891,6 +2249,136 @@ public: SourceLocation AliasNameLoc) { return; } + + /// \name Code completion actions + /// + /// These actions are used to signal that a code-completion token has been + /// found at a point in the grammar where the Action implementation is + /// likely to be able to provide a list of possible completions, e.g., + /// after the "." or "->" of a member access expression. + /// + /// \todo Code completion for designated field initializers + /// \todo Code completion for call arguments after a function template-id + /// \todo Code completion within a call expression, object construction, etc. + /// \todo Code completion within a template argument list. + /// \todo Code completion for attributes. + //@{ + + /// \brief Code completion for an ordinary name that occurs within the given + /// scope. + /// + /// \param S the scope in which the name occurs. + virtual void CodeCompleteOrdinaryName(Scope *S) { } + + /// \brief Code completion for a member access expression. + /// + /// This code completion action is invoked when the code-completion token + /// is found after the "." or "->" of a member access expression. + /// + /// \param S the scope in which the member access expression occurs. + /// + /// \param Base the base expression (e.g., the x in "x.foo") of the member + /// access. + /// + /// \param OpLoc the location of the "." or "->" operator. + /// + /// \param IsArrow true when the operator is "->", false when it is ".". + virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, + SourceLocation OpLoc, + bool IsArrow) { } + + /// \brief Code completion for a reference to a tag. + /// + /// This code completion action is invoked when the code-completion + /// token is found after a tag keyword (struct, union, enum, or class). + /// + /// \param S the scope in which the tag reference occurs. + /// + /// \param TagSpec an instance of DeclSpec::TST, indicating what kind of tag + /// this is (struct/union/enum/class). + virtual void CodeCompleteTag(Scope *S, unsigned TagSpec) { } + + /// \brief Code completion for a case statement. + /// + /// \brief S the scope in which the case statement occurs. + virtual void CodeCompleteCase(Scope *S) { } + + /// \brief Code completion for a call. + /// + /// \brief S the scope in which the call occurs. + /// + /// \param Fn the expression describing the function being called. + /// + /// \param Args the arguments to the function call (so far). + /// + /// \param NumArgs the number of arguments in \p Args. + virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, + ExprTy **Args, unsigned NumArgs) { } + + /// \brief Code completion for a C++ nested-name-specifier that precedes a + /// qualified-id of some form. + /// + /// This code completion action is invoked when the code-completion token + /// is found after the "::" of a nested-name-specifier. + /// + /// \param S the scope in which the nested-name-specifier occurs. + /// + /// \param SS the scope specifier ending with "::". + /// + /// \parame EnteringContext whether we're entering the context of this + /// scope specifier. + virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + bool EnteringContext) { } + + /// \brief Code completion for a C++ "using" declaration or directive. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the "using" keyword. + /// + /// \param S the scope in which the "using" occurs. + virtual void CodeCompleteUsing(Scope *S) { } + + /// \brief Code completion for a C++ using directive. + /// + /// This code completion action is invoked when the code-completion token is + /// found after "using namespace". + /// + /// \param S the scope in which the "using namespace" occurs. + virtual void CodeCompleteUsingDirective(Scope *S) { } + + /// \brief Code completion for a C++ namespace declaration or namespace + /// alias declaration. + /// + /// This code completion action is invoked when the code-completion token is + /// found after "namespace". + /// + /// \param S the scope in which the "namespace" token occurs. + virtual void CodeCompleteNamespaceDecl(Scope *S) { } + + /// \brief Code completion for a C++ namespace alias declaration. + /// + /// This code completion action is invoked when the code-completion token is + /// found after "namespace identifier = ". + /// + /// \param S the scope in which the namespace alias declaration occurs. + virtual void CodeCompleteNamespaceAliasDecl(Scope *S) { } + + /// \brief Code completion for an operator name. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the keyword "operator". + /// + /// \param S the scope in which the operator keyword occurs. + virtual void CodeCompleteOperatorName(Scope *S) { } + + /// \brief Code completion for an ObjC property decl. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the left paren. + /// + /// \param S the scope in which the operator keyword occurs. + virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { } + //@} }; /// MinimalAction - Minimal actions are used by light-weight clients of the @@ -1913,38 +2401,61 @@ public: /// getTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a typedef or not in this scope. + /// + /// \param II the identifier for which we are performing name lookup + /// + /// \param NameLoc the location of the identifier + /// + /// \param S the scope in which this name lookup occurs + /// + /// \param SS if non-NULL, the C++ scope specifier that precedes the + /// identifier + /// + /// \param isClassName whether this is a C++ class-name production, in + /// which we can end up referring to a member of an unknown specialization + /// that we know (from the grammar) is supposed to be a type. For example, + /// this occurs when deriving from "std::vector<T>::allocator_type", where T + /// is a template parameter. + /// + /// \returns the type referred to by this identifier, or NULL if the type + /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS); + Scope *S, const CXXScopeSpec *SS, + bool isClassName = false); /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S, const CXXScopeSpec *SS); - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, - TemplateTy &Template, - const CXXScopeSpec *SS = 0); + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectType, + bool EnteringContext, + TemplateTy &Template); /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is /// popped. virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D); - - /// ActOnPopScope - When a scope is popped, if any typedefs are now + + /// ActOnPopScope - When a scope is popped, if any typedefs are now /// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field. virtual void ActOnPopScope(SourceLocation Loc, Scope *S); virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); - + virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, unsigned NumElts); - + virtual DeclPtrTy ActOnStartClassInterface(SourceLocation interLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, + const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -1964,15 +2475,15 @@ public: Action &actions, SourceManager &sm, const char *Msg) : TheDecl(Decl), Loc(L), Actions(actions), SM(sm), Message(Msg) {} - + virtual void print(llvm::raw_ostream &OS) const; -}; - +}; + /// \brief RAII object that enters a new expression evaluation context. -class EnterExpressionEvaluationContext { +class EnterExpressionEvaluationContext { /// \brief The action object. Action &Actions; - + /// \brief The previous expression evaluation context. Action::ExpressionEvaluationContext PrevContext; @@ -1981,16 +2492,16 @@ class EnterExpressionEvaluationContext { public: EnterExpressionEvaluationContext(Action &Actions, - Action::ExpressionEvaluationContext NewContext) - : Actions(Actions), CurContext(NewContext) { + Action::ExpressionEvaluationContext NewContext) + : Actions(Actions), CurContext(NewContext) { PrevContext = Actions.PushExpressionEvaluationContext(NewContext); } - + ~EnterExpressionEvaluationContext() { Actions.PopExpressionEvaluationContext(CurContext, PrevContext); } }; - + } // end namespace clang #endif diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 50ca88acbce9..9fcc845cb006 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -21,7 +21,7 @@ namespace clang { class IdentifierInfo; class Action; - + /// AttributeList - Represents GCC's __attribute__ declaration. There are /// 4 forms of this construct...they are: /// @@ -47,7 +47,7 @@ public: ActionBase::ExprTy **args, unsigned numargs, AttributeList *Next, bool declspec = false); ~AttributeList(); - + enum Kind { // Please keep this list alphabetized. AT_IBOutlet, // Clang-specific. AT_address_space, @@ -69,6 +69,7 @@ public: AT_format, AT_format_arg, AT_gnu_inline, + AT_malloc, AT_mode, AT_nodebug, AT_noinline, @@ -101,67 +102,57 @@ public: IgnoredAttribute, UnknownAttribute }; - + IdentifierInfo *getName() const { return AttrName; } SourceLocation getLoc() const { return AttrLoc; } IdentifierInfo *getParameterName() const { return ParmName; } bool isDeclspecAttribute() const { return DeclspecAttribute; } - + Kind getKind() const { return getKind(getName()); } static Kind getKind(const IdentifierInfo *Name); - + AttributeList *getNext() const { return Next; } void setNext(AttributeList *N) { Next = N; } - - void addAttributeList(AttributeList *alist) { - assert((alist != 0) && "addAttributeList(): alist is null"); - AttributeList *next = this, *prev; - do { - prev = next; - next = next->getNext(); - } while (next); - prev->setNext(alist); - } /// getNumArgs - Return the number of actual arguments to this attribute. unsigned getNumArgs() const { return NumArgs; } - + /// getArg - Return the specified argument. ActionBase::ExprTy *getArg(unsigned Arg) const { assert(Arg < NumArgs && "Arg access out of range!"); return Args[Arg]; } - + class arg_iterator { ActionBase::ExprTy** X; unsigned Idx; public: - arg_iterator(ActionBase::ExprTy** x, unsigned idx) : X(x), Idx(idx) {} + arg_iterator(ActionBase::ExprTy** x, unsigned idx) : X(x), Idx(idx) {} arg_iterator& operator++() { ++Idx; return *this; } - + bool operator==(const arg_iterator& I) const { assert (X == I.X && "compared arg_iterators are for different argument lists"); return Idx == I.Idx; } - + bool operator!=(const arg_iterator& I) const { return !operator==(I); } - + ActionBase::ExprTy* operator*() const { return X[Idx]; } - + unsigned getArgNum() const { return Idx+1; } }; - + arg_iterator arg_begin() const { return arg_iterator(Args, 0); } @@ -171,6 +162,24 @@ public: } }; +/// addAttributeLists - Add two AttributeLists together +/// The right-hand list is appended to the left-hand list, if any +/// A pointer to the joined list is returned. +/// Note: the lists are not left unmodified. +inline AttributeList* addAttributeLists (AttributeList *Left, + AttributeList *Right) { + if (!Left) + return Right; + + AttributeList *next = Left, *prev; + do { + prev = next; + next = next->getNext(); + } while (next); + prev->setNext(Right); + return Left; +} + } // end namespace clang #endif diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 300602e5147c..51970f1867d9 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -25,7 +25,7 @@ namespace clang { class IdentifierInfo; class Preprocessor; class Declarator; - + /// DeclSpec - This class captures information about "declaration specifiers", /// which encompasses storage-class-specifiers, type-specifiers, /// type-qualifiers, and function-specifiers. @@ -42,7 +42,7 @@ public: SCS_private_extern, SCS_mutable }; - + // type-specifier enum TSW { TSW_unspecified, @@ -50,24 +50,26 @@ public: TSW_long, TSW_longlong }; - + enum TSC { TSC_unspecified, TSC_imaginary, TSC_complex }; - + enum TSS { TSS_unspecified, TSS_signed, TSS_unsigned }; - + enum TST { TST_unspecified, TST_void, TST_char, TST_wchar, // C++ wchar_t + TST_char16, // C++0x char16_t + TST_char32, // C++0x char32_t TST_int, TST_float, TST_double, @@ -86,9 +88,9 @@ public: TST_auto, // C++0x auto TST_error // erroneous type }; - + // type-qualifiers - enum TQ { // NOTE: These flags must be kept in sync with QualType::TQ. + enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. TQ_unspecified = 0, TQ_const = 1, TQ_restrict = 2, @@ -104,9 +106,9 @@ public: PQ_TypeQualifier = 4, PQ_FunctionSpecifier = 8 }; - + private: - + // storage-class-specifier /*SCS*/unsigned StorageClassSpec : 3; bool SCS_thread_specified : 1; @@ -120,50 +122,45 @@ private: // type-qualifiers unsigned TypeQualifiers : 3; // Bitwise OR of TQ. - + // function-specifier bool FS_inline_specified : 1; bool FS_virtual_specified : 1; bool FS_explicit_specified : 1; - + // friend-specifier bool Friend_specified : 1; - + /// TypeRep - This contains action-specific information about a specific TST. /// For example, for a typedef or struct, it might contain the declaration for /// these. - void *TypeRep; - + void *TypeRep; + // attributes. AttributeList *AttrList; - - // List of protocol qualifiers for objective-c classes. Used for + + // List of protocol qualifiers for objective-c classes. Used for // protocol-qualified interfaces "NString<foo>" and protocol-qualified id // "id<foo>". const ActionBase::DeclPtrTy *ProtocolQualifiers; unsigned NumProtocolQualifiers; - + SourceLocation ProtocolLAngleLoc; + SourceLocation *ProtocolLocs; + // SourceLocation info. These are null if the item wasn't specified or if // the setting was synthesized. SourceRange Range; - + SourceLocation StorageClassSpecLoc, SCS_threadLoc; SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; SourceLocation FriendLoc; - - bool BadSpecifier(TST T, const char *&PrevSpec); - bool BadSpecifier(TQ T, const char *&PrevSpec); - bool BadSpecifier(TSS T, const char *&PrevSpec); - bool BadSpecifier(TSC T, const char *&PrevSpec); - bool BadSpecifier(TSW T, const char *&PrevSpec); - bool BadSpecifier(SCS T, const char *&PrevSpec); - + DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT void operator=(const DeclSpec&); // DO NOT IMPLEMENT -public: - +public: + DeclSpec() : StorageClassSpec(SCS_unspecified), SCS_thread_specified(false), @@ -180,26 +177,28 @@ public: TypeRep(0), AttrList(0), ProtocolQualifiers(0), - NumProtocolQualifiers(0) { + NumProtocolQualifiers(0), + ProtocolLocs(0) { } ~DeclSpec() { delete AttrList; delete [] ProtocolQualifiers; + delete [] ProtocolLocs; } // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } bool isThreadSpecified() const { return SCS_thread_specified; } - + SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; } - + void ClearStorageClassSpecs() { StorageClassSpec = DeclSpec::SCS_unspecified; SCS_thread_specified = false; StorageClassSpecLoc = SourceLocation(); SCS_threadLoc = SourceLocation(); } - + // type-specifier TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; } TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } @@ -207,18 +206,22 @@ public: TST getTypeSpecType() const { return (TST)TypeSpecType; } bool isTypeSpecOwned() const { return TypeSpecOwned; } void *getTypeRep() const { return TypeRep; } - + const SourceRange &getSourceRange() const { return Range; } SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } - + /// getSpecifierName - Turn a type-specifier-type into a string like "_Bool" /// or "union". static const char *getSpecifierName(DeclSpec::TST T); + static const char *getSpecifierName(DeclSpec::TQ Q); + static const char *getSpecifierName(DeclSpec::TSS S); + static const char *getSpecifierName(DeclSpec::TSC C); + static const char *getSpecifierName(DeclSpec::TSW W); static const char *getSpecifierName(DeclSpec::SCS S); - + // type-qualifiers /// getTypeQualifiers - Return a set of TQs. @@ -226,7 +229,7 @@ public: SourceLocation getConstSpecLoc() const { return TQ_constLoc; } SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } - + // function-specifier bool isInlineSpecified() const { return FS_inline_specified; } SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; } @@ -245,7 +248,7 @@ public: FS_explicit_specified = false; FS_explicitLoc = SourceLocation(); } - + /// hasTypeSpecifier - Return true if any type-specifier has been found. bool hasTypeSpecifier() const { return getTypeSpecType() != DeclSpec::TST_unspecified || @@ -253,68 +256,81 @@ public: getTypeSpecComplex() != DeclSpec::TSC_unspecified || getTypeSpecSign() != DeclSpec::TSS_unspecified; } - + /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this /// DeclSpec includes. /// unsigned getParsedSpecifiers() const; - + /// isEmpty - Return true if this declaration specifier is completely empty: /// no tokens were parsed in the production of it. bool isEmpty() const { return getParsedSpecifiers() == DeclSpec::PQ_None; } - + void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } - - /// These methods set the specified attribute of the DeclSpec, but return true - /// and ignore the request if invalid (e.g. "extern" then "auto" is - /// specified). The name of the previous specifier is returned in prevspec. - bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec); - bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec); - bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec); - bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec); - bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec); + + /// These methods set the specified attribute of the DeclSpec and + /// return false if there was no error. If an error occurs (for + /// example, if we tried to set "auto" on a spec with "extern" + /// already set), they return true and set PrevSpec and DiagID + /// such that + /// Diag(Loc, DiagID) << PrevSpec; + /// will yield a useful result. + /// + /// TODO: use a more general approach that still allows these + /// diagnostics to be ignored when desired. + bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, - void *Rep = 0, bool Owned = false); + unsigned &DiagID, void *Rep = 0, bool Owned = false); bool SetTypeSpecError(); + void UpdateTypeRep(void *Rep) { TypeRep = Rep; } bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, - const LangOptions &Lang); - - bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec); - bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec); - bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec); - - bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec); + unsigned &DiagID, const LangOptions &Lang); + + bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool isFriendSpecified() const { return Friend_specified; } SourceLocation getFriendSpecLoc() const { return FriendLoc; } - /// AddAttributes - contatenates two attribute lists. + /// AddAttributes - contatenates two attribute lists. /// The GCC attribute syntax allows for the following: /// - /// short __attribute__(( unused, deprecated )) + /// short __attribute__(( unused, deprecated )) /// int __attribute__(( may_alias, aligned(16) )) var; /// /// This declares 4 attributes using 2 lists. The following syntax is /// also allowed and equivalent to the previous declaration. /// - /// short __attribute__((unused)) __attribute__((deprecated)) + /// short __attribute__((unused)) __attribute__((deprecated)) /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; - /// + /// void AddAttributes(AttributeList *alist) { - if (!alist) - return; // we parsed __attribute__(()) or had a syntax error - - if (AttrList) - alist->addAttributeList(AttrList); - AttrList = alist; + AttrList = addAttributeLists(AttrList, alist); } void SetAttributes(AttributeList *AL) { AttrList = AL; } const AttributeList *getAttributes() const { return AttrList; } AttributeList *getAttributes() { return AttrList; } - + /// TakeAttributes - Return the current attribute list and remove them from /// the DeclSpec so that it doesn't own them. AttributeList *TakeAttributes() { @@ -322,21 +338,20 @@ public: AttrList = 0; return AL; } - + typedef const ActionBase::DeclPtrTy *ProtocolQualifierListTy; ProtocolQualifierListTy getProtocolQualifiers() const { return ProtocolQualifiers; } + SourceLocation *getProtocolLocs() const { return ProtocolLocs; } unsigned getNumProtocolQualifiers() const { return NumProtocolQualifiers; } - void setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP) { - if (NP == 0) return; - ProtocolQualifiers = new ActionBase::DeclPtrTy[NP]; - memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP); - NumProtocolQualifiers = NP; - } - + SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; } + void setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP, + SourceLocation *ProtoLocs, + SourceLocation LAngleLoc); + /// Finish - This does final analysis of the declspec, issuing diagnostics for /// things like "_Imaginary" (lacking an FP type). After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. @@ -347,7 +362,7 @@ public: bool isMissingDeclaratorOk(); }; -/// ObjCDeclSpec - This class captures information about +/// ObjCDeclSpec - This class captures information about /// "declaration specifiers" specific to objective-c class ObjCDeclSpec { public: @@ -361,47 +376,46 @@ public: DQ_Byref = 0x10, DQ_Oneway = 0x20 }; - + /// PropertyAttributeKind - list of property attributes. - enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0, - DQ_PR_readonly = 0x01, - DQ_PR_getter = 0x02, - DQ_PR_assign = 0x04, - DQ_PR_readwrite = 0x08, + enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0, + DQ_PR_readonly = 0x01, + DQ_PR_getter = 0x02, + DQ_PR_assign = 0x04, + DQ_PR_readwrite = 0x08, DQ_PR_retain = 0x10, - DQ_PR_copy = 0x20, + DQ_PR_copy = 0x20, DQ_PR_nonatomic = 0x40, DQ_PR_setter = 0x80 }; - - + + ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), - GetterName(0), SetterName(0) - {} + GetterName(0), SetterName(0) { } ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } - void setObjCDeclQualifier(ObjCDeclQualifier DQVal) + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); } - - ObjCPropertyAttributeKind getPropertyAttributes() const + + ObjCPropertyAttributeKind getPropertyAttributes() const { return ObjCPropertyAttributeKind(PropertyAttributes); } - void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { - PropertyAttributes = + void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { + PropertyAttributes = (ObjCPropertyAttributeKind) (PropertyAttributes | PRVal); } - + const IdentifierInfo *getGetterName() const { return GetterName; } IdentifierInfo *getGetterName() { return GetterName; } void setGetterName(IdentifierInfo *name) { GetterName = name; } - + const IdentifierInfo *getSetterName() const { return SetterName; } IdentifierInfo *getSetterName() { return SetterName; } void setSetterName(IdentifierInfo *name) { SetterName = name; } private: - // FIXME: These two are unrelated and mutially exclusive. So perhaps + // FIXME: These two are unrelated and mutially exclusive. So perhaps // we can put them in a union to reflect their mutual exclusiveness // (space saving is negligible). ObjCDeclQualifier objcDeclQualifier : 6; - + // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind unsigned PropertyAttributes : 8; IdentifierInfo *GetterName; // getter name of NULL if no getter @@ -441,7 +455,7 @@ public: ScopeRep = 0; } }; - + /// CachedTokens - A set of tokens that has been cached for later /// parsing. typedef llvm::SmallVector<Token, 4> CachedTokens; @@ -457,7 +471,9 @@ struct DeclaratorChunk { /// Loc - The place where this type was defined. SourceLocation Loc; - + /// EndLoc - If valid, the place where this chunck ends. + SourceLocation EndLoc; + struct PointerTypeInfo { /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; @@ -481,20 +497,20 @@ struct DeclaratorChunk { struct ArrayTypeInfo { /// The type qualifiers for the array: const/volatile/restrict. unsigned TypeQuals : 3; - + /// True if this dimension included the 'static' keyword. bool hasStatic : 1; - + /// True if this dimension was [*]. In this case, NumElts is null. bool isStar : 1; - + /// This is the size of the array, or null if [] or [*] was specified. /// Since the parser is multi-purpose, and we don't want to impose a root /// expression class on all clients, NumElts is untyped. ActionBase::ExprTy *NumElts; void destroy() {} }; - + /// ParamInfo - An array of paraminfo objects is allocated whenever a function /// declarator is parsed. There are two interesting styles of arguments here: /// K&R-style identifier lists and parameter type lists. K&R-style identifier @@ -517,7 +533,7 @@ struct DeclaratorChunk { ParamInfo(IdentifierInfo *ident, SourceLocation iloc, ActionBase::DeclPtrTy param, CachedTokens *DefArgTokens = 0) - : Ident(ident), IdentLoc(iloc), Param(param), + : Ident(ident), IdentLoc(iloc), Param(param), DefaultArgTokens(DefArgTokens) {} }; @@ -538,7 +554,7 @@ struct DeclaratorChunk { bool isVariadic : 1; /// The type qualifiers: const/volatile/restrict. - /// The qualifier bitmask values are the same as in QualType. + /// The qualifier bitmask values are the same as in QualType. unsigned TypeQuals : 3; /// hasExceptionSpec - True if the function has an exception specification. @@ -678,7 +694,7 @@ struct DeclaratorChunk { I.Ptr.AttrList = AL; return I; } - + /// getReference - Return a DeclaratorChunk for a reference. /// static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, @@ -691,22 +707,23 @@ struct DeclaratorChunk { I.Ref.AttrList = AL; return I; } - + /// getArray - Return a DeclaratorChunk for an array. /// static DeclaratorChunk getArray(unsigned TypeQuals, bool isStatic, bool isStar, void *NumElts, - SourceLocation Loc) { + SourceLocation LBLoc, SourceLocation RBLoc) { DeclaratorChunk I; I.Kind = Array; - I.Loc = Loc; + I.Loc = LBLoc; + I.EndLoc = RBLoc; I.Arr.TypeQuals = TypeQuals; I.Arr.hasStatic = isStatic; I.Arr.isStar = isStar; I.Arr.NumElts = NumElts; return I; } - + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, @@ -717,9 +734,10 @@ struct DeclaratorChunk { bool hasAnyExceptionSpec, ActionBase::TypeTy **Exceptions, SourceRange *ExceptionRanges, - unsigned NumExceptions, SourceLocation Loc, + unsigned NumExceptions, + SourceLocation LPLoc, SourceLocation RPLoc, Declarator &TheDeclarator); - + /// getBlockPointer - Return a DeclaratorChunk for a block. /// static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc, @@ -775,12 +793,14 @@ public: /// DeclaratorKind - The kind of declarator this represents. enum DeclaratorKind { DK_Abstract, // An abstract declarator (has no identifier) - DK_Normal, // A normal declarator (has an identifier). + DK_Normal, // A normal declarator (has an identifier). DK_Constructor, // A C++ constructor (identifier is the class name) DK_Destructor, // A C++ destructor (identifier is ~class name) DK_Operator, // A C++ overloaded operator name - DK_Conversion // A C++ conversion function (identifier is + DK_Conversion, // A C++ conversion function (identifier is // "operator " then the type name) + DK_TemplateId // A C++ template-id naming a function template + // specialization. }; private: @@ -794,7 +814,7 @@ private: /// TheContext Context; - /// Kind - What kind of declarator this is. + /// Kind - What kind of declarator this is. DeclaratorKind Kind; /// DeclTypeInfo - This holds each type that the declarator includes as it is @@ -811,7 +831,7 @@ private: /// AttrList - Attributes. AttributeList *AttrList; - + /// AsmLabel - The asm label, if specified. ActionBase::ExprTy *AsmLabel; @@ -824,6 +844,10 @@ private: /// When Kind is DK_Operator, this is the actual overloaded /// operator that this declarator names. OverloadedOperatorKind OperatorKind; + + /// When Kind is DK_TemplateId, this is the template-id annotation that + /// contains the template and its template arguments. + TemplateIdAnnotation *TemplateId; }; /// InlineParams - This is a local array used for the first function decl @@ -832,6 +856,9 @@ private: DeclaratorChunk::ParamInfo InlineParams[16]; bool InlineParamsUsed; + /// Extension - true if the declaration is preceded by __extension__. + bool Extension : 1; + friend struct DeclaratorChunk; public: @@ -840,9 +867,9 @@ public: Kind(DK_Abstract), InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), GroupingParens(false), AttrList(0), AsmLabel(0), Type(0), - InlineParamsUsed(false) { + InlineParamsUsed(false), Extension(false) { } - + ~Declarator() { clear(); } @@ -850,7 +877,7 @@ public: /// getDeclSpec - Return the declaration-specifier that this declarator was /// declared with. const DeclSpec &getDeclSpec() const { return DS; } - + /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This /// should be used with extreme care: declspecs can often be shared between /// multiple declarators, so mutating the DeclSpec affects all of the @@ -898,6 +925,10 @@ public: Identifier = 0; IdentifierLoc = SourceLocation(); Range = DS.getSourceRange(); + + if (Kind == DK_TemplateId) + TemplateId->Destroy(); + Kind = DK_Abstract; for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) @@ -909,9 +940,9 @@ public: Type = 0; InlineParamsUsed = false; } - + /// mayOmitIdentifier - Return true if the identifier is either optional or - /// not allowed. This is true for typenames, prototypes, and template + /// not allowed. This is true for typenames, prototypes, and template /// parameter lists. bool mayOmitIdentifier() const { return Context == TypeNameContext || Context == PrototypeContext || @@ -934,7 +965,7 @@ public: Context == BlockContext || Context == ForContext); } - + /// isPastIdentifier - Return true if we have parsed beyond the point where /// the bool isPastIdentifier() const { return IdentifierLoc.isValid(); } @@ -946,7 +977,7 @@ public: IdentifierInfo *getIdentifier() const { return Identifier; } SourceLocation getIdentifierLoc() const { return IdentifierLoc; } - + void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) { Identifier = ID; IdentifierLoc = Loc; @@ -956,7 +987,7 @@ public: Kind = DK_Abstract; SetRangeEnd(Loc); } - + /// setConstructor - Set this declarator to be a C++ constructor /// declarator. Also extends the range. void setConstructor(ActionBase::TypeTy *Ty, SourceLocation Loc) { @@ -1005,6 +1036,16 @@ public: SetRangeEnd(EndLoc); } + /// \brief Set this declaration to be a C++ template-id, which includes the + /// template (or set of function templates) along with template arguments. + void setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id provided to declarator?"); + IdentifierLoc = TemplateId->TemplateNameLoc; + Kind = DK_TemplateId; + SetRangeEnd(TemplateId->RAngleLoc); + this->TemplateId = TemplateId; + } + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { @@ -1016,7 +1057,7 @@ public: /// getNumTypeObjects() - Return the number of types applied to this /// declarator. unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } - + /// Return the specified TypeInfo from this declarator. TypeInfo #0 is /// closest to the identifier. const DeclaratorChunk &getTypeObject(unsigned i) const { @@ -1027,14 +1068,14 @@ public: assert(i < DeclTypeInfo.size() && "Invalid type chunk"); return DeclTypeInfo[i]; } - + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, /// this method returns true if the identifier is a function declarator. bool isFunctionDeclarator() const { return !DeclTypeInfo.empty() && DeclTypeInfo[0].Kind == DeclaratorChunk::Function; } - + /// AddAttributes - simply adds the attribute list to the Declarator. /// These examples both add 3 attributes to "var": /// short int var __attribute__((aligned(16),common,deprecated)); @@ -1042,31 +1083,50 @@ public: /// __attribute__((common,deprecated)); /// /// Also extends the range of the declarator. - void AddAttributes(AttributeList *alist, SourceLocation LastLoc) { - if (!alist) - return; // we parsed __attribute__(()) or had a syntax error - - if (AttrList) - alist->addAttributeList(AttrList); - AttrList = alist; + void AddAttributes(AttributeList *alist, SourceLocation LastLoc) { + AttrList = addAttributeLists(AttrList, alist); if (!LastLoc.isInvalid()) SetRangeEnd(LastLoc); } - + const AttributeList *getAttributes() const { return AttrList; } AttributeList *getAttributes() { return AttrList; } + /// hasAttributes - do we contain any attributes? + bool hasAttributes() const { + if (getAttributes() || getDeclSpec().getAttributes()) return true; + for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) + if (getTypeObject(i).getAttrs()) + return true; + return false; + } + void setAsmLabel(ActionBase::ExprTy *E) { AsmLabel = E; } ActionBase::ExprTy *getAsmLabel() const { return AsmLabel; } - ActionBase::TypeTy *getDeclaratorIdType() const { return Type; } + void setExtension(bool Val = true) { Extension = Val; } + bool getExtension() const { return Extension; } - OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; } + ActionBase::TypeTy *getDeclaratorIdType() const { + assert((Kind == DK_Constructor || Kind == DK_Destructor || + Kind == DK_Conversion) && "Declarator kind does not have a type"); + return Type; + } + OverloadedOperatorKind getOverloadedOperator() const { + assert(Kind == DK_Operator && "Declarator is not an overloaded operator"); + return OperatorKind; + } + + TemplateIdAnnotation *getTemplateId() { + assert(Kind == DK_TemplateId && "Declarator is not a template-id"); + return TemplateId; + } + void setInvalidType(bool Val = true) { InvalidType = Val; } - bool isInvalidType() const { - return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; + bool isInvalidType() const { + return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; } void setGroupingParens(bool flag) { GroupingParens = flag; } diff --git a/include/clang/Parse/Designator.h b/include/clang/Parse/Designator.h index 026286d318fb..255af5901819 100644 --- a/include/clang/Parse/Designator.h +++ b/include/clang/Parse/Designator.h @@ -18,7 +18,7 @@ #include "clang/Parse/Action.h" namespace clang { - + /// Designator - This class is a discriminated union which holds the various /// different sorts of designators possible. A Designation is an array of /// these. An example of a designator are things like this: @@ -34,7 +34,7 @@ public: }; private: DesignatorKind Kind; - + struct FieldDesignatorInfo { const IdentifierInfo *II; unsigned DotLoc; @@ -50,15 +50,15 @@ private: unsigned LBracketLoc, EllipsisLoc; mutable unsigned RBracketLoc; }; - + union { FieldDesignatorInfo FieldInfo; ArrayDesignatorInfo ArrayInfo; ArrayRangeDesignatorInfo ArrayRangeInfo; }; - + public: - + DesignatorKind getKind() const { return Kind; } bool isFieldDesignator() const { return Kind == FieldDesignator; } bool isArrayDesignator() const { return Kind == ArrayDesignator; } @@ -78,7 +78,7 @@ public: assert(isFieldDesignator() && "Invalid accessor"); return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc); } - + ActionBase::ExprTy *getArrayIndex() const { assert(isArrayDesignator() && "Invalid accessor"); return ArrayInfo.Index; @@ -92,22 +92,22 @@ public: assert(isArrayRangeDesignator() && "Invalid accessor"); return ArrayRangeInfo.End; } - + SourceLocation getLBracketLoc() const { - assert((isArrayDesignator() || isArrayRangeDesignator()) && + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Invalid accessor"); if (isArrayDesignator()) return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc); - else + else return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc); } SourceLocation getRBracketLoc() const { - assert((isArrayDesignator() || isArrayRangeDesignator()) && + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Invalid accessor"); if (isArrayDesignator()) return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc); - else + else return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc); } @@ -135,10 +135,10 @@ public: D.ArrayInfo.RBracketLoc = 0; return D; } - + static Designator getArrayRange(ActionBase::ExprTy *Start, ActionBase::ExprTy *End, - SourceLocation LBracketLoc, + SourceLocation LBracketLoc, SourceLocation EllipsisLoc) { Designator D; D.Kind = ArrayRangeDesignator; @@ -151,14 +151,14 @@ public: } void setRBracketLoc(SourceLocation RBracketLoc) const { - assert((isArrayDesignator() || isArrayRangeDesignator()) && + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Invalid accessor"); if (isArrayDesignator()) ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding(); else ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding(); } - + /// ClearExprs - Null out any expression references, which prevents them from /// being 'delete'd later. void ClearExprs(Action &Actions) { @@ -173,7 +173,7 @@ public: return; } } - + /// FreeExprs - Release any unclaimed memory for the expressions in this /// designator. void FreeExprs(Action &Actions) { @@ -190,7 +190,7 @@ public: } }; - + /// Designation - Represent a full designation, which is a sequence of /// designators. This class is mostly a helper for InitListDesignations. class Designation { @@ -198,10 +198,10 @@ class Designation { /// example, if the initializer were "{ A, .foo=B, C }" a Designation would /// exist with InitIndex=1, because element #1 has a designation. unsigned InitIndex; - + /// Designators - The actual designators for this initializer. llvm::SmallVector<Designator, 2> Designators; - + Designation(unsigned Idx) : InitIndex(Idx) {} public: Designation() : InitIndex(4000) {} @@ -218,14 +218,14 @@ public: assert(Idx < Designators.size()); return Designators[Idx]; } - + /// ClearExprs - Null out any expression references, which prevents them from /// being 'delete'd later. void ClearExprs(Action &Actions) { for (unsigned i = 0, e = Designators.size(); i != e; ++i) Designators[i].ClearExprs(Actions); } - + /// FreeExprs - Release any unclaimed memory for the expressions in this /// designation. void FreeExprs(Action &Actions) { @@ -233,7 +233,7 @@ public: Designators[i].FreeExprs(Actions); } }; - + } // end namespace clang #endif diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h index 987edfa96dd1..9bd69c5fdb68 100644 --- a/include/clang/Parse/Ownership.h +++ b/include/clang/Parse/Ownership.h @@ -23,7 +23,7 @@ namespace clang { class ActionBase; - + /// OpaquePtr - This is a very simple POD type that wraps a pointer that the /// Parser doesn't know about but that Sema or another client does. The UID /// template argument is used to make sure that "Decl" pointers are not @@ -33,29 +33,29 @@ namespace clang { void *Ptr; public: OpaquePtr() : Ptr(0) {} - + template <typename T> T* getAs() const { return llvm::PointerLikeTypeTraits<T*>::getFromVoidPointer(Ptr); } - + template <typename T> T getAsVal() const { return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(Ptr); } - + void *get() const { return Ptr; } - + template<typename T> static OpaquePtr make(T P) { OpaquePtr R; R.set(P); return R; } - + template<typename T> void set(T P) { Ptr = llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(P); } - + operator bool() const { return Ptr != 0; } }; } @@ -218,7 +218,7 @@ namespace clang { /// expressions, stmts, etc. It encapsulates both the object returned by /// the action, plus a sense of whether or not it is valid. /// When CompressInvalid is true, the "invalid" flag will be - /// stored in the low bit of the Val pointer. + /// stored in the low bit of the Val pointer. template<unsigned UID, typename PtrTy = void*, bool CompressInvalid = IsResultPtrLowBitFree<UID>::value> @@ -252,7 +252,7 @@ namespace clang { uintptr_t PtrWithInvalid; typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits; public: - ActionResult(bool Invalid = false) + ActionResult(bool Invalid = false) : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { } template<typename ActualExprTy> @@ -262,17 +262,17 @@ namespace clang { PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); } - + ActionResult(PtrTy V) { void *VP = PtrTraits::getAsVoidPointer(V); PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); } - + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { } PtrTy get() const { - void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); + void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); return PtrTraits::getFromVoidPointer(VP); } @@ -326,8 +326,7 @@ namespace clang { /// Move emulation helper for ASTOwningResult. NEVER EVER use this class /// directly if you don't know what you're doing. template <ASTDestroyer Destroyer> - class ASTResultMover - { + class ASTResultMover { ASTOwningResult<Destroyer> &Moved; public: @@ -339,8 +338,7 @@ namespace clang { /// Move emulation helper for ASTMultiPtr. NEVER EVER use this class /// directly if you don't know what you're doing. template <ASTDestroyer Destroyer> - class ASTMultiMover - { + class ASTMultiMover { ASTMultiPtr<Destroyer> &Moved; public: @@ -357,8 +355,7 @@ namespace clang { /// Kept only as a type-safe wrapper for a void pointer, when smart pointers /// are disabled. When they are enabled, ASTOwningResult takes over. template <ASTDestroyer Destroyer> - class ASTOwningPtr - { + class ASTOwningPtr { void *Node; public: @@ -400,8 +397,7 @@ namespace clang { #if !defined(DISABLE_SMART_POINTERS) template <ASTDestroyer Destroyer> - class ASTOwningResult - { + class ASTOwningResult { llvm::PointerIntPair<ActionBase*, 1, bool> ActionInv; void *Ptr; @@ -505,8 +501,7 @@ namespace clang { }; #else template <ASTDestroyer Destroyer> - class ASTOwningResult - { + class ASTOwningResult { public: typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult; @@ -522,8 +517,7 @@ namespace clang { ASTOwningResult(const ASTOwningPtr<Destroyer> &o) : Result(o.get()) { } /// Assignment from a raw pointer. Takes ownership - beware! - ASTOwningResult & operator =(void *raw) - { + ASTOwningResult & operator =(void *raw) { Result = raw; return *this; } @@ -563,8 +557,7 @@ namespace clang { #endif template <ASTDestroyer Destroyer> - class ASTMultiPtr - { + class ASTMultiPtr { #if !defined(DISABLE_SMART_POINTERS) ActionBase &Actions; #endif @@ -584,7 +577,7 @@ namespace clang { // Either way, a classic C-style hard cast resolves any issue. static ASTMultiPtr* hack(moving::ASTMultiMover<Destroyer> & source) { return (ASTMultiPtr*)source.operator->(); - } + } #endif ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT @@ -608,7 +601,7 @@ namespace clang { /// Move constructor ASTMultiPtr(moving::ASTMultiMover<Destroyer> mover) #if defined(_MSC_VER) - // Apply the visual C++ hack supplied above. + // Apply the visual C++ hack supplied above. // Last tested with Visual Studio 2008. : Actions(hack(mover)->Actions), Nodes(hack(mover)->Nodes), Count(hack(mover)->Count) { #else @@ -660,7 +653,7 @@ namespace clang { } #endif }; - + class ASTTemplateArgsPtr { #if !defined(DISABLE_SMART_POINTERS) ActionBase &Actions; @@ -668,7 +661,7 @@ namespace clang { void **Args; bool *ArgIsType; mutable unsigned Count; - + #if !defined(DISABLE_SMART_POINTERS) void destroy() { if (!Count) @@ -684,16 +677,16 @@ namespace clang { public: ASTTemplateArgsPtr(ActionBase &actions, void **args, bool *argIsType, - unsigned count) : + unsigned count) : #if !defined(DISABLE_SMART_POINTERS) - Actions(actions), + Actions(actions), #endif Args(args), ArgIsType(argIsType), Count(count) { } // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'. - ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) : + ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) : #if !defined(DISABLE_SMART_POINTERS) - Actions(Other.Actions), + Actions(Other.Actions), #endif Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) { #if !defined(DISABLE_SMART_POINTERS) @@ -734,7 +727,7 @@ namespace clang { void *operator[](unsigned Arg) const { return Args[Arg]; } - void **release() const { + void **release() const { #if !defined(DISABLE_SMART_POINTERS) Count = 0; #endif @@ -754,7 +747,7 @@ namespace clang { ASTOwningVector &operator=(ASTOwningVector &); // do not implement public: - explicit ASTOwningVector(ActionBase &Actions) + explicit ASTOwningVector(ActionBase &Actions) #if !defined(DISABLE_SMART_POINTERS) : Actions(Actions), Owned(true) #endif @@ -825,8 +818,7 @@ namespace clang { template <ASTDestroyer Destroyer> inline ASTOwningPtr<Destroyer>::ASTOwningPtr(const ASTOwningResult<Destroyer> &o) - : Node(o.get()) - {} + : Node(o.get()) { } // These versions are hopefully no-ops. template <ASTDestroyer Destroyer> inline diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h index fa600ddadfab..c702e2fe65b8 100644 --- a/include/clang/Parse/ParseDiagnostic.h +++ b/include/clang/Parse/ParseDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define PARSESTART diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e2380542ae6f..9cb4677f6637 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -38,8 +38,8 @@ public: PrettyStackTraceParserEntry(const Parser &p) : P(p) {} virtual void print(llvm::raw_ostream &OS) const; }; - - + + /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has /// been read. @@ -47,13 +47,13 @@ public: class Parser { friend class PragmaUnusedHandler; PrettyStackTraceParserEntry CrashInfo; - + Preprocessor &PP; - + /// Tok - The current token we are peeking ahead. All parsing methods assume /// that this is valid. Token Tok; - + // PrevTokLocation - The location of the token we previously // consumed. This token is used for diagnostics where we expected to // see a token following another token (e.g., the ';' at the end of @@ -66,10 +66,10 @@ class Parser { /// in the file. This refers to the common base class between MinimalActions /// and SemaActions for those uses that don't matter. Action &Actions; - + Scope *CurScope; Diagnostic &Diags; - + /// ScopeCache - Cache scopes to reduce malloc traffic. enum { ScopeCacheSize = 16 }; unsigned NumCachedScopes; @@ -83,21 +83,24 @@ class Parser { llvm::OwningPtr<PragmaHandler> UnusedHandler; llvm::OwningPtr<PragmaHandler> WeakHandler; llvm::OwningPtr<clang::CommentHandler> CommentHandler; - + /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ /// template argument list, where the '>' closes the template /// argument list. bool GreaterThanIsOperator; + /// The "depth" of the template parameters currently being parsed. + unsigned TemplateParameterDepth; + /// \brief RAII object that makes '>' behave either as an operator /// or as the closing angle bracket for a template argument list. struct GreaterThanIsOperatorScope { bool &GreaterThanIsOperator; bool OldGreaterThanIsOperator; - + GreaterThanIsOperatorScope(bool >IO, bool Val) - : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { GreaterThanIsOperator = Val; } @@ -105,7 +108,7 @@ class Parser { GreaterThanIsOperator = OldGreaterThanIsOperator; } }; - + public: Parser(Preprocessor &PP, Action &Actions); ~Parser(); @@ -114,9 +117,9 @@ public: TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } Preprocessor &getPreprocessor() const { return PP; } Action &getActions() const { return Actions; } - + const Token &getCurToken() const { return Tok; } - + // Type forwarding. All of these are statically 'void*', but they may all be // different actual classes based on the actions in place. typedef Action::ExprTy ExprTy; @@ -163,24 +166,24 @@ public: OwningExprResult ExprEmpty() { return OwningExprResult(Actions, false); } // Parsing methods. - + /// ParseTranslationUnit - All in one method that initializes parses, and /// shuts down the parser. void ParseTranslationUnit(); - + /// Initialize - Warm up the parser. /// void Initialize(); - - /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if + + /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if /// the EOF was encountered. bool ParseTopLevelDecl(DeclGroupPtrTy &Result); - + private: //===--------------------------------------------------------------------===// // Low-Level token peeking and consumption methods. // - + /// isTokenParen - Return true if the cur token is '(' or ')'. bool isTokenParen() const { return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren; @@ -193,7 +196,7 @@ private: bool isTokenBrace() const { return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace; } - + /// isTokenStringLiteral - True if this token is a string-literal. /// bool isTokenStringLiteral() const { @@ -213,7 +216,7 @@ private: PP.Lex(Tok); return PrevTokLocation; } - + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the /// current token type. This should only be used in cases where the type of /// the token really isn't known, e.g. in error recovery. @@ -229,7 +232,7 @@ private: else return ConsumeToken(); } - + /// ConsumeParen - This consume method keeps the paren count up-to-date. /// SourceLocation ConsumeParen() { @@ -242,7 +245,7 @@ private: PP.Lex(Tok); return PrevTokLocation; } - + /// ConsumeBracket - This consume method keeps the bracket count up-to-date. /// SourceLocation ConsumeBracket() { @@ -251,12 +254,12 @@ private: ++BracketCount; else if (BracketCount) --BracketCount; // Don't let unbalanced ]'s drive the count negative. - + PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } - + /// ConsumeBrace - This consume method keeps the brace count up-to-date. /// SourceLocation ConsumeBrace() { @@ -265,12 +268,12 @@ private: ++BraceCount; else if (BraceCount) --BraceCount; // Don't let unbalanced }'s drive the count negative. - + PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } - + /// ConsumeStringToken - Consume the current 'peek token', lexing a new one /// and returning the token kind. This method is specific to strings, as it /// handles string literal concatenation, as per C99 5.1.1.2, translation @@ -282,7 +285,7 @@ private: PP.Lex(Tok); return PrevTokLocation; } - + /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) /// returns the token after Tok, etc. @@ -315,12 +318,12 @@ private: /// for expressions in C. /// /// This returns true if the token was annotated. - bool TryAnnotateTypeOrScopeToken(); + bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false); /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only /// annotates C++ scope specifiers. This returns true if the token was /// annotated. - bool TryAnnotateCXXScopeToken(); + bool TryAnnotateCXXScopeToken(bool EnteringContext = false); /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and @@ -359,8 +362,8 @@ private: assert(!isActive && "Forgot to call Commit or Revert!"); } }; - - + + /// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), /// this helper function matches and consumes the specified RHS token if /// present. If not present, it emits the specified diagnostic indicating @@ -369,7 +372,7 @@ private: /// of the consumed token. SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok, SourceLocation LHSLoc); - + /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the /// input. If so, it is consumed and false is returned. /// @@ -382,7 +385,7 @@ private: //===--------------------------------------------------------------------===// // Scope manipulation - + /// ParseScope - Introduces a new scope for parsing. The kind of /// scope is determined by ScopeFlags. Objects of this type should /// be created on the stack to coincide with the position where the @@ -399,7 +402,7 @@ private: // parser Self where the new Scope is created with the flags // ScopeFlags, but only when ManageScope is true (the default). If // ManageScope is false, this object does nothing. - ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) + ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) : Self(Self) { if (ManageScope) Self->EnterScope(ScopeFlags); @@ -423,7 +426,7 @@ private: /// EnterScope - Start a new scope. void EnterScope(unsigned ScopeFlags); - + /// ExitScope - Pop a scope off the scope stack. void ExitScope(); @@ -433,7 +436,7 @@ private: DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); - void SuggestParentheses(SourceLocation Loc, unsigned DK, + void SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange); /// SkipUntil - Read tokens until we get to the specified token, then consume @@ -441,9 +444,9 @@ private: /// token will ever occur, this skips to the next token, or to some likely /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' /// character. - /// + /// /// If SkipUntil finds the specified token, it returns true, otherwise it - /// returns false. + /// returns false. bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, bool DontConsume = false) { return SkipUntil(&T, 1, StopAtSemi, DontConsume); @@ -462,7 +465,13 @@ private: struct LexedMethod { Action::DeclPtrTy D; CachedTokens Toks; - explicit LexedMethod(Action::DeclPtrTy MD) : D(MD) {} + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + + explicit LexedMethod(Action::DeclPtrTy MD) : D(MD), TemplateScope(false) {} }; /// LateParsedDefaultArgument - Keeps track of a parameter that may @@ -470,7 +479,7 @@ private: /// occurs within a member function declaration inside the class /// (C++ [class.mem]p2). struct LateParsedDefaultArgument { - explicit LateParsedDefaultArgument(Action::DeclPtrTy P, + explicit LateParsedDefaultArgument(Action::DeclPtrTy P, CachedTokens *Toks = 0) : Param(P), Toks(Toks) { } @@ -483,22 +492,28 @@ private: /// default argument. CachedTokens *Toks; }; - + /// LateParsedMethodDeclaration - A method declaration inside a class that /// contains at least one entity whose parsing needs to be delayed /// until the class itself is completely-defined, such as a default /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration { - explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) : Method(M) { } + explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) + : Method(M), TemplateScope(false) { } /// Method - The method declaration. Action::DeclPtrTy Method; + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + /// DefaultArgs - Contains the parameters of the function and /// their default arguments. At least one of the parameters will /// have a default argument, but all of the parameters of the /// method will be stored so that they can be reintroduced into - /// scope at the appropriate times. + /// scope at the appropriate times. llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs; }; @@ -518,8 +533,8 @@ private: /// any member function declarations or definitions that need to be /// parsed after the corresponding top-level class is complete. struct ParsingClass { - ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass) - : TopLevelClass(TopLevelClass), TemplateScope(false), + ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass) + : TopLevelClass(TopLevelClass), TemplateScope(false), TagOrTemplate(TagOrTemplate) { } /// \brief Whether this is a "top-level" class, meaning that it is @@ -556,47 +571,35 @@ private: return *ClassStack.top(); } - /// \brief RAII object used to + /// \brief RAII object used to class ParsingClassDefinition { Parser &P; bool Popped; public: - ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass) - : P(P), Popped(false) { + ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass) + : P(P), Popped(false) { P.PushParsingClass(TagOrTemplate, TopLevelClass); } /// \brief Pop this class of the stack. - void Pop() { + void Pop() { assert(!Popped && "Nested class has already been popped"); Popped = true; P.PopParsingClass(); } - ~ParsingClassDefinition() { + ~ParsingClassDefinition() { if (!Popped) - P.PopParsingClass(); + P.PopParsingClass(); } }; - void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); - void DeallocateParsedClasses(ParsingClass *Class); - void PopParsingClass(); - - DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D); - void ParseLexedMethodDeclarations(ParsingClass &Class); - void ParseLexedMethodDefs(ParsingClass &Class); - bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, - CachedTokens &Toks, - tok::TokenKind EarlyAbortIf = tok::unknown, - bool ConsumeFinalToken = true); - /// \brief Contains information about any template-specific /// information that has been parsed prior to parsing declaration /// specifiers. struct ParsedTemplateInfo { - ParsedTemplateInfo() + ParsedTemplateInfo() : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } ParsedTemplateInfo(TemplateParameterLists *TemplateParams, @@ -604,9 +607,10 @@ private: : Kind(isSpecialization? ExplicitSpecialization : Template), TemplateParams(TemplateParams) { } - explicit ParsedTemplateInfo(SourceLocation TemplateLoc) - : Kind(ExplicitInstantiation), TemplateParams(0), - TemplateLoc(TemplateLoc) { } + explicit ParsedTemplateInfo(SourceLocation ExternLoc, + SourceLocation TemplateLoc) + : Kind(ExplicitInstantiation), TemplateParams(0), + ExternLoc(ExternLoc), TemplateLoc(TemplateLoc) { } /// \brief The kind of template we are parsing. enum { @@ -624,11 +628,28 @@ private: /// and explicit specializations. TemplateParameterLists *TemplateParams; + /// \brief The location of the 'extern' keyword, if any, for an explicit + /// instantiation + SourceLocation ExternLoc; + /// \brief The location of the 'template' keyword, for an explicit /// instantiation. SourceLocation TemplateLoc; }; + void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); + void DeallocateParsedClasses(ParsingClass *Class); + void PopParsingClass(); + + DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, + const ParsedTemplateInfo &TemplateInfo); + void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDefs(ParsingClass &Class); + bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + tok::TokenKind EarlyAbortIf = tok::unknown, + bool ConsumeFinalToken = true); + //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. DeclGroupPtrTy ParseExternalDeclaration(); @@ -636,7 +657,7 @@ private: bool isStartOfFunctionDefinition(); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( AccessSpecifier AS = AS_none); - + DeclPtrTy ParseFunctionDefinition(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseKNRParamDeclarations(Declarator &D); @@ -646,20 +667,22 @@ private: OwningExprResult ParseAsmStringLiteral(); // Objective-C External Declarations - DeclPtrTy ParseObjCAtDirectives(); + DeclPtrTy ParseObjCAtDirectives(); DeclPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); - DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, + DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, AttributeList *prefixAttrs = 0); - void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, + void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, SourceLocation atLoc); bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &P, - bool WarnOnDeclarations, + llvm::SmallVectorImpl<SourceLocation> &PLocs, + bool WarnOnDeclarations, + SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); void ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, tok::ObjCKeywordKind contextKey); DeclPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, AttributeList *prefixAttrs = 0); - + DeclPtrTy ObjCImpDecl; DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc); @@ -667,7 +690,7 @@ private: DeclPtrTy ParseObjCAtAliasDeclaration(SourceLocation atLoc); DeclPtrTy ParseObjCPropertySynthesize(SourceLocation atLoc); DeclPtrTy ParseObjCPropertyDynamic(SourceLocation atLoc); - + IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); // Definitions for Objective-c context sensitive keywords recognition. enum ObjCTypeQual { @@ -675,7 +698,7 @@ private: objc_NumQuals }; IdentifierInfo *ObjCTypeQuals[objc_NumQuals]; - + bool isTokIdentifier_in() const; TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS); @@ -686,9 +709,9 @@ private: DeclPtrTy classDecl, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); - + DeclPtrTy ParseObjCMethodDefinition(); - + //===--------------------------------------------------------------------===// // C99 6.5: Expressions. @@ -705,13 +728,15 @@ private: unsigned MinPrec); OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - bool &NotCastExpr); + bool &NotCastExpr, + bool parseParenAsExprList); OwningExprResult ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand = false); + bool isAddressOfOperand = false, + bool parseParenAsExprList = false); OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS); OwningExprResult ParseSizeofAlignofExpression(); OwningExprResult ParseBuiltinPrimaryExpression(); - + OwningExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, bool &isCastExpr, TypeTy *&CastTy, @@ -722,7 +747,11 @@ private: typedef llvm::SmallVector<SourceLocation, ExprListSize> CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs); + bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, + void (Action::*Completer)(Scope *S, void *Data, + ExprTy **Args, + unsigned NumArgs) = 0, + void *Data = 0); /// ParenParseOption - Control what ParseParenExpression will parse. enum ParenParseOption { @@ -733,31 +762,29 @@ private: }; OwningExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, + bool parseAsExprList, TypeTy *&CastTy, SourceLocation &RParenLoc); - + OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, TypeTy *&CastTy, SourceLocation LParenLoc, SourceLocation &RParenLoc); - + OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty, SourceLocation LParenLoc, SourceLocation RParenLoc); - + OwningExprResult ParseStringLiteralExpression(); //===--------------------------------------------------------------------===// // C++ Expressions OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); - /// ParseOptionalCXXScopeSpecifier - Parse global scope or - /// nested-name-specifier if present. Returns true if a nested-name-specifier - /// was parsed from the token stream. Note that this routine will not parse - /// ::new or ::delete, it will just leave them in the token stream. - /// - bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS); - + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + TypeTy *ObjectType, + bool EnteringContext); + //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts OwningExprResult ParseCXXCasts(); @@ -811,7 +838,7 @@ private: //===--------------------------------------------------------------------===// // C99 6.7.8: Initialization. - + /// ParseInitializer /// initializer: [C99 6.7.8] /// assignment-expression @@ -831,15 +858,15 @@ private: //===--------------------------------------------------------------------===// // Objective-C Expressions - + bool isTokObjCMessageIdentifierReceiver() const { if (!Tok.is(tok::identifier)) return false; - + IdentifierInfo *II = Tok.getIdentifierInfo(); if (Actions.getTypeName(*II, Tok.getLocation(), CurScope)) return true; - + return II == Ident_super; } @@ -906,7 +933,15 @@ private: //===--------------------------------------------------------------------===// // C99 6.7: Declarations. - + + /// A context for parsing declaration specifiers. TODO: flesh this + /// out, there are other significant restrictions on specifiers than + /// would be best implemented in the parser. + enum DeclSpecContext { + DSC_normal, // normal context + DSC_class // class context, enables 'friend' + }; + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, SourceLocation &DeclEnd, @@ -920,15 +955,17 @@ private: bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS); - void ParseDeclarationSpecifiers(DeclSpec &DS, + void ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), - AccessSpecifier AS = AS_none); - bool ParseOptionalTypeSpecifier(DeclSpec &DS, int &isInvalid, + AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DSC_normal); + bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid, const char *&PrevSpec, + unsigned &DiagID, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseSpecifierQualifierList(DeclSpec &DS); - + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS); void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, @@ -938,7 +975,7 @@ private: DeclPtrTy TagDecl); void ParseStructDeclaration(DeclSpec &DS, llvm::SmallVectorImpl<FieldDeclarator> &Fields); - + bool isDeclarationSpecifier(); bool isTypeSpecifierQualifier(); bool isTypeQualifier() const; @@ -1080,20 +1117,29 @@ private: class DeclaratorScopeObj { Parser &P; CXXScopeSpec &SS; + bool EnteredScope; public: - DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {} + DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) + : P(p), SS(ss), EnteredScope(false) {} void EnterDeclaratorScope() { - if (SS.isSet()) - P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS); + assert(!EnteredScope && "Already entered the scope!"); + assert(SS.isSet() && "C++ scope was not set!"); + if (P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS)) + SS.setScopeRep(0); + + if (!SS.isInvalid()) + EnteredScope = true; } ~DeclaratorScopeObj() { - if (SS.isSet()) + if (EnteredScope) { + assert(SS.isSet() && "C++ scope was cleared ?"); P.Actions.ActOnCXXExitDeclaratorScope(P.CurScope, SS); + } } }; - + /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); /// A function that parses a variant of direct-declarator. @@ -1109,10 +1155,10 @@ private: void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, Declarator &D); void ParseBracketDeclarator(Declarator &D); - + //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] - + DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); DeclPtrTy ParseLinkage(unsigned Context); DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, @@ -1120,25 +1166,30 @@ private: DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd); DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none); DeclPtrTy ParseStaticAssertDeclaration(SourceLocation &DeclEnd); DeclPtrTy ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd); - + //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. - TypeResult ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS = 0); + TypeResult ParseClassName(SourceLocation &EndLocation, + const CXXScopeSpec *SS = 0, + bool DestrExpected = false); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, - DeclSpec &DS, + DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); - void ParseCXXClassMemberDeclaration(AccessSpecifier AS); + void ParseCXXClassMemberDeclaration(AccessSpecifier AS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseConstructorInitializer(DeclPtrTy ConstructorDecl); MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl); + void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, + DeclPtrTy ThisDecl); //===--------------------------------------------------------------------===// // C++ 10: Derived classes [class.derived] @@ -1169,9 +1220,9 @@ private: const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, AccessSpecifier AS=AS_none); - bool ParseTemplateParameters(unsigned Depth, + bool ParseTemplateParameters(unsigned Depth, TemplateParameterList &TemplateParams, - SourceLocation &LAngleLoc, + SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, TemplateParameterList &TemplateParams); @@ -1185,7 +1236,7 @@ private: typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList; bool ParseTemplateIdAfterTemplateName(TemplateTy Template, - SourceLocation TemplateNameLoc, + SourceLocation TemplateNameLoc, const CXXScopeSpec *SS, bool ConsumeLastToken, SourceLocation &LAngleLoc, @@ -1203,7 +1254,8 @@ private: TemplateArgIsTypeList &TemplateArgIsType, TemplateArgLocationList &TemplateArgLocations); void *ParseTemplateArgument(bool &ArgIsType); - DeclPtrTy ParseExplicitInstantiation(SourceLocation TemplateLoc, + DeclPtrTy ParseExplicitInstantiation(SourceLocation ExternLoc, + SourceLocation TemplateLoc, SourceLocation &DeclEnd); //===--------------------------------------------------------------------===// diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index 84cc5d5c3461..480b94f73f62 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -31,15 +31,15 @@ public: /// FnScope - This indicates that the scope corresponds to a function, which /// means that labels are set here. FnScope = 0x01, - + /// BreakScope - This is a while,do,switch,for, etc that can have break /// stmts embedded into it. BreakScope = 0x02, - + /// ContinueScope - This is a while,do,for, which can have continue /// stmt embedded into it. ContinueScope = 0x04, - + /// DeclScope - This is a scope that can contain a declaration. Some scopes /// just contain loop constructs but don't contain decls. DeclScope = 0x08, @@ -49,7 +49,7 @@ public: /// ClassScope - The scope of a struct/union/class definition. ClassScope = 0x20, - + /// BlockScope - This is a scope that corresponds to a block object. /// Blocks serve as top-level scopes for some objects like labels, they /// also prevent things like break and continue. BlockScopes have the @@ -65,7 +65,7 @@ public: /// FunctionPrototypeScope - This is a scope that corresponds to the /// parameters within a function prototype. FunctionPrototypeScope = 0x100, - + /// AtCatchScope - This is a scope that corresponds to the Objective-C /// @catch statement. AtCatchScope = 0x200 @@ -74,15 +74,15 @@ private: /// The parent scope for this scope. This is null for the translation-unit /// scope. Scope *AnyParent; - + /// Depth - This is the depth of this scope. The translation-unit scope has /// depth 0. unsigned Depth : 16; - + /// Flags - This contains a set of ScopeFlags, which indicates how the scope /// interrelates with other control flow statements. unsigned Flags : 10; - + /// WithinElse - Whether this scope is part of the "else" branch in /// its parent ControlScope. bool WithinElse : 1; @@ -90,7 +90,7 @@ private: /// FnParent - If this scope has a parent scope that is a function body, this /// pointer is non-null and points to it. This is used for label processing. Scope *FnParent; - + /// BreakParent/ContinueParent - This is a direct link to the immediately /// preceeding BreakParent/ContinueParent if this scope is not one, or null if /// there is no containing break/continue scope. @@ -119,7 +119,7 @@ private: /// implement these semantics. typedef llvm::SmallPtrSet<Action::DeclPtrTy, 32> DeclSetTy; DeclSetTy DeclsInScope; - + /// Entity - The entity with which this scope is associated. For /// example, the entity of a class scope is the class itself, the /// entity of a function scope is a function, etc. This field is @@ -151,9 +151,9 @@ public: /// const Scope *getFnParent() const { return FnParent; } Scope *getFnParent() { return FnParent; } - + /// getContinueParent - Return the closest scope that a continue statement - /// would be affected by. If the closest scope is a closure scope, we know + /// would be affected by. If the closest scope is a closure scope, we know /// that there is no loop *inside* the closure. Scope *getContinueParent() { if (ContinueParent && !ContinueParent->isBlockScope()) @@ -164,9 +164,9 @@ public: const Scope *getContinueParent() const { return const_cast<Scope*>(this)->getContinueParent(); } - + /// getBreakParent - Return the closest scope that a break statement - /// would be affected by. If the closest scope is a block scope, we know + /// would be affected by. If the closest scope is a block scope, we know /// that there is no loop *inside* the block. Scope *getBreakParent() { if (BreakParent && !BreakParent->isBlockScope()) @@ -176,16 +176,16 @@ public: const Scope *getBreakParent() const { return const_cast<Scope*>(this)->getBreakParent(); } - + Scope *getControlParent() { return ControlParent; } const Scope *getControlParent() const { return ControlParent; } - + Scope *getBlockParent() { return BlockParent; } - const Scope *getBlockParent() const { return BlockParent; } + const Scope *getBlockParent() const { return BlockParent; } Scope *getTemplateParamParent() { return TemplateParamParent; } - const Scope *getTemplateParamParent() const { return TemplateParamParent; } - + const Scope *getTemplateParamParent() const { return TemplateParamParent; } + typedef DeclSetTy::iterator decl_iterator; decl_iterator decl_begin() const { return DeclsInScope.begin(); } decl_iterator decl_end() const { return DeclsInScope.end(); } @@ -222,7 +222,7 @@ public: } return false; } - + /// isTemplateParamScope - Return true if this scope is a C++ /// template parameter scope. bool isTemplateParamScope() const { @@ -275,7 +275,7 @@ public: AnyParent = Parent; Depth = AnyParent ? AnyParent->Depth+1 : 0; Flags = ScopeFlags; - + if (AnyParent) { FnParent = AnyParent->FnParent; BreakParent = AnyParent->BreakParent; @@ -291,7 +291,7 @@ public: TemplateParamParent = 0; WithinElse = false; } - + // If this scope is a function or contains breaks/continues, remember it. if (Flags & FnScope) FnParent = this; if (Flags & BreakScope) BreakParent = this; @@ -304,7 +304,7 @@ public: Entity = 0; } }; - + } // end namespace clang #endif diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/DeltaTree.h index 7bf9305e2877..7e0796524c6d 100644 --- a/include/clang/Rewrite/DeltaTree.h +++ b/include/clang/Rewrite/DeltaTree.h @@ -15,7 +15,7 @@ #define CLANG_REWRITE_DELTATREE_H namespace clang { - + /// DeltaTree - a multiway search tree (BTree) structure with some fancy /// features. B-Trees are are generally more memory and cache efficient than /// binary trees, because they store multiple keys/values in each node. This @@ -32,16 +32,16 @@ namespace clang { // Note: Currently we only support copying when the RHS is empty. DeltaTree(const DeltaTree &RHS); ~DeltaTree(); - + /// getDeltaAt - Return the accumulated delta at the specified file offset. /// This includes all insertions or delections that occurred *before* the /// specified file index. - int getDeltaAt(unsigned FileIndex) const; + int getDeltaAt(unsigned FileIndex) const; /// AddDelta - When a change is made that shifts around the text buffer, /// this method is used to record that info. It inserts a delta of 'Delta' /// into the current DeltaTree at offset FileIndex. - void AddDelta(unsigned FileIndex, int Delta); + void AddDelta(unsigned FileIndex, int Delta); }; } // end namespace clang diff --git a/include/clang/Rewrite/HTMLRewrite.h b/include/clang/Rewrite/HTMLRewrite.h index f49d49e710c9..f77e0c61c54c 100644 --- a/include/clang/Rewrite/HTMLRewrite.h +++ b/include/clang/Rewrite/HTMLRewrite.h @@ -19,36 +19,36 @@ #include <string> namespace clang { - + class Rewriter; class RewriteBuffer; class Preprocessor; class PreprocessorFactory; - + namespace html { - + /// HighlightRange - Highlight a range in the source code with the specified /// start/end tags. B/E must be in the same file. This ensures that /// start/end tags are placed at the start/end of each line if the range is /// multiline. void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, const char *StartTag, const char *EndTag); - + /// HighlightRange - Highlight a range in the source code with the specified - /// start/end tags. The Start/end of the range must be in the same file. + /// start/end tags. The Start/end of the range must be in the same file. /// This ensures that start/end tags are placed at the start/end of each line /// if the range is multiline. inline void HighlightRange(Rewriter &R, SourceRange Range, const char *StartTag, const char *EndTag) { HighlightRange(R, Range.getBegin(), Range.getEnd(), StartTag, EndTag); } - + /// HighlightRange - This is the same as the above method, but takes /// decomposed file locations. void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, const char *BufferStart, const char *StartTag, const char *EndTag); - + /// EscapeText - HTMLize a specified file so that special characters are /// are translated so that they are not interpreted as HTML tags. void EscapeText(Rewriter& R, FileID FID, @@ -61,9 +61,9 @@ namespace html { std::string EscapeText(const std::string& s, bool EscapeSpaces = false, bool ReplaceTabs = false); - void AddLineNumbers(Rewriter& R, FileID FID); - - void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, + void AddLineNumbers(Rewriter& R, FileID FID); + + void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, const char *title = NULL); /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with diff --git a/include/clang/Rewrite/RewriteRope.h b/include/clang/Rewrite/RewriteRope.h index 7faa451290e4..c0bd741d5546 100644 --- a/include/clang/Rewrite/RewriteRope.h +++ b/include/clang/Rewrite/RewriteRope.h @@ -14,15 +14,15 @@ #ifndef LLVM_CLANG_REWRITEROPE_H #define LLVM_CLANG_REWRITEROPE_H -#include "llvm/ADT/iterator.h" #include <cstring> #include <cassert> +#include <iterator> namespace clang { //===--------------------------------------------------------------------===// // RopeRefCountString Class //===--------------------------------------------------------------------===// - + /// RopeRefCountString - This struct is allocated with 'new char[]' from the /// heap, and represents a reference counted chunk of string data. When its /// ref count drops to zero, it is delete[]'d. This is primarily managed @@ -30,21 +30,21 @@ namespace clang { struct RopeRefCountString { unsigned RefCount; char Data[1]; // Variable sized. - + void addRef() { if (this) ++RefCount; } - + void dropRef() { if (this && --RefCount == 0) delete [] (char*)this; } }; - + //===--------------------------------------------------------------------===// // RopePiece Class //===--------------------------------------------------------------------===// - + /// RopePiece - This class represents a view into a RopeRefCountString object. /// This allows references to string data to be efficiently chopped up and /// moved around without having to push around the string data itself. @@ -57,9 +57,9 @@ namespace clang { RopeRefCountString *StrData; unsigned StartOffs; unsigned EndOffs; - + RopePiece() : StrData(0), StartOffs(0), EndOffs(0) {} - + RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End) : StrData(Str), StartOffs(Start), EndOffs(End) { StrData->addRef(); @@ -68,11 +68,11 @@ namespace clang { : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) { StrData->addRef(); } - + ~RopePiece() { StrData->dropRef(); } - + void operator=(const RopePiece &RHS) { if (StrData != RHS.StrData) { StrData->dropRef(); @@ -82,27 +82,27 @@ namespace clang { StartOffs = RHS.StartOffs; EndOffs = RHS.EndOffs; } - + const char &operator[](unsigned Offset) const { return StrData->Data[Offset+StartOffs]; } char &operator[](unsigned Offset) { return StrData->Data[Offset+StartOffs]; } - + unsigned size() const { return EndOffs-StartOffs; } }; - + //===--------------------------------------------------------------------===// // RopePieceBTreeIterator Class //===--------------------------------------------------------------------===// - + /// RopePieceBTreeIterator - This class provides read-only forward iteration /// over bytes that are in a RopePieceBTree. This first iterates over bytes /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf, /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree. class RopePieceBTreeIterator : - public forward_iterator<const char, ptrdiff_t> { + public std::iterator<std::forward_iterator_tag, const char, ptrdiff_t> { /// CurNode - The current B+Tree node that we are inspecting. const void /*RopePieceBTreeLeaf*/ *CurNode; /// CurPiece - The current RopePiece in the B+Tree node that we're @@ -115,18 +115,18 @@ namespace clang { RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N); // end iterator RopePieceBTreeIterator() : CurNode(0), CurPiece(0), CurChar(0) {} - + char operator*() const { return (*CurPiece)[CurChar]; } - + bool operator==(const RopePieceBTreeIterator &RHS) const { return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar; } bool operator!=(const RopePieceBTreeIterator &RHS) const { return !operator==(RHS); } - + RopePieceBTreeIterator& operator++() { // Preincrement if (CurChar+1 < CurPiece->size()) ++CurChar; @@ -140,11 +140,11 @@ namespace clang { private: void MoveToNextPiece(); }; - + //===--------------------------------------------------------------------===// // RopePieceBTree Class //===--------------------------------------------------------------------===// - + class RopePieceBTree { void /*RopePieceBTreeNode*/ *Root; void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT @@ -152,15 +152,15 @@ namespace clang { RopePieceBTree(); RopePieceBTree(const RopePieceBTree &RHS); ~RopePieceBTree(); - + typedef RopePieceBTreeIterator iterator; iterator begin() const { return iterator(Root); } iterator end() const { return iterator(); } unsigned size() const; unsigned empty() const { return size() == 0; } - + void clear(); - + void insert(unsigned Offset, const RopePiece &R); void erase(unsigned Offset, unsigned NumBytes); @@ -169,13 +169,13 @@ namespace clang { //===--------------------------------------------------------------------===// // RewriteRope Class //===--------------------------------------------------------------------===// - + /// RewriteRope - A powerful string class. This class supports extremely /// efficient insertions and deletions into the middle of it, even for /// ridiculously long strings. class RewriteRope { RopePieceBTree Chunks; - + /// We allocate space for string data out of a buffer of size AllocChunkSize. /// This keeps track of how much space is left. RopeRefCountString *AllocBuffer; @@ -184,7 +184,7 @@ class RewriteRope { public: RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {} - RewriteRope(const RewriteRope &RHS) + RewriteRope(const RewriteRope &RHS) : Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) { } @@ -192,23 +192,23 @@ public: // If we had an allocation buffer, drop our reference to it. AllocBuffer->dropRef(); } - + typedef RopePieceBTree::iterator iterator; typedef RopePieceBTree::iterator const_iterator; iterator begin() const { return Chunks.begin(); } iterator end() const { return Chunks.end(); } unsigned size() const { return Chunks.size(); } - + void clear() { Chunks.clear(); } - + void assign(const char *Start, const char *End) { clear(); if (Start != End) Chunks.insert(0, MakeRopeString(Start, End)); } - + void insert(unsigned Offset, const char *Start, const char *End) { assert(Offset <= size() && "Invalid position to insert!"); if (Start == End) return; @@ -224,7 +224,7 @@ public: private: RopePiece MakeRopeString(const char *Start, const char *End); }; - + } // end namespace clang #endif diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h index c3ee0175c36f..29e78fa27958 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -22,13 +22,14 @@ #include <cstring> #include <string> #include "clang/Rewrite/DeltaTree.h" +#include "llvm/ADT/StringRef.h" namespace clang { class SourceManager; class LangOptions; class Rewriter; class Stmt; - + /// RewriteBuffer - As code is rewritten, SourceBuffer's from the original /// input with modifications get a new RewriteBuffer associated with them. The /// RewriteBuffer captures the modified text itself as well as information used @@ -40,7 +41,7 @@ class RewriteBuffer { /// Deltas - Keep track of all the deltas in the source code due to insertions /// and deletions. DeltaTree Deltas; - + /// Buffer - This is the actual buffer itself. Note that using a vector or /// string is a horribly inefficient way to do this, we should use a rope /// instead. @@ -51,50 +52,47 @@ public: iterator begin() const { return Buffer.begin(); } iterator end() const { return Buffer.end(); } unsigned size() const { return Buffer.size(); } - + /// RemoveText - Remove the specified text. void RemoveText(unsigned OrigOffset, unsigned Size); - + /// InsertText - Insert some text at the specified point, where the offset in /// the buffer is specified relative to the original SourceBuffer. The /// text is inserted after the specified location. /// - void InsertText(unsigned OrigOffset, const char *StrData, unsigned StrLen, + void InsertText(unsigned OrigOffset, const llvm::StringRef &Str, bool InsertAfter = true); - - /// InsertTextBefore - Insert some text before the specified point, - /// where the offset in the buffer is specified relative to the original - /// SourceBuffer. - /// - void InsertTextBefore(unsigned OrigOffset, const char *StrData, - unsigned StrLen) { - InsertText(OrigOffset, StrData, StrLen, false); + + /// InsertTextBefore - Insert some text before the specified point, where the + /// offset in the buffer is specified relative to the original + /// SourceBuffer. The text is inserted before the specified location. This is + /// method is the same as InsertText with "InsertAfter == false". + void InsertTextBefore(unsigned OrigOffset, const llvm::StringRef &Str) { + InsertText(OrigOffset, Str, false); } - - /// InsertText - Insert some text at the specified point, where the offset in - /// the buffer is specified relative to the original SourceBuffer. The - /// text is inserted after the specified location. This is method is the - /// same as InsertText with "InsertAfter == false". - void InsertTextAfter(unsigned OrigOffset, const char *StrData, - unsigned StrLen) { - InsertText(OrigOffset, StrData, StrLen); + + /// InsertTextAfter - Insert some text at the specified point, where the + /// offset in the buffer is specified relative to the original SourceBuffer. + /// The text is inserted after the specified location. + void InsertTextAfter(unsigned OrigOffset, const llvm::StringRef &Str) { + InsertText(OrigOffset, Str); } - + /// ReplaceText - This method replaces a range of characters in the input /// buffer with a new string. This is effectively a combined "remove/insert" /// operation. void ReplaceText(unsigned OrigOffset, unsigned OrigLength, - const char *NewStr, unsigned NewLength); - + const llvm::StringRef &NewStr); + private: // Methods only usable by Rewriter. - + /// Initialize - Start this rewrite buffer out with a copy of the unmodified /// input buffer. void Initialize(const char *BufStart, const char *BufEnd) { Buffer.assign(BufStart, BufEnd); } - + /// getMappedOffset - Given an offset into the original SourceBuffer that this /// RewriteBuffer is based on, map it into the offset space of the /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a @@ -104,7 +102,7 @@ private: // Methods only usable by Rewriter. bool AfterInserts = false) const{ return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; } - + /// AddInsertDelta - When an insertion is made at a position, this /// method is used to record that information. void AddInsertDelta(unsigned OrigOffset, int Change) { @@ -117,7 +115,7 @@ private: // Methods only usable by Rewriter. return Deltas.AddDelta(2*OrigOffset+1, Change); } }; - + /// Rewriter - This is the main interface to the rewrite buffers. Its primary /// job is to dispatch high-level requests to the low-level RewriteBuffers that @@ -130,14 +128,14 @@ public: explicit Rewriter(SourceManager &SM, const LangOptions &LO) : SourceMgr(&SM), LangOpts(&LO) {} explicit Rewriter() : SourceMgr(0), LangOpts(0) {} - + void setSourceMgr(SourceManager &SM, const LangOptions &LO) { SourceMgr = &SM; LangOpts = &LO; } SourceManager &getSourceMgr() { return *SourceMgr; } const LangOptions &getLangOpts() { return *LangOpts; } - + /// isRewritable - Return true if this location is a raw file location, which /// is rewritable. Locations from macros, etc are not rewritable. static bool isRewritable(SourceLocation Loc) { @@ -147,7 +145,7 @@ public: /// getRangeSize - Return the size in bytes of the specified range if they /// are in the same file. If not, this returns -1. int getRangeSize(SourceRange Range) const; - + /// getRewritenText - Return the rewritten form of the text in the specified /// range. If the start or end of the range was unrewritable or if they are /// in different buffers, this returns an empty string. @@ -155,66 +153,45 @@ public: /// Note that this method is not particularly efficient. /// std::string getRewritenText(SourceRange Range) const; - + /// InsertText - Insert the specified string at the specified location in the /// original buffer. This method returns true (and does nothing) if the input /// location was not rewritable, false otherwise. - bool InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen, + bool InsertText(SourceLocation Loc, const llvm::StringRef &Str, bool InsertAfter = true); - + /// InsertTextAfter - Insert the specified string at the specified location in - /// the original buffer. This method returns true (and does nothing) if + /// the original buffer. This method returns true (and does nothing) if /// the input location was not rewritable, false otherwise. Text is /// inserted after any other text that has been previously inserted /// at the some point (the default behavior for InsertText). - bool InsertTextAfter(SourceLocation Loc, const char *StrData, - unsigned StrLen) { - return InsertText(Loc, StrData, StrLen); - } - + bool InsertTextAfter(SourceLocation Loc, const llvm::StringRef &Str) { + return InsertText(Loc, Str); + } + /// InsertText - Insert the specified string at the specified location in the /// original buffer. This method returns true (and does nothing) if the input /// location was not rewritable, false otherwise. Text is /// inserted before any other text that has been previously inserted /// at the some point. - bool InsertTextBefore(SourceLocation Loc, const char *StrData, - unsigned StrLen) { - return InsertText(Loc, StrData, StrLen, false); - } - - - bool InsertCStrBefore(SourceLocation Loc, const char* Str) { - return InsertTextBefore(Loc, Str, strlen(Str)); - } - - - bool InsertCStrAfter(SourceLocation Loc, const char* Str) { - return InsertTextAfter(Loc, Str, strlen(Str)); - } - - bool InsertStrBefore(SourceLocation Loc, const std::string& S) { - return S.empty() ? false : InsertTextBefore(Loc, &S[0], S.size()); + bool InsertTextBefore(SourceLocation Loc, const llvm::StringRef &Str) { + return InsertText(Loc, Str, false); } - bool InsertStrAfter(SourceLocation Loc, const std::string& S) { - return S.empty() ? false : InsertTextAfter(Loc, &S[0], S.size()); - } - - /// RemoveText - Remove the specified text region. bool RemoveText(SourceLocation Start, unsigned Length); - + /// ReplaceText - This method replaces a range of characters in the input /// buffer with a new string. This is effectively a combined "remove/insert" /// operation. bool ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength); - + const llvm::StringRef &NewStr); + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty /// printer to generate the replacement code. This returns true if the input /// could not be rewritten, or false if successful. bool ReplaceStmt(Stmt *From, Stmt *To); - + /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. /// If no modification has been made to it, return null. const RewriteBuffer *getRewriteBufferFor(FileID FID) const { @@ -232,7 +209,7 @@ public: private: unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; }; - + } // end namespace clang #endif diff --git a/include/clang/Rewrite/TokenRewriter.h b/include/clang/Rewrite/TokenRewriter.h index c8fd0f532c25..62ea12af1f17 100644 --- a/include/clang/Rewrite/TokenRewriter.h +++ b/include/clang/Rewrite/TokenRewriter.h @@ -24,7 +24,7 @@ namespace clang { class Token; class LangOptions; class ScratchBuffer; - + class TokenRewriter { /// TokenList - This is the list of raw tokens that make up this file. Each /// of these tokens has a unique SourceLocation, which is a FileID. @@ -32,17 +32,17 @@ namespace clang { /// TokenRefTy - This is the type used to refer to a token in the TokenList. typedef std::list<Token>::iterator TokenRefTy; - + /// TokenAtLoc - This map indicates which token exists at a specific /// SourceLocation. Since each token has a unique SourceLocation, this is a /// one to one map. The token can return its own location directly, to map /// backwards. std::map<SourceLocation, TokenRefTy> TokenAtLoc; - + /// ScratchBuf - This is the buffer that we create scratch tokens from. /// llvm::OwningPtr<ScratchBuffer> ScratchBuf; - + TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT void operator=(const TokenRewriter&); // DO NOT IMPLEMENT. public: @@ -50,30 +50,30 @@ namespace clang { /// specified FileID. TokenRewriter(FileID FID, SourceManager &SM, const LangOptions &LO); ~TokenRewriter(); - + typedef std::list<Token>::const_iterator token_iterator; token_iterator token_begin() const { return TokenList.begin(); } token_iterator token_end() const { return TokenList.end(); } - - + + token_iterator AddTokenBefore(token_iterator I, const char *Val); token_iterator AddTokenAfter(token_iterator I, const char *Val) { assert(I != token_end() && "Cannot insert after token_end()!"); return AddTokenBefore(++I, Val); } - + private: /// RemapIterator - Convert from token_iterator (a const iterator) to /// TokenRefTy (a non-const iterator). TokenRefTy RemapIterator(token_iterator I); - + /// AddToken - Add the specified token into the Rewriter before the other /// position. TokenRefTy AddToken(const Token &T, TokenRefTy Where); }; - - - + + + } // end namespace clang #endif diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h new file mode 100644 index 000000000000..d2f509df7b2c --- /dev/null +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -0,0 +1,332 @@ +//===---- CodeCompleteConsumer.h - Code Completion 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 the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H +#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H + +#include "llvm/ADT/SmallVector.h" +#include <memory> +#include <string> + +namespace llvm { +class raw_ostream; +} + +namespace clang { + +class FunctionDecl; +class FunctionType; +class FunctionTemplateDecl; +class NamedDecl; +class NestedNameSpecifier; +class Sema; + +/// \brief A "string" used to describe how code completion can +/// be performed for an entity. +/// +/// A code completion string typically shows how a particular entity can be +/// used. For example, the code completion string for a function would show +/// the syntax to call it, including the parentheses, placeholders for the +/// arguments, etc. +class CodeCompletionString { +public: + /// \brief The different kinds of "chunks" that can occur within a code + /// completion string. + enum ChunkKind { + /// \brief A piece of text that should be placed in the buffer, e.g., + /// parentheses or a comma in a function call. + CK_Text, + /// \brief A code completion string that is entirely optional. For example, + /// an optional code completion string that describes the default arguments + /// in a function call. + CK_Optional, + /// \brief A string that acts as a placeholder for, e.g., a function + /// call argument. + CK_Placeholder, + /// \brief A piece of text that describes something about the result but + /// should not be inserted into the buffer. + CK_Informative + }; + + /// \brief One piece of the code completion string. + struct Chunk { + /// \brief The kind of data stored in this piece of the code completion + /// string. + ChunkKind Kind; + + union { + /// \brief The text string associated with a CK_Text, CK_Placeholder, + /// or CK_Informative chunk. + /// The string is owned by the chunk and will be deallocated + /// (with delete[]) when the chunk is destroyed. + const char *Text; + + /// \brief The code completion string associated with a CK_Optional chunk. + /// The optional code completion string is owned by the chunk, and will + /// be deallocated (with delete) when the chunk is destroyed. + CodeCompletionString *Optional; + }; + + Chunk() : Kind(CK_Text), Text(0) { } + + private: + Chunk(ChunkKind Kind, const char *Text); + + public: + /// \brief Create a new text chunk. + static Chunk CreateText(const char *Text); + + /// \brief Create a new optional chunk. + static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional); + + /// \brief Create a new placeholder chunk. + static Chunk CreatePlaceholder(const char *Placeholder); + + /// \brief Create a new informative chunk. + static Chunk CreateInformative(const char *Informative); + + /// \brief Destroy this chunk, deallocating any memory it owns. + void Destroy(); + }; + +private: + /// \brief The chunks stored in this string. + llvm::SmallVector<Chunk, 4> Chunks; + + CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT + CodeCompletionString &operator=(const CodeCompletionString &); // DITTO + +public: + CodeCompletionString() { } + ~CodeCompletionString(); + + typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator; + iterator begin() const { return Chunks.begin(); } + iterator end() const { return Chunks.end(); } + + /// \brief Add a new text chunk. + /// The text string will be copied. + void AddTextChunk(const char *Text) { + Chunks.push_back(Chunk::CreateText(Text)); + } + + /// \brief Add a new optional chunk. + void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) { + Chunks.push_back(Chunk::CreateOptional(Optional)); + } + + /// \brief Add a new placeholder chunk. + /// The placeholder text will be copied. + void AddPlaceholderChunk(const char *Placeholder) { + Chunks.push_back(Chunk::CreatePlaceholder(Placeholder)); + } + + /// \brief Add a new informative chunk. + /// The text will be copied. + void AddInformativeChunk(const char *Text) { + Chunks.push_back(Chunk::CreateInformative(Text)); + } + + /// \brief Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// \brief Abstract interface for a consumer of code-completion +/// information. +class CodeCompleteConsumer { +public: + /// \brief Captures a result of code completion. + struct Result { + /// \brief Describes the kind of result generated. + enum ResultKind { + RK_Declaration = 0, //< Refers to a declaration + RK_Keyword //< Refers to a keyword or symbol. + }; + + /// \brief The kind of result stored here. + ResultKind Kind; + + union { + /// \brief When Kind == RK_Declaration, the declaration we are referring + /// to. + NamedDecl *Declaration; + + /// \brief When Kind == RK_Keyword, the string representing the keyword + /// or symbol's spelling. + const char *Keyword; + }; + + /// \brief Describes how good this result is, with zero being the best + /// result and progressively higher numbers representing poorer results. + unsigned Rank; + + /// \brief Whether this result is hidden by another name. + bool Hidden : 1; + + /// \brief Whether this result was found via lookup into a base class. + bool QualifierIsInformative : 1; + + /// \brief Whether this declaration is the beginning of a + /// nested-name-specifier and, therefore, should be followed by '::'. + bool StartsNestedNameSpecifier : 1; + + /// \brief If the result should have a nested-name-specifier, this is it. + /// When \c QualifierIsInformative, the nested-name-specifier is + /// informative rather than required. + NestedNameSpecifier *Qualifier; + + /// \brief Build a result that refers to a declaration. + Result(NamedDecl *Declaration, unsigned Rank, + NestedNameSpecifier *Qualifier = 0, + bool QualifierIsInformative = false) + : Kind(RK_Declaration), Declaration(Declaration), Rank(Rank), + Hidden(false), QualifierIsInformative(QualifierIsInformative), + StartsNestedNameSpecifier(false), Qualifier(Qualifier) { } + + /// \brief Build a result that refers to a keyword or symbol. + Result(const char *Keyword, unsigned Rank) + : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + Qualifier(0) { } + + /// \brief Retrieve the declaration stored in this result. + NamedDecl *getDeclaration() const { + assert(Kind == RK_Declaration && "Not a declaration result"); + return Declaration; + } + + /// \brief Retrieve the keyword stored in this result. + const char *getKeyword() const { + assert(Kind == RK_Keyword && "Not a keyword result"); + return Keyword; + } + + /// \brief Create a new code-completion string that describes how to insert + /// this result into a program. + CodeCompletionString *CreateCodeCompletionString(Sema &S); + }; + + class OverloadCandidate { + public: + /// \brief Describes the type of overload candidate. + enum CandidateKind { + /// \brief The candidate is a function declaration. + CK_Function, + /// \brief The candidate is a function template. + CK_FunctionTemplate, + /// \brief The "candidate" is actually a variable, expression, or block + /// for which we only have a function prototype. + CK_FunctionType + }; + + private: + /// \brief The kind of overload candidate. + CandidateKind Kind; + + union { + /// \brief The function overload candidate, available when + /// Kind == CK_Function. + FunctionDecl *Function; + + /// \brief The function template overload candidate, available when + /// Kind == CK_FunctionTemplate. + FunctionTemplateDecl *FunctionTemplate; + + /// \brief The function type that describes the entity being called, + /// when Kind == CK_FunctionType. + const FunctionType *Type; + }; + + public: + OverloadCandidate(FunctionDecl *Function) + : Kind(CK_Function), Function(Function) { } + + OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl) + : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplate) { } + + OverloadCandidate(const FunctionType *Type) + : Kind(CK_FunctionType), Type(Type) { } + + /// \brief Determine the kind of overload candidate. + CandidateKind getKind() const { return Kind; } + + /// \brief Retrieve the function overload candidate or the templated + /// function declaration for a function template. + FunctionDecl *getFunction() const; + + /// \brief Retrieve the function template overload candidate. + FunctionTemplateDecl *getFunctionTemplate() const { + assert(getKind() == CK_FunctionTemplate && "Not a function template"); + return FunctionTemplate; + } + + /// \brief Retrieve the function type of the entity, regardless of how the + /// function is stored. + const FunctionType *getFunctionType() const; + + /// \brief Create a new code-completion string that describes the function + /// signature of this overload candidate. + CodeCompletionString *CreateSignatureString(unsigned CurrentArg, + Sema &S) const; + }; + + /// \brief Deregisters and destroys this code-completion consumer. + virtual ~CodeCompleteConsumer(); + + /// \name Code-completion callbacks + //@{ + /// \brief Process the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Result *Results, + unsigned NumResults) { } + + /// \brief Process the set of overload candidates. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + virtual void ProcessOverloadCandidates(unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { } + //@} +}; + +/// \brief A simple code-completion consumer that prints the results it +/// receives in a simple format. +class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { + /// \brief The semantic-analysis object to which this code-completion + /// consumer is attached. + Sema &SemaRef; + + /// \brief The raw output stream. + llvm::raw_ostream &OS; + +public: + /// \brief Create a new printing code-completion consumer that prints its + /// results to the given raw output stream. + PrintingCodeCompleteConsumer(Sema &S, llvm::raw_ostream &OS) + : SemaRef(S), OS(OS) { } + + /// \brief Prints the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Result *Results, + unsigned NumResults); + + virtual void ProcessOverloadCandidates(unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates); +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 0f0d375e9c30..05c56451b218 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -39,13 +39,13 @@ public: /// /// \returns a pair of Objective-C methods lists containing the /// instance and factory methods, respectively, with this selector. - virtual std::pair<ObjCMethodList, ObjCMethodList> - ReadMethodPool(Selector Sel) { + virtual std::pair<ObjCMethodList, ObjCMethodList> + ReadMethodPool(Selector Sel) { return std::pair<ObjCMethodList, ObjCMethodList>(); } - + // isa/cast/dyn_cast support - static bool classof(const ExternalASTSource *Source) { + static bool classof(const ExternalASTSource *Source) { return Source->SemaSource; } static bool classof(const ExternalSemaSource *) { return true; } diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h index bdce5e95effb..8a245d03cdaa 100644 --- a/include/clang/Sema/ParseAST.h +++ b/include/clang/Sema/ParseAST.h @@ -18,7 +18,9 @@ namespace clang { class Preprocessor; class ASTConsumer; class ASTContext; - + class CodeCompleteConsumer; + class Sema; + /// \brief Parse the entire file specified, notifying the ASTConsumer as /// the file is parsed. /// @@ -28,9 +30,11 @@ namespace clang { /// \param CompleteTranslationUnit When true, the parsed file is /// considered to be a complete translation unit, and any /// end-of-translation-unit wrapup will be performed. - void ParseAST(Preprocessor &pp, ASTConsumer *C, + void ParseAST(Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, bool PrintStats = false, - bool CompleteTranslationUnit = true); + bool CompleteTranslationUnit = true, + CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data) = 0, + void *CreateCodeCompleterData = 0); } // end namespace clang diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h index e821947035c4..b213daf8a39e 100644 --- a/include/clang/Sema/SemaConsumer.h +++ b/include/clang/Sema/SemaConsumer.h @@ -35,8 +35,8 @@ namespace clang { virtual void InitializeSema(Sema &S) {} // isa/cast/dyn_cast support - static bool classof(const ASTConsumer *Consumer) { - return Consumer->SemaConsumer; + static bool classof(const ASTConsumer *Consumer) { + return Consumer->SemaConsumer; } static bool classof(const SemaConsumer *) { return true; } }; diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h index de92844f4d6a..d026339b5caf 100644 --- a/include/clang/Sema/SemaDiagnostic.h +++ b/include/clang/Sema/SemaDiagnostic.h @@ -13,7 +13,7 @@ #include "clang/Basic/Diagnostic.h" namespace clang { - namespace diag { + namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define SEMASTART |