diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
commit | bca07a4524feb4edec581062d631a13116320a24 (patch) | |
tree | a9243275843fbeaa590afc07ee888e006b8d54ea /include/clang | |
parent | 998bc5802ecdd65ce3b270f6c69a8ae8557f0a10 (diff) | |
download | src-bca07a4524feb4edec581062d631a13116320a24.tar.gz src-bca07a4524feb4edec581062d631a13116320a24.zip |
Notes
Diffstat (limited to 'include/clang')
218 files changed, 15902 insertions, 6941 deletions
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index 84833c099f97..08ee4ef40de0 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -19,6 +19,7 @@ namespace clang { class CXXRecordDecl; class DeclGroupRef; class HandleTagDeclDefinition; + class ASTMutationListener; class ASTDeserializationListener; // layering violation because void* is ugly class SemaConsumer; // layering violation required for safe SemaConsumer class TagDecl; @@ -86,10 +87,13 @@ public: /// it was actually used. virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {} + /// \brief If the consumer is interested in entities getting modified after + /// their initial creation, it should return a pointer to + /// a GetASTMutationListener here. + virtual ASTMutationListener *GetASTMutationListener() { return 0; } + /// \brief If the consumer is interested in entities being deserialized from /// AST files, it should return a pointer to a ASTDeserializationListener here - /// - /// The return type is void* because ASTDS lives in Frontend. virtual ASTDeserializationListener *GetASTDeserializationListener() { return 0; } /// PrintStats - If desired, print any statistics. diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ae4ee946fe27..0e887133d01e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -45,6 +45,7 @@ namespace clang { class Diagnostic; class Expr; class ExternalASTSource; + class ASTMutationListener; class IdentifierTable; class SelectorTable; class SourceManager; @@ -56,6 +57,7 @@ namespace clang { class CXXRecordDecl; class Decl; class FieldDecl; + class MangleContext; class ObjCIvarDecl; class ObjCIvarRefExpr; class ObjCPropertyDecl; @@ -78,49 +80,61 @@ namespace clang { class ASTContext { ASTContext &this_() { return *this; } - std::vector<Type*> Types; - llvm::FoldingSet<ExtQuals> ExtQualNodes; - llvm::FoldingSet<ComplexType> ComplexTypes; - llvm::FoldingSet<PointerType> PointerTypes; - llvm::FoldingSet<BlockPointerType> BlockPointerTypes; - llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; - llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes; - llvm::FoldingSet<MemberPointerType> MemberPointerTypes; - llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; - llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; - std::vector<VariableArrayType*> VariableArrayTypes; - 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<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes; - llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> + mutable std::vector<Type*> Types; + mutable llvm::FoldingSet<ExtQuals> ExtQualNodes; + mutable llvm::FoldingSet<ComplexType> ComplexTypes; + mutable llvm::FoldingSet<PointerType> PointerTypes; + mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes; + mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; + mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes; + mutable llvm::FoldingSet<MemberPointerType> MemberPointerTypes; + mutable llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; + mutable llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; + mutable std::vector<VariableArrayType*> VariableArrayTypes; + mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; + mutable llvm::FoldingSet<DependentSizedExtVectorType> + DependentSizedExtVectorTypes; + mutable llvm::FoldingSet<VectorType> VectorTypes; + mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; + mutable llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes; + mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; + mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; + mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmType> + SubstTemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmPackType> + SubstTemplateTypeParmPackTypes; + mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> TemplateSpecializationTypes; - llvm::FoldingSet<ElaboratedType> ElaboratedTypes; - llvm::FoldingSet<DependentNameType> DependentNameTypes; - llvm::ContextualFoldingSet<DependentTemplateSpecializationType, ASTContext&> + mutable llvm::FoldingSet<ParenType> ParenTypes; + mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes; + mutable llvm::FoldingSet<DependentNameType> DependentNameTypes; + mutable llvm::ContextualFoldingSet<DependentTemplateSpecializationType, + ASTContext&> DependentTemplateSpecializationTypes; - llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; - llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; - - llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; - llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; - + llvm::FoldingSet<PackExpansionType> PackExpansionTypes; + mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; + mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; + llvm::FoldingSet<AttributedType> AttributedTypes; + + mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; + mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; + mutable llvm::FoldingSet<SubstTemplateTemplateParmPackStorage> + SubstTemplateTemplateParmPacks; + /// \brief The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. - llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; - NestedNameSpecifier *GlobalNestedNameSpecifier; + mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; + mutable NestedNameSpecifier *GlobalNestedNameSpecifier; friend class NestedNameSpecifier; /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. /// This is lazily created. This is intentionally not serialized. - llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts; - llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts; + mutable llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> + ASTRecordLayouts; + mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> + ObjCLayouts; /// KeyFunctions - A cache mapping from CXXRecordDecls to key functions. llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions; @@ -128,6 +142,9 @@ class ASTContext { /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; + /// \brief Mapping from __block VarDecls to their copy initialization expr. + llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits; + /// \brief Representation of a "canonical" template template parameter that /// is used in canonical template names. class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { @@ -144,10 +161,11 @@ class ASTContext { static void Profile(llvm::FoldingSetNodeID &ID, TemplateTemplateParmDecl *Parm); }; - llvm::FoldingSet<CanonicalTemplateTemplateParm> CanonTemplateTemplateParms; + mutable llvm::FoldingSet<CanonicalTemplateTemplateParm> + CanonTemplateTemplateParms; - TemplateTemplateParmDecl *getCanonicalTemplateTemplateParmDecl( - TemplateTemplateParmDecl *TTP); + TemplateTemplateParmDecl * + getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; /// \brief Whether __[u]int128_t identifier is installed. bool IsInt128Installed; @@ -171,11 +189,11 @@ class ASTContext { QualType ObjCClassTypedefType; QualType ObjCConstantStringType; - RecordDecl *CFConstantStringTypeDecl; + mutable RecordDecl *CFConstantStringTypeDecl; - RecordDecl *NSConstantStringTypeDecl; + mutable RecordDecl *NSConstantStringTypeDecl; - RecordDecl *ObjCFastEnumerationStateTypeDecl; + mutable RecordDecl *ObjCFastEnumerationStateTypeDecl; /// \brief The type for the C FILE type. TypeDecl *FILEDecl; @@ -187,10 +205,13 @@ class ASTContext { TypeDecl *sigjmp_bufDecl; /// \brief Type for the Block descriptor for Blocks CodeGen. - RecordDecl *BlockDescriptorType; + mutable RecordDecl *BlockDescriptorType; /// \brief Type for the Block descriptor for Blocks CodeGen. - RecordDecl *BlockDescriptorExtendedType; + mutable RecordDecl *BlockDescriptorExtendedType; + + /// \brief Declaration for the CUDA cudaConfigureCall function. + FunctionDecl *cudaConfigureCallDecl; TypeSourceInfo NullTypeSourceInfo; @@ -279,7 +300,7 @@ class ASTContext { /// /// AST objects are never destructed; rather, all memory associated with the /// AST objects will be released when the ASTContext itself is destroyed. - llvm::BumpPtrAllocator BumpAlloc; + mutable llvm::BumpPtrAllocator BumpAlloc; /// \brief Allocator for partial diagnostics. PartialDiagnostic::StorageAllocator DiagAllocator; @@ -287,14 +308,17 @@ class ASTContext { /// \brief The current C++ ABI. llvm::OwningPtr<CXXABI> ABI; CXXABI *createCXXABI(const TargetInfo &T); - + + friend class ASTDeclReader; + public: const TargetInfo &Target; IdentifierTable &Idents; SelectorTable &Selectors; Builtin::Context &BuiltinInfo; - DeclarationNameTable DeclarationNames; + mutable DeclarationNameTable DeclarationNames; llvm::OwningPtr<ExternalASTSource> ExternalSource; + ASTMutationListener *Listener; clang::PrintingPolicy PrintingPolicy; // Typedefs which may be provided defining the structure of Objective-C @@ -305,10 +329,10 @@ public: SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } - void *Allocate(unsigned Size, unsigned Align = 8) { + void *Allocate(unsigned Size, unsigned Align = 8) const { return BumpAlloc.Allocate(Size, Align); } - void Deallocate(void *Ptr) { } + void Deallocate(void *Ptr) const { } PartialDiagnostic::StorageAllocator &getDiagAllocator() { return DiagAllocator; @@ -316,6 +340,8 @@ public: const LangOptions& getLangOptions() const { return LangOpts; } + Diagnostic &getDiagnostics() const; + FullSourceLoc getFullLoc(SourceLocation Loc) const { return FullSourceLoc(Loc,SourceMgr); } @@ -388,7 +414,6 @@ public: CanQualType VoidPtrTy, NullPtrTy; CanQualType OverloadTy; CanQualType DependentTy; - CanQualType UndeducedAutoTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, @@ -409,6 +434,19 @@ public: /// with this AST context, if any. ExternalASTSource *getExternalSource() const { return ExternalSource.get(); } + /// \brief Attach an AST mutation listener to the AST context. + /// + /// The AST mutation listener provides the ability to track modifications to + /// the abstract syntax tree entities committed after they were initially + /// created. + void setASTMutationListener(ASTMutationListener *Listener) { + this->Listener = Listener; + } + + /// \brief Retrieve a pointer to the AST mutation listener associated + /// with this AST context, if any. + ASTMutationListener *getASTMutationListener() const { return Listener; } + void PrintStats() const; const std::vector<Type*>& getTypes() const { return Types; } @@ -418,9 +456,9 @@ public: private: /// getExtQualType - Return a type with extended qualifiers. - QualType getExtQualType(const Type *Base, Qualifiers Quals); + QualType getExtQualType(const Type *Base, Qualifiers Quals) const; - QualType getTypeDeclTypeSlow(const TypeDecl *Decl); + QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; public: /// getAddSpaceQualType - Return the uniqued reference to the type for an @@ -428,24 +466,26 @@ public: /// 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); + QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; /// 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, Qualifiers::GC gcAttr); + QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr) const; /// 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) { + QualType getRestrictType(QualType T) const { 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); + QualType getVolatileType(QualType T) const { + return T.withFastQualifiers(Qualifiers::Volatile); + } /// getConstType - Returns the uniqued reference to the type for a /// 'const' qualified type. The resulting type has a union of the @@ -453,44 +493,33 @@ public: /// /// It can be reasonably expected that this will always be /// equivalent to calling T.withConst(). - QualType getConstType(QualType T) { return T.withConst(); } - - /// getNoReturnType - Add or remove 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, bool AddNoReturn = true); - - /// getCallConvType - Adds the specified calling convention attribute to - /// the given type, which must be a FunctionType or a pointer to an - /// allowable type. - QualType getCallConvType(QualType T, CallingConv CallConv); + QualType getConstType(QualType T) const { return T.withConst(); } - /// getRegParmType - Sets the specified regparm attribute to - /// the given type, which must be a FunctionType or a pointer to an - /// allowable type. - QualType getRegParmType(QualType T, unsigned RegParm); + /// adjustFunctionType - Change the ExtInfo on a function type. + const FunctionType *adjustFunctionType(const FunctionType *Fn, + FunctionType::ExtInfo EInfo); /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. - QualType getComplexType(QualType T); - CanQualType getComplexType(CanQualType T) { + QualType getComplexType(QualType T) const; + CanQualType getComplexType(CanQualType T) const { return CanQualType::CreateUnsafe(getComplexType((QualType) T)); } /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. - QualType getPointerType(QualType T); - CanQualType getPointerType(CanQualType T) { + QualType getPointerType(QualType T) const; + CanQualType getPointerType(CanQualType T) const { return CanQualType::CreateUnsafe(getPointerType((QualType) T)); } /// getBlockPointerType - Return the uniqued reference to the type for a block /// of the specified type. - QualType getBlockPointerType(QualType T); + QualType getBlockPointerType(QualType T) const; /// This gets the struct used to keep track of the descriptor for pointer to /// blocks. - QualType getBlockDescriptorType(); + QualType getBlockDescriptorType() const; // Set the type for a Block descriptor type. void setBlockDescriptorType(QualType T); @@ -503,48 +532,56 @@ public: /// This gets the struct used to keep track of the extended descriptor for /// pointer to blocks. - QualType getBlockDescriptorExtendedType(); + QualType getBlockDescriptorExtendedType() const; // Set the type for a Block descriptor extended type. void setBlockDescriptorExtendedType(QualType T); /// Get the BlockDescriptorExtendedType type, or NULL if it hasn't yet been /// built. - QualType getRawBlockdescriptorExtendedType() { + QualType getRawBlockdescriptorExtendedType() const { if (BlockDescriptorExtendedType) return getTagDeclType(BlockDescriptorExtendedType); return QualType(); } + void setcudaConfigureCallDecl(FunctionDecl *FD) { + cudaConfigureCallDecl = FD; + } + FunctionDecl *getcudaConfigureCallDecl() { + return cudaConfigureCallDecl; + } + /// This gets the struct used to keep track of pointer to blocks, complete /// with captured variables. QualType getBlockParmType(bool BlockHasCopyDispose, - llvm::SmallVectorImpl<const Expr *> &Layout); + llvm::SmallVectorImpl<const Expr *> &Layout) const; /// This builds the struct used for __block variables. - QualType BuildByRefType(llvm::StringRef DeclName, QualType Ty); + QualType BuildByRefType(llvm::StringRef DeclName, QualType Ty) const; /// Returns true iff we need copy/dispose helpers for the given type. - bool BlockRequiresCopying(QualType Ty); + bool BlockRequiresCopying(QualType Ty) const; /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. - QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true); + QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true) + const; /// getRValueReferenceType - Return the uniqued reference to the type for an /// rvalue reference to the specified type. - QualType getRValueReferenceType(QualType T); + QualType getRValueReferenceType(QualType T) const; /// getMemberPointerType - Return the uniqued reference to the type for a /// member pointer to the specified type in the specified class. The class /// is a Type because it could be a dependent name. - QualType getMemberPointerType(QualType T, const Type *Cls); + QualType getMemberPointerType(QualType T, const Type *Cls) const; /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. QualType getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets); + unsigned IndexTypeQuals, + SourceRange Brackets) const; /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element @@ -552,30 +589,34 @@ public: /// comparable, at some point. QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets); + unsigned IndexTypeQuals, + SourceRange Brackets) const; /// getIncompleteArrayType - Returns a unique reference to the type for a /// incomplete array of the specified element type. QualType getIncompleteArrayType(QualType EltTy, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals); + unsigned IndexTypeQuals) const; /// getConstantArrayType - Return the unique reference to the type for a /// constant array of the specified element type. QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals); + unsigned IndexTypeQuals) const; + + /// getVariableArrayDecayedType - Returns a vla type where known sizes + /// are replaced with [*]. + QualType getVariableArrayDecayedType(QualType Ty) const; /// 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, - VectorType::AltiVecSpecific AltiVecSpec); + VectorType::VectorKind VecKind) const; /// getExtVectorType - Return the unique reference to an extended vector type /// of the specified element type and size. VectorType must be a built-in /// type. - QualType getExtVectorType(QualType VectorType, unsigned NumElts); + QualType getExtVectorType(QualType VectorType, unsigned NumElts) const; /// getDependentSizedExtVectorType - Returns a non-unique reference to /// the type for a dependently-sized vector of the specified element @@ -583,30 +624,27 @@ public: /// comparable, at some point. QualType getDependentSizedExtVectorType(QualType VectorType, Expr *SizeExpr, - SourceLocation AttrLoc); + SourceLocation AttrLoc) const; /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType getFunctionNoProtoType(QualType ResultTy, - const FunctionType::ExtInfo &Info); + const FunctionType::ExtInfo &Info) const; - QualType getFunctionNoProtoType(QualType ResultTy) { + QualType getFunctionNoProtoType(QualType ResultTy) const { return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo()); } - /// getFunctionType - Return a normal function type with a typed argument - /// list. isVariadic indicates whether the argument list includes '...'. - QualType getFunctionType(QualType ResultTy, const QualType *ArgArray, - unsigned NumArgs, bool isVariadic, - unsigned TypeQuals, bool hasExceptionSpec, - bool hasAnyExceptionSpec, - unsigned NumExs, const QualType *ExArray, - const FunctionType::ExtInfo &Info); + /// getFunctionType - Return a normal function type with a typed + /// argument list. + QualType getFunctionType(QualType ResultTy, + const QualType *Args, unsigned NumArgs, + const FunctionProtoType::ExtProtoInfo &EPI) const; /// getTypeDeclType - Return the unique reference to the type for /// the specified type declaration. QualType getTypeDeclType(const TypeDecl *Decl, - const TypeDecl *PrevDecl = 0) { + const TypeDecl *PrevDecl = 0) const { assert(Decl && "Passed null for Decl param"); if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); @@ -621,77 +659,93 @@ public: /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. - QualType getTypedefType(const TypedefDecl *Decl, QualType Canon = QualType()); + QualType getTypedefType(const TypedefDecl *Decl, QualType Canon = QualType()) + const; + + QualType getRecordType(const RecordDecl *Decl) const; - QualType getRecordType(const RecordDecl *Decl); + QualType getEnumType(const EnumDecl *Decl) const; - QualType getEnumType(const EnumDecl *Decl); + QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; - QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST); + QualType getAttributedType(AttributedType::Kind attrKind, + QualType modifiedType, + QualType equivalentType); QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, - QualType Replacement); + QualType Replacement) const; + QualType getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, - IdentifierInfo *Name = 0); + IdentifierInfo *Name = 0) const; QualType getTemplateSpecializationType(TemplateName T, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon = QualType()); + QualType Canon = QualType()) const; QualType getCanonicalTemplateSpecializationType(TemplateName T, const TemplateArgument *Args, - unsigned NumArgs); + unsigned NumArgs) const; QualType getTemplateSpecializationType(TemplateName T, const TemplateArgumentListInfo &Args, - QualType Canon = QualType()); + QualType Canon = QualType()) const; TypeSourceInfo * getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, const TemplateArgumentListInfo &Args, - QualType Canon = QualType()); + QualType Canon = QualType()) const; + + QualType getParenType(QualType NamedType) const; QualType getElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, - QualType NamedType); + QualType NamedType) const; QualType getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, - QualType Canon = QualType()); + QualType Canon = QualType()) const; QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args); + const TemplateArgumentListInfo &Args) const; QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, unsigned NumArgs, - const TemplateArgument *Args); + const TemplateArgument *Args) const; + + QualType getPackExpansionType(QualType Pattern, + llvm::Optional<unsigned> NumExpansions); - QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl); + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const; QualType getObjCObjectType(QualType Base, ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols); + unsigned NumProtocols) const; /// getObjCObjectPointerType - Return a ObjCObjectPointerType type /// for the given ObjCObjectType. - QualType getObjCObjectPointerType(QualType OIT); + QualType getObjCObjectPointerType(QualType OIT) const; /// getTypeOfType - GCC extension. - QualType getTypeOfExprType(Expr *e); - QualType getTypeOfType(QualType t); + QualType getTypeOfExprType(Expr *e) const; + QualType getTypeOfType(QualType t) const; /// getDecltypeType - C++0x decltype. - QualType getDecltypeType(Expr *e); + QualType getDecltypeType(Expr *e) const; + + /// getAutoType - C++0x deduced auto type. + QualType getAutoType(QualType DeducedType) const; /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. - QualType getTagDeclType(const TagDecl *Decl); + QualType getTagDeclType(const TagDecl *Decl) const; /// 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). @@ -716,14 +770,14 @@ public: // getCFConstantStringType - Return the C structure type used to represent // constant CFStrings. - QualType getCFConstantStringType(); + QualType getCFConstantStringType() const; // getNSConstantStringType - Return the C structure type used to represent // constant NSStrings. - QualType getNSConstantStringType(); + QualType getNSConstantStringType() const; /// Get the structure type used to representation NSStrings, or NULL /// if it hasn't yet been built. - QualType getRawNSConstantStringType() { + QualType getRawNSConstantStringType() const { if (NSConstantStringTypeDecl) return getTagDeclType(NSConstantStringTypeDecl); return QualType(); @@ -733,7 +787,7 @@ public: /// Get the structure type used to representation CFStrings, or NULL /// if it hasn't yet been built. - QualType getRawCFConstantStringType() { + QualType getRawCFConstantStringType() const { if (CFConstantStringTypeDecl) return getTagDeclType(CFConstantStringTypeDecl); return QualType(); @@ -747,11 +801,11 @@ public: } //// This gets the struct used to keep track of fast enumerations. - QualType getObjCFastEnumerationStateType(); + QualType getObjCFastEnumerationStateType() const; /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet /// been built. - QualType getRawObjCFastEnumerationStateType() { + QualType getRawObjCFastEnumerationStateType() const { if (ObjCFastEnumerationStateTypeDecl) return getTagDeclType(ObjCFastEnumerationStateTypeDecl); return QualType(); @@ -763,7 +817,7 @@ public: void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; } /// \brief Retrieve the C FILE type. - QualType getFILEType() { + QualType getFILEType() const { if (FILEDecl) return getTypeDeclType(FILEDecl); return QualType(); @@ -775,7 +829,7 @@ public: } /// \brief Retrieve the C jmp_buf type. - QualType getjmp_bufType() { + QualType getjmp_bufType() const { if (jmp_bufDecl) return getTypeDeclType(jmp_bufDecl); return QualType(); @@ -787,17 +841,22 @@ public: } /// \brief Retrieve the C sigjmp_buf type. - QualType getsigjmp_bufType() { + QualType getsigjmp_bufType() const { if (sigjmp_bufDecl) return getTypeDeclType(sigjmp_bufDecl); return QualType(); } + /// \brief The result type of logical operations, '<', '>', '!=', etc. + QualType getLogicalOperationType() const { + return getLangOptions().CPlusPlus ? BoolTy : IntTy; + } + /// 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, - const FieldDecl *Field=0); + const FieldDecl *Field=0) const; void getLegacyIntegralTypeEncoding(QualType &t) const; @@ -805,13 +864,18 @@ public: void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, std::string &S) const; + /// getObjCEncodingForFunctionDecl - Returns the encoded type for this + //function. This is in the same format as Objective-C method encodings. + void getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S); + /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. - void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S); + void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S) + const; - /// getObjCEncodingForBlockDecl - Return the encoded type for this block + /// getObjCEncodingForBlock - Return the encoded type for this block /// declaration. - void getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S); + std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const; /// getObjCEncodingForPropertyDecl - Return the encoded type for /// this method declaration. If non-NULL, Container must be either @@ -819,14 +883,14 @@ public: /// only be NULL when getting encodings for protocol properties. void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, const Decl *Container, - std::string &S); + std::string &S) const; bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, - ObjCProtocolDecl *rProto); + ObjCProtocolDecl *rProto) const; /// getObjCEncodingTypeSize returns size of type for objective-c encoding /// purpose in characters. - CharUnits getObjCEncodingTypeSize(QualType t); + CharUnits getObjCEncodingTypeSize(QualType t) const; /// \brief Whether __[u]int128_t identifier is installed. bool isInt128Installed() const { return IsInt128Installed; } @@ -854,12 +918,12 @@ public: /// getCVRQualifiedType - Returns a type with additional const, /// volatile, or restrict qualifiers. - QualType getCVRQualifiedType(QualType T, unsigned CVR) { + QualType getCVRQualifiedType(QualType T, unsigned CVR) const { return getQualifiedType(T, Qualifiers::fromCVRMask(CVR)); } /// getQualifiedType - Returns a type with additional qualifiers. - QualType getQualifiedType(QualType T, Qualifiers Qs) { + QualType getQualifiedType(QualType T, Qualifiers Qs) const { if (!Qs.hasNonFastQualifiers()) return T.withFastQualifiers(Qs.getFastQualifiers()); QualifierCollector Qc(Qs); @@ -868,35 +932,41 @@ public: } /// getQualifiedType - Returns a type with additional qualifiers. - QualType getQualifiedType(const Type *T, Qualifiers Qs) { + QualType getQualifiedType(const Type *T, Qualifiers Qs) const { if (!Qs.hasNonFastQualifiers()) return QualType(T, Qs.getFastQualifiers()); return getExtQualType(T, Qs); } DeclarationNameInfo getNameForTemplate(TemplateName Name, - SourceLocation NameLoc); + SourceLocation NameLoc) const; TemplateName getOverloadedTemplateName(UnresolvedSetIterator Begin, - UnresolvedSetIterator End); + UnresolvedSetIterator End) const; TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, - TemplateDecl *Template); + TemplateDecl *Template) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, - const IdentifierInfo *Name); + const IdentifierInfo *Name) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, - OverloadedOperatorKind Operator); - + OverloadedOperatorKind Operator) const; + TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const; + enum GetBuiltinTypeError { 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); + /// GetBuiltinType - Return the type for the specified builtin. If + /// IntegerConstantArgs is non-null, it is filled in with a bitmask of + /// arguments to the builtin that are required to be integer constant + /// expressions. + QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs = 0) const; private: CanQualType getFromTargetType(unsigned Type) const; @@ -909,11 +979,12 @@ public: /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// - Qualifiers::GC getObjCGCAttrKind(const QualType &Ty) const; + Qualifiers::GC getObjCGCAttrKind(QualType Ty) const; - /// areCompatibleVectorTypes - Return true if the given vector types either - /// are of the same unqualified type or if one is GCC and other - equivalent - /// AltiVec vector type. + /// areCompatibleVectorTypes - Return true if the given vector types + /// are of the same unqualified type or if they are equivalent to the same + /// GCC vector type, ignoring whether they are target-specific (AltiVec or + /// Neon) types. bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec); /// isObjCNSObjectType - Return true if this is an NSObject object with @@ -930,76 +1001,83 @@ public: /// 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) { + std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const; + std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const { 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) { + uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).first; } - uint64_t getTypeSize(const Type *T) { + uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).first; } /// getCharWidth - Return the size of the character type, in bits - uint64_t getCharWidth() { + uint64_t getCharWidth() const { return getTypeSize(CharTy); } + /// toCharUnitsFromBits - Convert a size in bits to a size in characters. + CharUnits toCharUnitsFromBits(int64_t BitSize) const; + + /// toBits - Convert a size in characters to a size in bits. + int64_t toBits(CharUnits CharSize) const; + /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. - CharUnits getTypeSizeInChars(QualType T); - CharUnits getTypeSizeInChars(const Type *T); + CharUnits getTypeSizeInChars(QualType T) const; + CharUnits getTypeSizeInChars(const Type *T) const; /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. /// This method does not work on incomplete types. - unsigned getTypeAlign(QualType T) { + unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).second; } - unsigned getTypeAlign(const Type *T) { + unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).second; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in /// characters. This method does not work on incomplete types. - CharUnits getTypeAlignInChars(QualType T); - CharUnits getTypeAlignInChars(const Type *T); + CharUnits getTypeAlignInChars(QualType T) const; + CharUnits getTypeAlignInChars(const Type *T) const; - std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T); - std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T); + std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const; + std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const; /// 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); + unsigned getPreferredTypeAlign(const Type *T) const; /// getDeclAlign - Return a conservative estimate of the alignment of /// the specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. /// If @p RefAsPointee, references are treated like their underlying type /// (for alignof), else they're treated like pointers (for CodeGen). - CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false); + CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const; /// 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); + const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const; /// getASTObjCInterfaceLayout - Get or compute information about the /// layout of the specified Objective-C interface. - const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D); + const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) + const; - void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS); + void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS) const; /// getASTObjCImplementationLayout - Get or compute information about /// the layout of the specified Objective-C implementation. This may /// differ from the interface if synthesized ivars are present. const ASTRecordLayout & - getASTObjCImplementationLayout(const ObjCImplementationDecl *D); + getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const; /// getKeyFunction - Get the key function for the given record decl, or NULL /// if there isn't one. The key function is, according to the Itanium C++ ABI @@ -1009,13 +1087,18 @@ public: /// of class definition. const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD); + bool isNearlyEmpty(const CXXRecordDecl *RD) const; + + MangleContext *createMangleContext(); + void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) + const; void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const; - unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI); + unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const; void CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols); @@ -1029,8 +1112,11 @@ public: /// 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. - CanQualType getCanonicalType(QualType T); - const Type *getCanonicalType(const Type *T) { + CanQualType getCanonicalType(QualType T) const { + return CanQualType::CreateUnsafe(T.getCanonicalType()); + } + + const Type *getCanonicalType(const Type *T) const { return T->getCanonicalTypeInternal().getTypePtr(); } @@ -1038,7 +1124,7 @@ public: /// corresponding to the specific potentially non-canonical one. /// Qualifiers are stripped off, functions are turned into function /// pointers, and arrays decay one level into pointers. - CanQualType getCanonicalParamType(QualType T); + CanQualType getCanonicalParamType(QualType T) const; /// \brief Determine whether the given types are equivalent. bool hasSameType(QualType T1, QualType T2) { @@ -1062,13 +1148,8 @@ public: /// \brief Determine whether the given types are equivalent after /// cvr-qualifiers have been removed. bool hasSameUnqualifiedType(QualType T1, QualType T2) { - CanQualType CT1 = getCanonicalType(T1); - CanQualType CT2 = getCanonicalType(T2); - - Qualifiers Quals; - QualType UnqualT1 = getUnqualifiedArrayType(CT1, Quals); - QualType UnqualT2 = getUnqualifiedArrayType(CT2, Quals); - return UnqualT1 == UnqualT2; + return getCanonicalType(T1).getTypePtr() == + getCanonicalType(T2).getTypePtr(); } bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); @@ -1097,11 +1178,15 @@ public: /// by declarations in the type system and the canonical type for /// the template type parameter 'T' is template-param-0-0. NestedNameSpecifier * - getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS); + getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; + + /// \brief Retrieves the default calling convention to use for + /// C++ instance methods. + CallingConv getDefaultMethodCallConv(); /// \brief Retrieves the canonical representation of the given /// calling convention. - CallingConv getCanonicalCallConv(CallingConv CC) { + CallingConv getCanonicalCallConv(CallingConv CC) const { if (CC == CC_C) return CC_Default; return CC; @@ -1131,7 +1216,7 @@ public: /// template name uses the shortest form of the dependent /// nested-name-specifier, which itself contains all canonical /// types, values, and templates. - TemplateName getCanonicalTemplateName(TemplateName Name); + TemplateName getCanonicalTemplateName(TemplateName Name) const; /// \brief Determine whether the given template names refer to the same /// template. @@ -1142,33 +1227,35 @@ public: /// 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); + TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) + const; /// 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 /// canonicalization, e.g. to move type qualifiers into the element type. - const ArrayType *getAsArrayType(QualType T); - const ConstantArrayType *getAsConstantArrayType(QualType T) { + const ArrayType *getAsArrayType(QualType T) const; + const ConstantArrayType *getAsConstantArrayType(QualType T) const { return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T)); } - const VariableArrayType *getAsVariableArrayType(QualType T) { + const VariableArrayType *getAsVariableArrayType(QualType T) const { return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T)); } - const IncompleteArrayType *getAsIncompleteArrayType(QualType T) { + const IncompleteArrayType *getAsIncompleteArrayType(QualType T) const { return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T)); } - const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) { + const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) + const { return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T)); } /// getBaseElementType - Returns the innermost element type of an array type. /// For example, will return "int" for int[m][n] - QualType getBaseElementType(const ArrayType *VAT); + QualType getBaseElementType(const ArrayType *VAT) const; /// getBaseElementType - Returns the innermost element type of a type /// (which needn't actually be an array type). - QualType getBaseElementType(QualType QT); + QualType getBaseElementType(QualType QT) const; /// getConstantArrayElementCount - Returns number of constant array elements. uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; @@ -1179,30 +1266,30 @@ public: /// this returns a pointer to a properly qualified element of the array. /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. - QualType getArrayDecayedType(QualType T); + QualType getArrayDecayedType(QualType T) const; /// 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); + QualType getPromotedIntegerType(QualType PromotableType) const; /// \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); + QualType isPromotableBitField(Expr *E) const; /// 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. - int getIntegerTypeOrder(QualType LHS, QualType RHS); + int getIntegerTypeOrder(QualType LHS, QualType RHS) const; /// 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. - int getFloatingTypeOrder(QualType LHS, QualType RHS); + int getFloatingTypeOrder(QualType LHS, QualType RHS) const; /// getFloatingTypeOfSizeWithinDomain - Returns a real floating /// point or a complex type (based on typeDomain/typeSize). @@ -1213,7 +1300,7 @@ public: private: // Helper for integer ordering - unsigned getIntegerRank(Type* T); + unsigned getIntegerRank(const Type *T) const; public: @@ -1260,14 +1347,15 @@ public: bool Unqualified = false); QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false, bool Unqualified = false); + QualType mergeFunctionArgumentTypes(QualType, QualType, + bool OfBlockPointer=false, + bool Unqualified = false); + QualType mergeTransparentUnionType(QualType, QualType, + bool OfBlockPointer=false, + bool Unqualified = false); QualType mergeObjCGCQualifiers(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); - void ResetObjCLayout(const ObjCContainerDecl *CD) { ObjCLayouts[CD] = 0; } @@ -1278,7 +1366,7 @@ public: // The width of an integer, as defined in C99 6.2.6.2. This is the number // of bits in an integer type excluding any padding bits. - unsigned getIntWidth(QualType T); + unsigned getIntWidth(QualType T) const; // Per C99 6.2.5p6, for every signed integer type, there is a corresponding // unsigned integer type. This method takes a signed type, and returns the @@ -1303,7 +1391,7 @@ public: /// MakeIntValue - Make an APSInt of the appropriate width and /// signedness for the given \arg Value and integer \arg Type. - llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) { + llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const { llvm::APSInt Res(getIntWidth(Type), !Type->isSignedIntegerType()); Res = Value; return Res; @@ -1314,12 +1402,23 @@ public: /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + /// \brief returns true if there is at lease one @implementation in TU. + bool AnyObjCImplementation() { + return !ObjCImpls.empty(); + } + /// \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 Set the copy inialization expression of a block var decl. + void setBlockVarCopyInits(VarDecl*VD, Expr* Init); + /// \brief Get the copy initialization expression of VarDecl,or NULL if + /// none exists. + Expr *getBlockVarCopyInits(const VarDecl*VD); /// \brief Allocate an uninitialized TypeSourceInfo. /// @@ -1332,13 +1431,14 @@ public: /// /// \param Size the size of the type info to create, or 0 if the size /// should be calculated based on the type. - TypeSourceInfo *CreateTypeSourceInfo(QualType T, unsigned Size = 0); + TypeSourceInfo *CreateTypeSourceInfo(QualType T, unsigned Size = 0) const; /// \brief Allocate a TypeSourceInfo where all locations have been /// initialized to a given location, which defaults to the empty /// location. TypeSourceInfo * - getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation()); + getTrivialTypeSourceInfo(QualType T, + SourceLocation Loc = SourceLocation()) const; TypeSourceInfo *getNullTypeSourceInfo() { return &NullTypeSourceInfo; } @@ -1407,10 +1507,11 @@ private: bool ExpandStructures, const FieldDecl *Field, bool OutermostType = false, - bool EncodingProperty = false); + bool EncodingProperty = false) const; - const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl); + const ASTRecordLayout & + getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) const; private: /// \brief A set of deallocations that should be performed when the @@ -1423,8 +1524,8 @@ private: llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; /// \brief A counter used to uniquely identify "blocks". - unsigned int UniqueBlockByRefTypeID; - unsigned int UniqueBlockParmTypeID; + mutable unsigned int UniqueBlockByRefTypeID; + mutable unsigned int UniqueBlockParmTypeID; friend class DeclContext; friend class DeclarationNameTable; @@ -1469,7 +1570,7 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { /// @param Alignment The alignment of the allocated memory (if the underlying /// allocator supports it). /// @return The allocated memory. Could be NULL. -inline void *operator new(size_t Bytes, clang::ASTContext &C, +inline void *operator new(size_t Bytes, const clang::ASTContext &C, size_t Alignment) throw () { return C.Allocate(Bytes, Alignment); } @@ -1479,7 +1580,7 @@ inline void *operator new(size_t Bytes, clang::ASTContext &C, /// invoking it directly; see the new operator for more details. This operator /// is called implicitly by the compiler if a placement new expression using /// the ASTContext throws in the object constructor. -inline void operator delete(void *Ptr, clang::ASTContext &C, size_t) +inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) throw () { C.Deallocate(Ptr); } @@ -1503,7 +1604,7 @@ inline void operator delete(void *Ptr, clang::ASTContext &C, size_t) /// @param Alignment The alignment of the allocated memory (if the underlying /// allocator supports it). /// @return The allocated memory. Could be NULL. -inline void *operator new[](size_t Bytes, clang::ASTContext& C, +inline void *operator new[](size_t Bytes, const clang::ASTContext& C, size_t Alignment = 8) throw () { return C.Allocate(Bytes, Alignment); } @@ -1514,7 +1615,7 @@ inline void *operator new[](size_t Bytes, clang::ASTContext& C, /// invoking it directly; see the new[] operator for more details. This operator /// is called implicitly by the compiler if a placement new[] expression using /// the ASTContext throws in the object constructor. -inline void operator delete[](void *Ptr, clang::ASTContext &C, size_t) +inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) throw () { C.Deallocate(Ptr); } diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 7cbf3a511705..1ab53b3e9148 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define ASTSTART #include "clang/Basic/DiagnosticASTKinds.inc" #undef DIAG diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index 9380058118c5..b659ce74bb7c 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -45,13 +45,13 @@ namespace clang { /// \brief The file managers we're importing to and from. FileManager &ToFileManager, &FromFileManager; - - /// \brief The diagnostics object that we should use to emit diagnostics. - Diagnostic &Diags; + + /// \brief Whether to perform a minimal import. + bool Minimal; /// \brief Mapping from the already-imported types in the "from" context /// to the corresponding types in the "to" context. - llvm::DenseMap<Type *, Type *> ImportedTypes; + llvm::DenseMap<const Type *, const Type *> ImportedTypes; /// \brief Mapping from the already-imported declarations in the "from" /// context to the corresponding declarations in the "to" context. @@ -63,7 +63,7 @@ namespace clang { /// \brief Mapping from the already-imported FileIDs in the "from" source /// manager to the corresponding FileIDs in the "to" source manager. - llvm::DenseMap<unsigned, FileID> ImportedFileIDs; + llvm::DenseMap<FileID, FileID> ImportedFileIDs; /// \brief Imported, anonymous tag declarations that are missing their /// corresponding typedefs. @@ -74,12 +74,29 @@ namespace clang { NonEquivalentDeclSet NonEquivalentDecls; public: - ASTImporter(Diagnostic &Diags, - ASTContext &ToContext, FileManager &ToFileManager, - ASTContext &FromContext, FileManager &FromFileManager); + /// \brief Create a new AST importer. + /// + /// \param ToContext The context we'll be importing into. + /// + /// \param ToFileManager The file manager we'll be importing into. + /// + /// \param FromContext The context we'll be importing from. + /// + /// \param FromFileManager The file manager we'll be importing into. + /// + /// \param MinimalImport If true, the importer will attempt to import + /// as little as it can, e.g., by importing declarations as forward + /// declarations that can be completed at a later point. + ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport); virtual ~ASTImporter(); + /// \brief Whether the importer will perform a minimal import, creating + /// to-be-completed forward declarations when possible. + bool isMinimalImport() const { return Minimal; } + /// \brief Import the given type from the "from" context into the "to" /// context. /// @@ -129,6 +146,10 @@ namespace clang { /// context, or NULL if an error occurred. NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); + /// \brief Import the goven template name from the "from" context into the + /// "to" context. + TemplateName Import(TemplateName From); + /// \brief Import the given source location from the "from" context into /// the "to" context. /// @@ -154,7 +175,7 @@ namespace clang { /// into the "to" context. /// /// \returns the equivalent identifier in the "to" context. - IdentifierInfo *Import(IdentifierInfo *FromId); + IdentifierInfo *Import(const IdentifierInfo *FromId); /// \brief Import the given Objective-C selector from the "from" /// context into the "to" context. @@ -169,6 +190,12 @@ namespace clang { /// context. FileID Import(FileID); + /// \brief Import the definition of the given declaration, including all of + /// the declarations it contains. + /// + /// This routine is intended to be used + void ImportDefinition(Decl *From); + /// \brief Cope with a name conflict when importing a declaration into the /// given context. /// @@ -212,9 +239,6 @@ namespace clang { /// \brief Retrieve the file manager that AST nodes are being imported from. FileManager &getFromFileManager() const { return FromFileManager; } - - /// \brief Retrieve the diagnostic formatter. - Diagnostic &getDiags() const { return Diags; } /// \brief Report a diagnostic in the "to" context. DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID); @@ -228,12 +252,13 @@ namespace clang { /// \brief Note that we have imported the "from" declaration by mapping it /// to the (potentially-newly-created) "to" declaration. /// - /// \returns \p To - Decl *Imported(Decl *From, Decl *To); + /// Subclasses can override this function to observe all of the \c From -> + /// \c To declaration mappings as they are imported. + virtual Decl *Imported(Decl *From, Decl *To); /// \brief Determine whether the given types are structurally /// equivalent. - bool IsStructurallyEquivalent(QualType From, QualType To); + bool IsStructurallyEquivalent(QualType From, QualType To); }; } diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h new file mode 100644 index 000000000000..01e618024913 --- /dev/null +++ b/include/clang/AST/ASTMutationListener.h @@ -0,0 +1,48 @@ +//===--- ASTMutationListener.h - AST Mutation 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 ASTMutationListener interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H +#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H + +namespace clang { + class Decl; + class DeclContext; + class TagDecl; + class CXXRecordDecl; + class ClassTemplateDecl; + class ClassTemplateSpecializationDecl; + +/// \brief An abstract interface that should be implemented by listeners +/// that want to be notified when an AST entity gets modified after its +/// initial creation. +class ASTMutationListener { +public: + virtual ~ASTMutationListener(); + + /// \brief A new TagDecl definition was completed. + virtual void CompletedTagDefinition(const TagDecl *D) { } + + /// \brief A new declaration with name has been added to a DeclContext. + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D) {} + + /// \brief An implicit member was added after the definition was completed. + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D) {} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 62ca49fbf3b1..67968fde2d6b 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -36,19 +36,19 @@ namespace clang { } // Defined in ASTContext.h -void *operator new(size_t Bytes, clang::ASTContext &C, +void *operator new(size_t Bytes, const clang::ASTContext &C, size_t Alignment = 16) throw (); // FIXME: Being forced to not have a default argument here due to redeclaration // rules on default arguments sucks -void *operator new[](size_t Bytes, clang::ASTContext &C, +void *operator new[](size_t Bytes, const clang::ASTContext &C, size_t Alignment) throw (); // It is good practice to pair new/delete operators. Also, MSVC gives many // warnings if a matching delete overload is not declared, even though the // throw() spec guarantees it will not be implicitly called. -void operator delete(void *Ptr, clang::ASTContext &C, size_t) +void operator delete(void *Ptr, const clang::ASTContext &C, size_t) throw (); -void operator delete[](void *Ptr, clang::ASTContext &C, size_t) +void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) throw (); namespace clang { @@ -58,9 +58,10 @@ class Attr { private: SourceLocation Loc; unsigned AttrKind : 16; - bool Inherited : 1; protected: + bool Inherited : 1; + virtual ~Attr(); void* operator new(size_t bytes) throw() { @@ -88,10 +89,6 @@ protected: public: - /// \brief Whether this attribute should be merged to new - /// declarations. - virtual bool isMerged() const { return true; } - attr::Kind getKind() const { return static_cast<attr::Kind>(AttrKind); } @@ -100,7 +97,6 @@ public: void setLocation(SourceLocation L) { Loc = L; } bool isInherited() const { return Inherited; } - void setInherited(bool I) { Inherited = I; } // Clone this attribute. virtual Attr* clone(ASTContext &C) const = 0; @@ -109,6 +105,21 @@ public: static bool classof(const Attr *) { return true; } }; +class InheritableAttr : public Attr { +protected: + InheritableAttr(attr::Kind AK, SourceLocation L) + : Attr(AK, L) {} + +public: + void setInherited(bool I) { Inherited = I; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() <= attr::LAST_INHERITABLE; + } + static bool classof(const InheritableAttr *) { return true; } +}; + #include "clang/AST/Attrs.inc" /// AttrVec - A vector of Attr, which is how they are stored on the AST. diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index 5a84e404a1b6..2d30cb3b8b62 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -20,6 +20,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include <list> #include <map> @@ -359,7 +360,11 @@ public: /// subobjects of that type. class CXXFinalOverriderMap : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { }; - + +/// \brief A set of all the primary bases for a class. +class CXXIndirectPrimaryBaseSet + : public llvm::SmallSet<const CXXRecordDecl*, 32> { }; + } // end namespace clang #endif diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index dad4dfc926e1..4d7fcfd1d121 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -66,7 +66,16 @@ public: /// \brief Retrieve the underlying type pointer, which refers to a /// canonical type. - T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); } + /// + /// The underlying pointer must not be NULL. + const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); } + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type, or NULL. + /// + const T *getTypePtrOrNull() const { + return cast_or_null<T>(Stored.getTypePtrOrNull()); + } /// \brief Implicit conversion to a qualified type. operator QualType() const { return Stored; } @@ -78,6 +87,8 @@ public: return Stored.isNull(); } + SplitQualType split() const { return Stored.split(); } + /// \brief Retrieve a canonical type pointer with a different static type, /// upcasting or downcasting as needed. /// @@ -216,7 +227,7 @@ protected: public: /// \brief Retrieve the pointer to the underlying Type - T* getTypePtr() const { return Stored.getTypePtr(); } + const T *getTypePtr() const { return Stored.getTypePtr(); } /// \brief Implicit conversion to the underlying pointer. /// @@ -225,7 +236,7 @@ public: /// @code /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } /// @endcode - operator const T*() const { return this->Stored.getTypePtr(); } + operator const T*() const { return this->Stored.getTypePtrOrNull(); } /// \brief Try to convert the given canonical type to a specific structural /// type. @@ -336,7 +347,7 @@ namespace llvm { /// to return smart pointer (proxies?). template<typename T> struct simplify_type<const ::clang::CanQual<T> > { - typedef T* SimpleType; + typedef const T *SimpleType; static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) { return Val.getTypePtr(); } @@ -630,7 +641,6 @@ 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<> diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h index 0bb4b769d0f3..cf909e88220f 100644 --- a/include/clang/AST/CharUnits.h +++ b/include/clang/AST/CharUnits.h @@ -14,7 +14,9 @@ #ifndef LLVM_CLANG_AST_CHARUNITS_H #define LLVM_CLANG_AST_CHARUNITS_H -#include "llvm/System/DataTypes.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" namespace clang { @@ -131,12 +133,24 @@ namespace clang { CharUnits operator- (const CharUnits &Other) const { return CharUnits(Quantity - Other.Quantity); } + CharUnits operator- () const { + return CharUnits(-Quantity); + } + // Conversions. /// getQuantity - Get the raw integer representation of this quantity. QuantityType getQuantity() const { return Quantity; } + /// RoundUpToAlignment - Returns the next integer (mod 2**64) that is + /// greater than or equal to this quantity and is a multiple of \arg + /// Align. Align must be non-zero. + CharUnits RoundUpToAlignment(const CharUnits &Align) { + return CharUnits(llvm::RoundUpToAlignment(Quantity, + Align.Quantity)); + } + }; // class CharUnit } // namespace clang @@ -146,4 +160,38 @@ inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale, return CU * Scale; } +namespace llvm { + +template<> struct DenseMapInfo<clang::CharUnits> { + static clang::CharUnits getEmptyKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getEmptyKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static clang::CharUnits getTombstoneKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getTombstoneKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static unsigned getHashValue(const clang::CharUnits &CU) { + clang::CharUnits::QuantityType Quantity = CU.getQuantity(); + return DenseMapInfo<clang::CharUnits::QuantityType>::getHashValue(Quantity); + } + + static bool isEqual(const clang::CharUnits &LHS, + const clang::CharUnits &RHS) { + return LHS == RHS; + } +}; + +template <> struct isPodLike<clang::CharUnits> { + static const bool value = true; +}; + +} // end namespace llvm + #endif // LLVM_CLANG_AST_CHARUNITS_H diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 674925532210..ee515da0835c 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -36,6 +36,7 @@ class FunctionTemplateSpecializationInfo; class DependentFunctionTemplateSpecializationInfo; class TypeLoc; class UnresolvedSetImpl; +class LabelStmt; /// \brief A container of type source information. /// @@ -196,9 +197,86 @@ public: /// determine whether it's an instance member of its class. bool isCXXInstanceMember() const; + class LinkageInfo { + Linkage linkage_; + Visibility visibility_; + bool explicit_; + + public: + LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility), + explicit_(false) {} + LinkageInfo(Linkage L, Visibility V, bool E) + : linkage_(L), visibility_(V), explicit_(E) {} + + static LinkageInfo external() { + return LinkageInfo(); + } + static LinkageInfo internal() { + return LinkageInfo(InternalLinkage, DefaultVisibility, false); + } + static LinkageInfo uniqueExternal() { + return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false); + } + static LinkageInfo none() { + return LinkageInfo(NoLinkage, DefaultVisibility, false); + } + + Linkage linkage() const { return linkage_; } + Visibility visibility() const { return visibility_; } + bool visibilityExplicit() const { return explicit_; } + + void setLinkage(Linkage L) { linkage_ = L; } + void setVisibility(Visibility V) { visibility_ = V; } + void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; } + void setVisibility(LinkageInfo Other) { + setVisibility(Other.visibility(), Other.visibilityExplicit()); + } + + void mergeLinkage(Linkage L) { + setLinkage(minLinkage(linkage(), L)); + } + void mergeLinkage(LinkageInfo Other) { + setLinkage(minLinkage(linkage(), Other.linkage())); + } + + void mergeVisibility(Visibility V) { + setVisibility(minVisibility(visibility(), V)); + } + void mergeVisibility(Visibility V, bool E) { + setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E); + } + void mergeVisibility(LinkageInfo Other) { + mergeVisibility(Other.visibility(), Other.visibilityExplicit()); + } + + void merge(LinkageInfo Other) { + mergeLinkage(Other); + mergeVisibility(Other); + } + void merge(std::pair<Linkage,Visibility> LV) { + mergeLinkage(LV.first); + mergeVisibility(LV.second); + } + + friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) { + L.merge(R); + return L; + } + }; + /// \brief Determine what kind of linkage this entity has. Linkage getLinkage() const; + /// \brief Determines the visibility of this entity. + Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); } + + /// \brief Determines the linkage and visibility of this entity. + LinkageInfo getLinkageAndVisibility() const; + + /// \brief Clear the linkage cache in response to a change + /// to the declaration. + void ClearLinkageCache(); + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl(); @@ -217,6 +295,29 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } +/// LabelDecl - Represents the declaration of a label. Labels also have a +/// corresponding LabelStmt, which indicates the position that the label was +/// defined at. For normal labels, the location of the decl is the same as the +/// location of the statement. For GNU local labels (__label__), the decl +/// location is where the __label__ is. +class LabelDecl : public NamedDecl { + LabelStmt *TheStmt; + LabelDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *II, LabelStmt *S) + : NamedDecl(Label, DC, L, II), TheStmt(S) {} + +public: + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *II); + + LabelStmt *getStmt() const { return TheStmt; } + void setStmt(LabelStmt *T) { TheStmt = T; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const LabelDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Label; } +}; + /// NamespaceDecl - Represent a C++ namespace. class NamespaceDecl : public NamedDecl, public DeclContext { bool IsInline : 1; @@ -232,7 +333,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext { // NextNamespace points to the next extended declaration. // OrigNamespace points to the original namespace declaration. // OrigNamespace of the first namespace decl points to its anonymous namespace - NamespaceDecl *NextNamespace; + LazyDeclPtr NextNamespace; /// \brief A pointer to either the original namespace definition for /// this namespace (if the boolean value is false) or the anonymous @@ -250,7 +351,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext { NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace), - IsInline(false), NextNamespace(0), OrigOrAnonNamespace(0, true) { } + IsInline(false), NextNamespace(), OrigOrAnonNamespace(0, true) { } public: static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, @@ -281,8 +382,10 @@ public: /// \brief Return the next extended namespace declaration or null if there /// is none. - NamespaceDecl *getNextNamespace() { return NextNamespace; } - const NamespaceDecl *getNextNamespace() const { return NextNamespace; } + NamespaceDecl *getNextNamespace(); + const NamespaceDecl *getNextNamespace() const { + return const_cast<NamespaceDecl *>(this)->getNextNamespace(); + } /// \brief Set the next extended namespace declaration. void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } @@ -331,9 +434,9 @@ public: SourceLocation getLBracLoc() const { return LBracLoc; } SourceLocation getRBracLoc() const { return RBracLoc; } - void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; } - void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; } - + void setLBracLoc(SourceLocation L) { LBracLoc = L; } + void setRBracLoc(SourceLocation R) { RBracLoc = R; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NamespaceDecl *D) { return true; } @@ -471,6 +574,9 @@ public: static bool classofKind(Kind K) { return K >= firstDeclarator && K <= lastDeclarator; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// \brief Structure used to store a statement, the constant value to @@ -545,15 +651,21 @@ private: /// \brief Whether this local variable could be allocated in the return /// slot of its function, enabling the named return value optimization (NRVO). bool NRVOVariable : 1; + + /// \brief Whether this variable has a deduced C++0x auto type for which we're + /// currently parsing the initializer. + bool ParsingAutoInit : 1; friend class StmtIteratorBase; + friend class ASTDeclReader; + protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC, StorageClass SCAsWritten) : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), - ExceptionVar(false), NRVOVariable(false) { + ExceptionVar(false), NRVOVariable(false), ParsingAutoInit(false) { SClass = SC; SClassAsWritten = SCAsWritten; } @@ -582,10 +694,7 @@ public: StorageClass getStorageClassAsWritten() const { return (StorageClass) SClassAsWritten; } - void setStorageClass(StorageClass SC) { - assert(isLegalForVariable(SC)); - SClass = SC; - } + void setStorageClass(StorageClass SC); void setStorageClassAsWritten(StorageClass SC) { assert(isLegalForVariable(SC)); SClassAsWritten = SC; @@ -630,13 +739,13 @@ public: /// external, C linkage. bool isExternC() const; - /// isBlockVarDecl - Returns true for local variable declarations. Note that - /// this includes static variables inside of functions. It also includes - /// variables inside blocks. + /// isLocalVarDecl - Returns true for local variable declarations + /// other than parameters. Note that this includes static variables + /// inside of functions. It also includes variables inside blocks. /// /// void foo() { int x; static int y; extern int z; } /// - bool isBlockVarDecl() const { + bool isLocalVarDecl() const { if (getKind() != Decl::Var) return false; if (const DeclContext *DC = getDeclContext()) @@ -644,8 +753,8 @@ public: return false; } - /// isFunctionOrMethodVarDecl - Similar to isBlockVarDecl, but excludes - /// variables declared in blocks. + /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but + /// excludes variables declared in blocks. bool isFunctionOrMethodVarDecl() const { if (getKind() != Decl::Var) return false; @@ -683,6 +792,10 @@ public: /// definition. DefinitionKind isThisDeclarationADefinition() const; + /// \brief Check whether this variable is defined in this + /// translation unit. + DefinitionKind hasDefinition() const; + /// \brief Get the tentative definition that acts as the real definition in /// a TU. Returns null if there is a proper definition available. VarDecl *getActingDefinition(); @@ -733,7 +846,7 @@ public: const Expr *getAnyInitializer(const VarDecl *&D) const; bool hasInit() const { - return !Init.isNull(); + return !Init.isNull() && (Init.is<Stmt *>() || Init.is<EvaluatedStmt *>()); } const Expr *getInit() const { if (Init.isNull()) @@ -776,6 +889,18 @@ public: void setInit(Expr *I); + /// \brief Check whether we are in the process of parsing an initializer + /// needed to deduce the type of this variable. + bool isParsingAutoInit() const { + return ParsingAutoInit; + } + + /// \brief Note whether we are currently parsing an initializer needed to + /// deduce the type of this variable. + void setParsingAutoInit(bool P) { + ParsingAutoInit = P; + } + EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); if (!Eval) { @@ -928,7 +1053,9 @@ class ImplicitParamDecl : public VarDecl { protected: ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType Tw) - : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, SC_None, SC_None) {} + : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, SC_None, SC_None) { + setImplicit(); + } public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -1046,6 +1173,10 @@ public: return getType(); } + /// \brief Determine whether this parameter is actually a function + /// parameter pack. + bool isParameterPack() 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 @@ -1096,13 +1227,13 @@ private: unsigned SClass : 2; unsigned SClassAsWritten : 2; bool IsInline : 1; + bool IsInlineSpecified : 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; /// \brief End part of this FunctionDecl's source range. @@ -1136,19 +1267,54 @@ private: /// declaration name embedded in the DeclaratorDecl base class. DeclarationNameLoc DNLoc; + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param C the ASTContext. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \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. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation PointOfInstantiation); + + /// \brief Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, + TemplateSpecializationKind TSK); + + void setParams(ASTContext &C, ParmVarDecl **NewParamInfo, unsigned NumParams); + protected: FunctionDecl(Kind DK, DeclContext *DC, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten, bool isInline) + StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo), DeclContext(DK), ParamInfo(0), Body(), - SClass(S), SClassAsWritten(SCAsWritten), IsInline(isInline), + SClass(S), SClassAsWritten(SCAsWritten), + IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), - IsCopyAssignment(false), - HasImplicitReturnZero(false), - EndRangeLoc(NameInfo.getEndLoc()), + HasImplicitReturnZero(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1169,11 +1335,11 @@ public: TypeSourceInfo *TInfo, StorageClass S = SC_None, StorageClass SCAsWritten = SC_None, - bool isInline = false, + bool isInlineSpecified = false, bool hasWrittenPrototype = true) { DeclarationNameInfo NameInfo(N, L); return FunctionDecl::Create(C, DC, NameInfo, T, TInfo, S, SCAsWritten, - isInline, hasWrittenPrototype); + isInlineSpecified, hasWrittenPrototype); } static FunctionDecl *Create(ASTContext &C, DeclContext *DC, @@ -1181,7 +1347,7 @@ public: QualType T, TypeSourceInfo *TInfo, StorageClass S = SC_None, StorageClass SCAsWritten = SC_None, - bool isInline = false, + bool isInlineSpecified = false, bool hasWrittenPrototype = true); DeclarationNameInfo getNameInfo() const { @@ -1246,7 +1412,7 @@ public: /// Whether this virtual function is pure, i.e. makes the containing class /// abstract. bool isPure() const { return IsPure; } - void setPure(bool P = true) { IsPure = P; } + void setPure(bool P = true); /// Whether this function is "trivial" in some specialized C++ senses. /// Can only be true for default constructors, copy constructors, @@ -1255,9 +1421,6 @@ public: 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. @@ -1273,7 +1436,6 @@ public: } bool hasWrittenPrototype() const { return HasWrittenPrototype; } - void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; } /// \brief Whether this function inherited its prototype from a /// previous declaration. @@ -1343,7 +1505,9 @@ public: assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; } - void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); + void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { + setParams(getASTContext(), NewParamInfo, NumParams); + } /// getMinRequiredArguments - Returns the minimum number of arguments /// needed to call this function. This may be fewer than the number of @@ -1361,31 +1525,32 @@ public: } StorageClass getStorageClass() const { return StorageClass(SClass); } - void setStorageClass(StorageClass SC) { - assert(isLegalForFunction(SC)); - SClass = SC; - } + void setStorageClass(StorageClass SC); StorageClass getStorageClassAsWritten() const { return StorageClass(SClassAsWritten); } - void setStorageClassAsWritten(StorageClass SC) { - assert(isLegalForFunction(SC)); - SClassAsWritten = SC; - } /// \brief Determine whether the "inline" keyword was specified for this /// function. - bool isInlineSpecified() const { return IsInline; } + bool isInlineSpecified() const { return IsInlineSpecified; } /// Set whether the "inline" keyword was specified for this function. - void setInlineSpecified(bool I) { IsInline = I; } + void setInlineSpecified(bool I) { + IsInlineSpecified = I; + IsInline = I; + } + + /// Flag that this function is implicitly inline. + void setImplicitlyInline() { + IsInline = true; + } /// \brief Determine whether this function should be inlined, because it is /// either marked "inline" or is a member function of a C++ class that /// was defined in the class body. bool isInlined() const; - + bool isInlineDefinitionExternallyVisible() const; /// isOverloadedOperator - Whether this function declaration @@ -1432,7 +1597,9 @@ public: /// \brief Specify that this record is an instantiation of the /// member function FD. void setInstantiationOfMemberFunction(FunctionDecl *FD, - TemplateSpecializationKind TSK); + TemplateSpecializationKind TSK) { + setInstantiationOfMemberFunction(getASTContext(), FD, TSK); + } /// \brief Retrieves the function template that is described by this /// function declaration. @@ -1526,43 +1693,11 @@ public: void *InsertPos, TemplateSpecializationKind TSK = TSK_ImplicitInstantiation, const TemplateArgumentListInfo *TemplateArgsAsWritten = 0, - SourceLocation PointOfInstantiation = SourceLocation()); - - /// \brief Specify that this function declaration is actually a function - /// template specialization. - /// - /// \param Template the function template that this function template - /// specialization specializes. - /// - /// \param NumTemplateArgs number of template arguments that produced this - /// function template specialization from the template. - /// - /// \param TemplateArgs array of template arguments that produced this - /// function template specialization from the template. - /// - /// \param TSK the kind of template specialization this is. - /// - /// \param NumTemplateArgsAsWritten number of template arguments that produced - /// this function template specialization from the template. - /// - /// \param TemplateArgsAsWritten array of location info for the template - /// arguments. - /// - /// \param LAngleLoc location of left angle token. - /// - /// \param RAngleLoc location of right angle token. - /// - /// \param PointOfInstantiation point at which the function template - /// specialization was first instantiated. - void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, - unsigned NumTemplateArgs, - const TemplateArgument *TemplateArgs, - TemplateSpecializationKind TSK, - unsigned NumTemplateArgsAsWritten, - TemplateArgumentLoc *TemplateArgsAsWritten, - SourceLocation LAngleLoc, - SourceLocation RAngleLoc, - SourceLocation PointOfInstantiation); + SourceLocation PointOfInstantiation = SourceLocation()) { + setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs, + InsertPos, TSK, TemplateArgsAsWritten, + PointOfInstantiation); + } /// \brief Specifies that this function declaration is actually a /// dependent function template specialization. @@ -1620,19 +1755,26 @@ public: class FieldDecl : public DeclaratorDecl { // FIXME: This can be packed into the bitfields in Decl. bool Mutable : 1; + mutable unsigned CachedFieldIndex : 31; + Expr *BitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable) - : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Mutable(Mutable), BitWidth(BW) { + : DeclaratorDecl(DK, DC, L, Id, T, TInfo), + Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) { } public: - static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, + static FieldDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable); + /// getFieldIndex - Returns the index of this field within its record, + /// as appropriate for passing to ASTRecordLayout::getFieldOffset. + unsigned getFieldIndex() const; + /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } @@ -1707,6 +1849,45 @@ public: friend class StmtIteratorBase; }; +/// IndirectFieldDecl - An instance of this class is created to represent a +/// field injected from an anonymous union/struct into the parent scope. +/// IndirectFieldDecl are always implicit. +class IndirectFieldDecl : public ValueDecl { + NamedDecl **Chaining; + unsigned ChainingSize; + + IndirectFieldDecl(DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + NamedDecl **CH, unsigned CHS) + : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {} + +public: + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, NamedDecl **CH, unsigned CHS); + + typedef NamedDecl * const *chain_iterator; + chain_iterator chain_begin() const { return Chaining; } + chain_iterator chain_end() const { return Chaining+ChainingSize; } + + unsigned getChainingSize() const { return ChainingSize; } + + FieldDecl *getAnonField() const { + assert(ChainingSize >= 2); + return cast<FieldDecl>(Chaining[ChainingSize - 1]); + } + + VarDecl *getVarDecl() const { + assert(ChainingSize >= 2); + return dyn_cast<VarDecl>(*chain_begin()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const IndirectFieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K == IndirectField; } + friend class ASTDeclReader; +}; /// TypeDecl - Represents a declaration of a type. /// @@ -1715,7 +1896,7 @@ class TypeDecl : public NamedDecl { /// this TypeDecl. It is a cache maintained by /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. - mutable Type *TypeForDecl; + mutable const Type *TypeForDecl; friend class ASTContext; friend class DeclContext; friend class TagDecl; @@ -1729,8 +1910,8 @@ protected: public: // Low-level accessor - Type *getTypeForDecl() const { return TypeForDecl; } - void setTypeForDecl(Type *TD) { TypeForDecl = TD; } + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -1820,6 +2001,19 @@ protected: unsigned NumPositiveBits : 8; unsigned NumNegativeBits : 8; + /// IsScoped - True if this tag declaration is a scoped enumeration. Only + /// possible in C++0x mode. + bool IsScoped : 1; + /// IsScopedUsingClassTag - If this tag declaration is a scoped enum, + /// then this is true if the scoped enum was declared using the class + /// tag, false if it was declared with the struct tag. No meaning is + /// associated if this tag declaration is not a scoped enum. + bool IsScopedUsingClassTag : 1; + + /// IsFixed - True if this is an enumeration with fixed underlying type. Only + /// possible in C++0x mode. + bool IsFixed : 1; + private: SourceLocation TagKeywordLoc; SourceLocation RBraceLoc; @@ -1859,6 +2053,11 @@ protected: typedef Redeclarable<TagDecl> redeclarable_base; virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + /// @brief Completes the definition of this tag declaration. + /// + /// This is a helper function for derived classes. + void completeDefinition(); + public: typedef redeclarable_base::redecl_iterator redecl_iterator; redecl_iterator redecls_begin() const { @@ -1923,9 +2122,6 @@ public: /// where it is in the process of being defined. void startDefinition(); - /// @brief Completes the definition of this tag declaration. - void completeDefinition(); - /// 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 @@ -2001,7 +2197,19 @@ class EnumDecl : public TagDecl { /// IntegerType - This represent the integer type that the enum corresponds /// to for code generation purposes. Note that the enumerator constants may /// have a different type than this does. - QualType IntegerType; + /// + /// If the underlying integer type was explicitly stated in the source + /// code, this is a TypeSourceInfo* for that type. Otherwise this type + /// was automatically deduced somehow, and this is a Type*. + /// + /// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in + /// some cases it won't. + /// + /// The underlying type of an enumeration never has any qualifiers, so + /// we can get away with just storing a raw Type*, and thus save an + /// extra pointer when TypeSourceInfo is needed. + + llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType; /// PromotionType - The integer type that values of this type should /// promote to. In C, enumerators are generally of an integer type @@ -2022,11 +2230,16 @@ class EnumDecl : public TagDecl { }; EnumDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL) + IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL, + bool Scoped, bool ScopedUsingClassTag, bool Fixed) : TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) { - IntegerType = QualType(); + assert(Scoped || !ScopedUsingClassTag); + IntegerType = (const Type*)0; NumNegativeBits = 0; NumPositiveBits = 0; + IsScoped = Scoped; + IsScopedUsingClassTag = ScopedUsingClassTag; + IsFixed = Fixed; } public: EnumDecl *getCanonicalDecl() { @@ -2045,7 +2258,9 @@ public: static EnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - SourceLocation TKL, EnumDecl *PrevDecl); + SourceLocation TKL, EnumDecl *PrevDecl, + bool IsScoped, bool IsScopedUsingClassTag, + bool IsFixed); static EnumDecl *Create(ASTContext &C, EmptyShell Empty); /// completeDefinition - When created, the EnumDecl corresponds to a @@ -2085,10 +2300,25 @@ public: /// getIntegerType - Return the integer type this enum decl corresponds to. /// This returns a null qualtype for an enum forward definition. - QualType getIntegerType() const { return IntegerType; } + QualType getIntegerType() const { + if (!IntegerType) + return QualType(); + if (const Type* T = IntegerType.dyn_cast<const Type*>()) + return QualType(T, 0); + return IntegerType.get<TypeSourceInfo*>()->getType(); + } /// \brief Set the underlying integer type. - void setIntegerType(QualType T) { IntegerType = T; } + void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); } + + /// \brief Set the underlying integer type source info. + void setIntegerTypeSourceInfo(TypeSourceInfo* TInfo) { IntegerType = TInfo; } + + /// \brief Return the type source info for the underlying integer type, + /// if no type source info exists, return 0. + TypeSourceInfo* getIntegerTypeSourceInfo() const { + return IntegerType.dyn_cast<TypeSourceInfo*>(); + } /// \brief Returns the width in bits requred to store all the /// non-negative enumerators of this enum. @@ -2116,6 +2346,27 @@ public: NumNegativeBits = Num; } + /// \brief Returns true if this is a C++0x scoped enumeration. + bool isScoped() const { + return IsScoped; + } + + /// \brief Returns true if this is a C++0x scoped enumeration. + bool isScopedUsingClassTag() const { + return IsScopedUsingClassTag; + } + + /// \brief Returns true if this is a C++0x enumeration with fixed underlying + /// type. + bool isFixed() const { + return IsFixed; + } + + /// \brief Returns true if this can be considered a complete type. + bool isComplete() const { + return isDefinition() || isFixed(); + } + /// \brief Returns the enumeration (declared within the template) /// from which this enumeration type was instantiated, or NULL if /// this enumeration was not instantiated from any template. @@ -2128,6 +2379,8 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const EnumDecl *D) { return true; } static bool classofKind(Kind K) { return K == Enum; } + + friend class ASTDeclReader; }; @@ -2151,17 +2404,24 @@ class RecordDecl : public TagDecl { /// containing an object. bool HasObjectMember : 1; + /// \brief Whether the field declarations of this record have been loaded + /// from external storage. To avoid unnecessary deserialization of + /// methods/nested types we allow deserialization of just the fields + /// when needed. + mutable bool LoadedFieldsFromExternalStorage : 1; + friend class DeclContext; + protected: RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, RecordDecl *PrevDecl, SourceLocation TKL); public: - static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, + static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL = SourceLocation(), RecordDecl* PrevDecl = 0); - static RecordDecl *Create(ASTContext &C, EmptyShell Empty); + static RecordDecl *Create(const ASTContext &C, EmptyShell Empty); const RecordDecl *getPreviousDeclaration() const { return cast_or_null<RecordDecl>(TagDecl::getPreviousDeclaration()); @@ -2190,11 +2450,6 @@ public: AnonymousStructOrUnion = Anon; } - ValueDecl *getAnonymousStructOrUnionObject(); - const ValueDecl *getAnonymousStructOrUnionObject() const { - return const_cast<RecordDecl*>(this)->getAnonymousStructOrUnionObject(); - } - bool hasObjectMember() const { return HasObjectMember; } void setHasObjectMember (bool val) { HasObjectMember = val; } @@ -2229,11 +2484,10 @@ public: // data members, functions, constructors, destructors, etc. typedef specific_decl_iterator<FieldDecl> field_iterator; - field_iterator field_begin() const { - return field_iterator(decls_begin()); - } + field_iterator field_begin() const; + field_iterator field_end() const { - return field_iterator(decls_end()); + return field_iterator(decl_iterator()); } // field_empty - Whether there are any fields (non-static data @@ -2244,13 +2498,17 @@ public: /// completeDefinition - Notes that the definition of this type is /// now complete. - void completeDefinition(); + virtual void completeDefinition(); static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const RecordDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstRecord && K <= lastRecord; } + +private: + /// \brief Deserialize just the fields. + void LoadFieldsFromExternalStorage() const; }; class FileScopeAsmDecl : public Decl { @@ -2275,8 +2533,49 @@ public: /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } /// class BlockDecl : public Decl, public DeclContext { +public: + /// A class which contains all the information about a particular + /// captured value. + class Capture { + enum { + flag_isByRef = 0x1, + flag_isNested = 0x2 + }; + + /// The variable being captured. + llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags; + + /// The copy expression, expressed in terms of a DeclRef (or + /// BlockDeclRef) to the captured variable. Only required if the + /// variable has a C++ class type. + Expr *CopyExpr; + + public: + Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy) + : VariableAndFlags(variable, + (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)), + CopyExpr(copy) {} + + /// The variable being captured. + VarDecl *getVariable() const { return VariableAndFlags.getPointer(); } + + /// Whether this is a "by ref" capture, i.e. a capture of a __block + /// variable. + bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + + /// Whether this is a nested capture, i.e. the variable captured + /// is not from outside the immediately enclosing function/block. + bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } + + bool hasCopyExpr() const { return CopyExpr != 0; } + Expr *getCopyExpr() const { return CopyExpr; } + void setCopyExpr(Expr *e) { CopyExpr = e; } + }; + +private: // FIXME: This can be packed into the bitfields in Decl. bool IsVariadic : 1; + bool CapturesCXXThis : 1; /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. @@ -2286,11 +2585,15 @@ class BlockDecl : public Decl, public DeclContext { Stmt *Body; TypeSourceInfo *SignatureAsWritten; + Capture *Captures; + unsigned NumCaptures; + protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), - IsVariadic(false), ParamInfo(0), NumParams(0), Body(0), - SignatureAsWritten(0) {} + IsVariadic(false), CapturesCXXThis(false), + ParamInfo(0), NumParams(0), Body(0), + SignatureAsWritten(0), Captures(0), NumCaptures(0) {} public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -2319,7 +2622,7 @@ public: param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_size(); } - unsigned getNumParams() const; + unsigned getNumParams() const { return NumParams; } const ParmVarDecl *getParamDecl(unsigned i) const { assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; @@ -2330,6 +2633,30 @@ public: } void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); + /// hasCaptures - True if this block (or its nested blocks) captures + /// anything of local storage from its enclosing scopes. + bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } + + /// getNumCaptures - Returns the number of captured variables. + /// Does not include an entry for 'this'. + unsigned getNumCaptures() const { return NumCaptures; } + + typedef const Capture *capture_iterator; + typedef const Capture *capture_const_iterator; + capture_iterator capture_begin() { return Captures; } + capture_iterator capture_end() { return Captures + NumCaptures; } + capture_const_iterator capture_begin() const { return Captures; } + capture_const_iterator capture_end() const { return Captures + NumCaptures; } + + bool capturesCXXThis() const { return CapturesCXXThis; } + + void setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis); + + virtual SourceRange getSourceRange() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const BlockDecl *D) { return true; } @@ -2350,6 +2677,32 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } +template<typename decl_type> +void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { + // Note: This routine is implemented here because we need both NamedDecl + // and Redeclarable to be defined. + + decl_type *First; + + if (PrevDecl) { + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + RedeclLink = PreviousDeclLink(llvm::cast<decl_type>( + PrevDecl->getMostRecentDeclaration())); + 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)); + if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this))) + ND->ClearLinkageCache(); +} + } // end namespace clang #endif diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 1369c2b5955a..bf249cea9d5f 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -43,6 +43,7 @@ class DeclarationName; class CompoundStmt; class StoredDeclsMap; class DependentDiagnostic; +class ASTMutationListener; } namespace llvm { @@ -197,25 +198,25 @@ private: return DeclCtx.get<DeclContext*>(); } - /// Loc - The location that this decl. + /// Loc - The location of this decl. SourceLocation Loc; /// DeclKind - This indicates which class this is. - Kind DeclKind : 8; + unsigned DeclKind : 8; /// InvalidDecl - This indicates a semantic error occurred. - unsigned int InvalidDecl : 1; + unsigned InvalidDecl : 1; /// HasAttrs - This indicates whether the decl has attributes or not. - unsigned int HasAttrs : 1; + unsigned HasAttrs : 1; /// Implicit - Whether this declaration was implicitly generated by /// the implementation rather than explicitly written by the user. - bool Implicit : 1; + unsigned Implicit : 1; /// \brief Whether this declaration was "used", meaning that a definition is /// required. - bool Used : 1; + unsigned Used : 1; protected: /// Access - Used by C++ decls for the access specifier. @@ -227,17 +228,24 @@ protected: unsigned PCHLevel : 2; /// ChangedAfterLoad - if this declaration has changed since being loaded - bool ChangedAfterLoad : 1; + unsigned ChangedAfterLoad : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. - unsigned IdentifierNamespace : 15; + unsigned IdentifierNamespace : 12; + /// \brief Whether the \c CachedLinkage field is active. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned HasCachedLinkage : 1; + + /// \brief If \c HasCachedLinkage, the linkage of this declaration. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned CachedLinkage : 2; + + private: -#ifndef NDEBUG void CheckAccessDeclContext() const; -#else - void CheckAccessDeclContext() const { } -#endif protected: @@ -246,7 +254,9 @@ protected: Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { if (Decl::CollectingStats()) add(DK); } @@ -254,7 +264,9 @@ protected: : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { if (Decl::CollectingStats()) add(DK); } @@ -272,7 +284,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - Kind getKind() const { return DeclKind; } + Kind getKind() const { return static_cast<Kind>(DeclKind); } const char *getDeclKindName() const; Decl *getNextDeclInContext() { return NextDeclInContext; } @@ -298,17 +310,21 @@ public: void setAccess(AccessSpecifier AS) { Access = AS; +#ifndef NDEBUG CheckAccessDeclContext(); +#endif } AccessSpecifier getAccess() const { +#ifndef NDEBUG CheckAccessDeclContext(); +#endif return AccessSpecifier(Access); } bool hasAttrs() const { return HasAttrs; } void setAttrs(const AttrVec& Attrs); - AttrVec& getAttrs() { + AttrVec &getAttrs() { return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs()); } const AttrVec &getAttrs() const; @@ -551,6 +567,9 @@ public: /// template parameter pack. bool isTemplateParameterPack() const; + /// \brief Whether this declaration is a parameter pack. + bool isParameterPack() const; + /// \brief Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const; @@ -621,10 +640,14 @@ public: llvm::raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); void dump() const; + void dumpXML() const; + void dumpXML(llvm::raw_ostream &OS) const; private: const Attr *getAttrsImpl() const; +protected: + ASTMutationListener *getASTMutationListener() const; }; /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when @@ -681,23 +704,24 @@ public: /// class DeclContext { /// DeclKind - This indicates which class this is. - Decl::Kind DeclKind : 8; + unsigned DeclKind : 8; /// \brief Whether this declaration context also has some external /// storage that contains additional declarations that are lexically /// part of this context. - mutable bool ExternalLexicalStorage : 1; + mutable unsigned ExternalLexicalStorage : 1; /// \brief Whether this declaration context also has some external /// storage that contains additional declarations that are visible /// in this context. - mutable bool ExternalVisibleStorage : 1; + mutable unsigned ExternalVisibleStorage : 1; /// \brief Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a /// dependent context). mutable StoredDeclsMap *LookupPtr; +protected: /// FirstDecl - The first declaration stored within this declaration /// context. mutable Decl *FirstDecl; @@ -710,7 +734,12 @@ class DeclContext { friend class ExternalASTSource; -protected: + /// \brief Build up a chain of declarations. + /// + /// \returns the first/last pair of declarations. + static std::pair<Decl *, Decl *> + BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls); + DeclContext(Decl::Kind K) : DeclKind(K), ExternalLexicalStorage(false), ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0), @@ -720,7 +749,7 @@ public: ~DeclContext(); Decl::Kind getDeclKind() const { - return DeclKind; + return static_cast<Decl::Kind>(DeclKind); } const char *getDeclKindName() const; @@ -807,6 +836,10 @@ public: /// C++0x scoped enums), and C++ linkage specifications. bool isTransparentContext() const; + /// \brief Determines whether this context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isExternCContext() const; + /// \brief Determine whether this declaration context is equivalent /// to the declaration context DC. bool Equals(const DeclContext *DC) const { diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index a9802bfcaf4e..d11ee8f7fd64 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -35,6 +35,7 @@ class CXXMethodDecl; class CXXRecordDecl; class CXXMemberLookupCriteria; class CXXFinalOverriderMap; +class CXXIndirectPrimaryBaseSet; class FriendDecl; /// \brief Represents any kind of function declaration, whether it is a @@ -112,6 +113,8 @@ class AccessSpecDecl : public Decl { : Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) { setAccess(AS); } + AccessSpecDecl(EmptyShell Empty) + : Decl(AccessSpec, Empty) { } public: /// getAccessSpecifierLoc - The location of the access specifier. SourceLocation getAccessSpecifierLoc() const { return getLocation(); } @@ -132,6 +135,9 @@ public: SourceLocation ColonLoc) { return new (C) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); } + static AccessSpecDecl *Create(ASTContext &C, EmptyShell Empty) { + return new (C) AccessSpecDecl(Empty); + } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -162,6 +168,10 @@ class CXXBaseSpecifier { /// specifier (if present). SourceRange Range; + /// \brief The source location of the ellipsis, if this is a pack + /// expansion. + SourceLocation EllipsisLoc; + /// Virtual - Whether this is a virtual base class or not. bool Virtual : 1; @@ -177,6 +187,10 @@ class CXXBaseSpecifier { /// VC++ bug. unsigned Access : 2; + /// InheritConstructors - Whether the class contains a using declaration + /// to inherit the named class's constructors. + bool InheritConstructors : 1; + /// BaseTypeInfo - The type of the base class. This will be a class or struct /// (or a typedef of such). The source code range does not include the /// "virtual" or access specifier. @@ -186,8 +200,9 @@ public: CXXBaseSpecifier() { } CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, - TypeSourceInfo *TInfo) - : Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseTypeInfo(TInfo) { } + TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) + : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), + Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { } /// getSourceRange - Retrieves the source range that contains the /// entire base specifier. @@ -201,6 +216,22 @@ public: /// with the 'class' keyword (vs. one declared with the 'struct' keyword). bool isBaseOfClass() const { return BaseOfClass; } + /// \brief Determine whether this base specifier is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief Determine whether this base class's constructors get inherited. + bool getInheritConstructors() const { return InheritConstructors; } + + /// \brief Set that this base class's constructors should be inherited. + void setInheritConstructors(bool Inherit = true) { + InheritConstructors = Inherit; + } + + /// \brief For a pack expansion, determine the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + /// getAccessSpecifier - Returns the access specifier for this base /// specifier. This is the actual base specifier as used for /// semantic analysis, so the result can never be AS_none. To @@ -336,20 +367,20 @@ class CXXRecordDecl : public RecordDecl { /// \brief Whether we have already declared a destructor within the class. bool DeclaredDestructor : 1; - - /// Bases - Base classes of this class. - /// FIXME: This is wasted space for a union. - CXXBaseSpecifier *Bases; /// 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; + /// Bases - Base classes of this class. + /// FIXME: This is wasted space for a union. + LazyCXXBaseSpecifiersPtr Bases; + + /// VBases - direct and indirect virtual base classes of this class. + LazyCXXBaseSpecifiersPtr VBases; + /// 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 @@ -371,6 +402,15 @@ class CXXRecordDecl : public RecordDecl { /// in reverse order. FriendDecl *FirstFriend; + /// \brief Retrieve the set of direct base classes. + CXXBaseSpecifier *getBases() const { + return Bases.get(Definition->getASTContext().getExternalSource()); + } + + /// \brief Retrieve the set of virtual base classes. + CXXBaseSpecifier *getVBases() const { + return VBases.get(Definition->getASTContext().getExternalSource()); + } } *DefinitionData; struct DefinitionData &data() { @@ -395,9 +435,17 @@ class CXXRecordDecl : public RecordDecl { llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> TemplateOrInstantiation; -#ifndef NDEBUG - void CheckConversionFunction(NamedDecl *D); -#endif + friend class DeclContext; + + /// \brief Notify the class that member has been added. + /// + /// This routine helps maintain information about the class based on which + /// members have been added. It will be invoked by DeclContext::addDecl() + /// whenever a member is added to this record. + void addedMember(Decl *D); + + void markedVirtualFunctionPure(); + friend void FunctionDecl::setPure(bool); protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -445,12 +493,12 @@ public: bool hasDefinition() const { return DefinitionData != 0; } - static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, + static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL = SourceLocation(), CXXRecordDecl* PrevDecl=0, bool DelayTypeCreation = false); - static CXXRecordDecl *Create(ASTContext &C, EmptyShell Empty); + static CXXRecordDecl *Create(const ASTContext &C, EmptyShell Empty); bool isDynamicClass() const { return data().Polymorphic || data().NumVBases != 0; @@ -463,8 +511,8 @@ public: /// class. unsigned getNumBases() const { return data().NumBases; } - base_class_iterator bases_begin() { return data().Bases; } - base_class_const_iterator bases_begin() const { return data().Bases; } + base_class_iterator bases_begin() { return data().getBases(); } + base_class_const_iterator bases_begin() const { return data().getBases(); } base_class_iterator bases_end() { return bases_begin() + data().NumBases; } base_class_const_iterator bases_end() const { return bases_begin() + data().NumBases; @@ -486,8 +534,8 @@ public: /// class. unsigned getNumVBases() const { return data().NumVBases; } - base_class_iterator vbases_begin() { return data().VBases; } - base_class_const_iterator vbases_begin() const { return data().VBases; } + base_class_iterator vbases_begin() { return data().getVBases(); } + base_class_const_iterator vbases_begin() const { return data().getVBases(); } base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } base_class_const_iterator vbases_end() const { return vbases_begin() + data().NumVBases; @@ -553,18 +601,12 @@ public: return data().DeclaredDefaultConstructor; } - /// \brief Note whether this class has already had its default constructor - /// implicitly declared or doesn't need one. - void setDeclaredDefaultConstructor(bool DDC) { - data().DeclaredDefaultConstructor = DDC; - } - /// hasConstCopyConstructor - Determines whether this class has a /// copy constructor that accepts a const-qualified argument. - bool hasConstCopyConstructor(ASTContext &Context) const; + bool hasConstCopyConstructor(const ASTContext &Context) const; /// getCopyConstructor - Returns the copy constructor for this class - CXXConstructorDecl *getCopyConstructor(ASTContext &Context, + CXXConstructorDecl *getCopyConstructor(const ASTContext &Context, unsigned TypeQuals) const; /// \brief Retrieve the copy-assignment operator for this class, if available. @@ -579,11 +621,6 @@ public: /// a unique copy-assignment operator could not be found. CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const; - /// addedConstructor - Notify the class that another constructor has - /// been added. This routine helps maintain information about the - /// class based on which constructors have been added. - void addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl); - /// hasUserDeclaredConstructor - Whether this class has any /// user-declared constructors. When true, a default constructor /// will not be implicitly declared. @@ -606,17 +643,6 @@ public: return data().DeclaredCopyConstructor; } - /// \brief Note whether this class has already had its copy constructor - /// declared. - void setDeclaredCopyConstructor(bool DCC) { - data().DeclaredCopyConstructor = DCC; - } - - /// addedAssignmentOperator - Notify the class that another assignment - /// operator has been added. This routine helps maintain information about the - /// class based on which operators have been added. - void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl); - /// hasUserDeclaredCopyAssignment - Whether this class has a /// user-declared copy assignment operator. When false, a copy /// assigment operator will be implicitly declared. @@ -632,12 +658,6 @@ public: return data().DeclaredCopyAssignment; } - /// \brief Note whether this class has already had its copy assignment - /// operator declared. - void setDeclaredCopyAssignment(bool DCA) { - data().DeclaredCopyAssignment = DCA; - } - /// hasUserDeclaredDestructor - Whether this class has a /// user-declared destructor. When false, a destructor will be /// implicitly declared. @@ -645,26 +665,12 @@ public: return data().UserDeclaredDestructor; } - /// 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) { - data().UserDeclaredDestructor = UCD; - if (UCD) - data().DeclaredDestructor = true; - } - /// \brief Determine whether this class has had its destructor declared, /// either via the user or via an implicit declaration. /// /// This value is used for lazy creation of destructors. bool hasDeclaredDestructor() const { return data().DeclaredDestructor; } - - /// \brief Note whether this class has already had its destructor declared. - void setDeclaredDestructor(bool DD) { - data().DeclaredDestructor = DD; - } - + /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. UnresolvedSetImpl *getConversionFunctions() { @@ -682,13 +688,6 @@ public: return getConversionFunctions()->end(); } - /// Replaces a conversion function with a new declaration. - /// - /// Returns true if the old conversion was found. - bool replaceConversion(const NamedDecl* Old, NamedDecl *New) { - return getConversionFunctions()->replace(Old, New); - } - /// Removes a conversion function from this class. The conversion /// function must currently be a member of this class. Furthermore, /// this class must currently be in the process of being defined. @@ -698,105 +697,52 @@ public: /// in current class; including conversion function templates. const UnresolvedSetImpl *getVisibleConversionFunctions(); - /// addConversionFunction - Registers a conversion function which - /// this class declares directly. - void addConversionFunction(NamedDecl *Decl) { -#ifndef NDEBUG - CheckConversionFunction(Decl); -#endif - - // We intentionally don't use the decl's access here because it - // hasn't been set yet. That's really just a misdesign in Sema. - data().Conversions.addDecl(Decl); - } - /// isAggregate - Whether this class is an aggregate (C++ /// [dcl.init.aggr]), which is a class with no user-declared /// constructors, no private or protected non-static data members, /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1). bool isAggregate() const { return data().Aggregate; } - /// setAggregate - Set whether this class is an aggregate (C++ - /// [dcl.init.aggr]). - void setAggregate(bool Agg) { data().Aggregate = Agg; } - - /// setMethodAsVirtual - Make input method virtual and set the necesssary - /// special function bits and other bits accordingly. - void setMethodAsVirtual(FunctionDecl *Method); - /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class /// that is an aggregate that has no non-static non-POD data members, no /// reference data members, no user-defined copy assignment operator and no /// user-defined destructor. bool isPOD() const { return data().PlainOldData; } - /// setPOD - Set whether this class is a POD-type (C++ [class]p4). - void setPOD(bool POD) { data().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 data().Empty; } - /// Set whether this class is empty (C++0x [meta.unary.prop]) - void setEmpty(bool Emp) { data().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 data().Polymorphic; } - /// setPolymorphic - Set whether this class is polymorphic (C++ - /// [class.virtual]). - void setPolymorphic(bool Poly) { data().Polymorphic = Poly; } - /// 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 data().Abstract; } - /// setAbstract - Set whether this class is abstract (C++ [class.abstract]) - void setAbstract(bool Abs) { data().Abstract = Abs; } - // hasTrivialConstructor - Whether this class has a trivial constructor // (C++ [class.ctor]p5) bool hasTrivialConstructor() const { return data().HasTrivialConstructor; } - // setHasTrivialConstructor - Set whether this class has a trivial constructor - // (C++ [class.ctor]p5) - void setHasTrivialConstructor(bool TC) { data().HasTrivialConstructor = TC; } - // hasTrivialCopyConstructor - Whether this class has a trivial copy // constructor (C++ [class.copy]p6) bool hasTrivialCopyConstructor() const { return data().HasTrivialCopyConstructor; } - // setHasTrivialCopyConstructor - Set whether this class has a trivial - // copy constructor (C++ [class.copy]p6) - void setHasTrivialCopyConstructor(bool TC) { - data().HasTrivialCopyConstructor = TC; - } - // hasTrivialCopyAssignment - Whether this class has a trivial copy // assignment operator (C++ [class.copy]p11) bool hasTrivialCopyAssignment() const { return data().HasTrivialCopyAssignment; } - // setHasTrivialCopyAssignment - Set whether this class has a - // trivial copy assignment operator (C++ [class.copy]p11) - void setHasTrivialCopyAssignment(bool TC) { - data().HasTrivialCopyAssignment = TC; - } - // hasTrivialDestructor - Whether this class has a trivial destructor // (C++ [class.dtor]p3) bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } - // setHasTrivialDestructor - Set whether this class has a trivial destructor - // (C++ [class.dtor]p3) - void setHasTrivialDestructor(bool TC) { data().HasTrivialDestructor = TC; } - /// \brief If this record is an instantiation of a member class, /// retrieves the member class from which it was instantiated. /// @@ -854,9 +800,6 @@ public: /// \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(); /// getDestructor - Returns the destructor decl for this class. CXXDestructorDecl *getDestructor() const; @@ -880,7 +823,7 @@ public: /// \param Base the base class we are searching for. /// /// \returns true if this class is derived from Base, false otherwise. - bool isDerivedFrom(CXXRecordDecl *Base) const; + bool isDerivedFrom(const CXXRecordDecl *Base) const; /// \brief Determine whether this class is derived from the type \p Base. /// @@ -898,7 +841,7 @@ public: /// /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than /// tangling input and output in \p Paths - bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const; + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; /// \brief Determine whether this class is virtually derived from /// the class \p Base. @@ -1034,6 +977,9 @@ public: /// most-derived class in the class hierarchy. void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const; + /// \brief Get the indirect primary bases for this class. + void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const; + /// viewInheritance - Renders and displays an inheritance diagram /// for this C++ class and all of its base classes (transitively) using /// GraphViz. @@ -1048,6 +994,27 @@ public: return (PathAccess > DeclAccess ? PathAccess : DeclAccess); } + /// \brief Indicates that the definition of this class is now complete. + virtual void completeDefinition(); + + /// \brief Indicates that the definition of this class is now complete, + /// and provides a final overrider map to help determine + /// + /// \param FinalOverriders The final overrider map for this class, which can + /// be provided as an optimization for abstract-class checking. If NULL, + /// final overriders will be computed if they are needed to complete the + /// definition. + void completeDefinition(CXXFinalOverriderMap *FinalOverriders); + + /// \brief Determine whether this class may end up being abstract, even though + /// it is not yet known to be abstract. + /// + /// \returns true if this class is not known to be abstract but has any + /// base classes that are abstract. In this case, \c completeDefinition() + /// will need to compute final overriders to determine whether the class is + /// actually abstract. + bool mayBeAbstract() const; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstCXXRecord && K <= lastCXXRecord; @@ -1059,6 +1026,8 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; + friend class ASTReader; + friend class ASTWriter; }; /// CXXMethodDecl - Represents a static or instance method of a @@ -1139,6 +1108,20 @@ public: return getType()->getAs<FunctionProtoType>()->getTypeQuals(); } + /// \brief Retrieve the ref-qualifier associated with this method. + /// + /// In the following example, \c f() has an lvalue ref-qualifier, \c g() + /// has an rvalue ref-qualifier, and \c h() has no ref-qualifier. + /// \code + /// struct X { + /// void f() &; + /// void g() &&; + /// void h(); + /// }; + RefQualifierKind getRefQualifier() const { + return getType()->getAs<FunctionProtoType>()->getRefQualifier(); + } + bool hasInlineBody() const; // Implement isa/cast/dyncast/etc. @@ -1149,7 +1132,7 @@ public: } }; -/// CXXBaseOrMemberInitializer - Represents a C++ base or member +/// CXXCtorInitializer - Represents a C++ base or member /// initializer, which is part of a constructor initializer that /// initializes one non-static member variable or one base class. For /// example, in the following, both 'A(a)' and 'f(3.14159)' are member @@ -1163,37 +1146,20 @@ public: /// B(A& a) : A(a), f(3.14159) { } /// }; /// @endcode -class CXXBaseOrMemberInitializer { - /// \brief Either the base class name (stored as a TypeSourceInfo*) or the - /// field being initialized. - llvm::PointerUnion<TypeSourceInfo *, FieldDecl *> BaseOrMember; +class CXXCtorInitializer { + /// \brief Either the base class name (stored as a TypeSourceInfo*), an normal + /// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being + /// initialized. + llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *> + Initializee; - /// \brief The source location for the field name. - SourceLocation MemberLocation; + /// \brief The source location for the field name or, for a base initializer + /// pack expansion, the location of the ellipsis. + SourceLocation MemberOrEllipsisLocation; /// \brief The argument used to initialize the base or member, which may /// end up constructing an object (when multiple arguments are involved). Stmt *Init; - - /// \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. - FieldDecl *AnonUnionMember; /// LParenLoc - Location of the left paren of the ctor-initializer. SourceLocation LParenLoc; @@ -1208,6 +1174,7 @@ class CXXBaseOrMemberInitializer { /// IsWritten - Whether or not the initializer is explicitly written /// in the sources. bool IsWritten : 1; + /// SourceOrderOrNumArrayIndices - If IsWritten is true, then this /// number keeps track of the textual order of this initializer in the /// original sources, counting from 0; otherwise, if IsWritten is false, @@ -1215,50 +1182,62 @@ class CXXBaseOrMemberInitializer { /// object in memory. unsigned SourceOrderOrNumArrayIndices : 14; - CXXBaseOrMemberInitializer(ASTContext &Context, - FieldDecl *Member, SourceLocation MemberLoc, - SourceLocation L, - Expr *Init, - SourceLocation R, - VarDecl **Indices, - unsigned NumIndices); + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R, VarDecl **Indices, unsigned NumIndices); public: - /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. + /// CXXCtorInitializer - Creates a new base-class initializer. explicit - CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, bool IsVirtual, - SourceLocation L, - Expr *Init, - SourceLocation R); + CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, + SourceLocation L, Expr *Init, SourceLocation R, + SourceLocation EllipsisLoc); - /// CXXBaseOrMemberInitializer - Creates a new member initializer. + /// CXXCtorInitializer - Creates a new member initializer. explicit - CXXBaseOrMemberInitializer(ASTContext &Context, - FieldDecl *Member, SourceLocation MemberLoc, - SourceLocation L, - Expr *Init, - SourceLocation R); + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); + + explicit + CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); /// \brief Creates a new member initializer that optionally contains /// array indices used to describe an elementwise initialization. - static CXXBaseOrMemberInitializer *Create(ASTContext &Context, - FieldDecl *Member, - SourceLocation MemberLoc, - SourceLocation L, - Expr *Init, - SourceLocation R, - VarDecl **Indices, - unsigned NumIndices); + static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, + Expr *Init, SourceLocation R, + VarDecl **Indices, unsigned NumIndices); /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. - bool isBaseInitializer() const { return BaseOrMember.is<TypeSourceInfo*>(); } + bool isBaseInitializer() const { return Initializee.is<TypeSourceInfo*>(); } /// isMemberInitializer - Returns true when this initializer is /// initializing a non-static data member. - bool isMemberInitializer() const { return BaseOrMember.is<FieldDecl*>(); } + bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); } + + bool isAnyMemberInitializer() const { + return isMemberInitializer() || isIndirectMemberInitializer(); + } + bool isIndirectMemberInitializer() const { + return Initializee.is<IndirectFieldDecl*>(); + } + + /// \brief Determine whether this initializer is a pack expansion. + bool isPackExpansion() const { + return isBaseInitializer() && MemberOrEllipsisLocation.isValid(); + } + + // \brief For a pack expansion, returns the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + assert(isPackExpansion() && "Initializer is not a pack expansion"); + return MemberOrEllipsisLocation; + } + /// If this is a base class initializer, returns the type of the /// base class with location information. Otherwise, returns an NULL /// type location. @@ -1267,7 +1246,6 @@ public: /// If this is a base class initializer, returns the type of the base class. /// Otherwise, returns NULL. const Type *getBaseClass() const; - Type *getBaseClass(); /// Returns whether the base is virtual or not. bool isBaseVirtual() const { @@ -1278,7 +1256,7 @@ public: /// \brief Returns the declarator information for a base class initializer. TypeSourceInfo *getBaseClassInfo() const { - return BaseOrMember.dyn_cast<TypeSourceInfo *>(); + return Initializee.dyn_cast<TypeSourceInfo *>(); } /// getMember - If this is a member initializer, returns the @@ -1286,18 +1264,28 @@ public: /// initialized. Otherwise, returns NULL. FieldDecl *getMember() const { if (isMemberInitializer()) - return BaseOrMember.get<FieldDecl*>(); + return Initializee.get<FieldDecl*>(); + else + return 0; + } + FieldDecl *getAnyMember() const { + if (isMemberInitializer()) + return Initializee.get<FieldDecl*>(); + else if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>()->getAnonField(); else return 0; } - SourceLocation getMemberLocation() const { - return MemberLocation; + IndirectFieldDecl *getIndirectMember() const { + if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>(); + else + return 0; } - void setMember(FieldDecl *Member) { - assert(isMemberInitializer()); - BaseOrMember = Member; + SourceLocation getMemberLocation() const { + return MemberOrEllipsisLocation; } /// \brief Determine the source location of the initializer. @@ -1329,15 +1317,7 @@ public: IsWritten = true; SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos); } - - FieldDecl *getAnonUnionMember() const { - return AnonUnionMember; - } - void setAnonUnionMember(FieldDecl *anonMember) { - AnonUnionMember = anonMember; - } - SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -1388,10 +1368,10 @@ class CXXConstructorDecl : public CXXMethodDecl { bool ImplicitlyDefined : 1; /// Support for base and member initializers. - /// BaseOrMemberInitializers - The arguments used to initialize the base + /// CtorInitializers - The arguments used to initialize the base /// or member. - CXXBaseOrMemberInitializer **BaseOrMemberInitializers; - unsigned NumBaseOrMemberInitializers; + CXXCtorInitializer **CtorInitializers; + unsigned NumCtorInitializers; CXXConstructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, @@ -1400,7 +1380,7 @@ class CXXConstructorDecl : public CXXMethodDecl { : CXXMethodDecl(CXXConstructor, RD, NameInfo, T, TInfo, false, SC_None, isInline), IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), - BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { + CtorInitializers(0), NumCtorInitializers(0) { setImplicit(isImplicitlyDeclared); } @@ -1443,37 +1423,54 @@ public: } /// init_iterator - Iterates through the member/base initializer list. - typedef CXXBaseOrMemberInitializer **init_iterator; + typedef CXXCtorInitializer **init_iterator; /// init_const_iterator - Iterates through the memberbase initializer list. - typedef CXXBaseOrMemberInitializer * const * init_const_iterator; + typedef CXXCtorInitializer * const * init_const_iterator; /// init_begin() - Retrieve an iterator to the first initializer. - init_iterator init_begin() { return BaseOrMemberInitializers; } + init_iterator init_begin() { return CtorInitializers; } /// begin() - Retrieve an iterator to the first initializer. - init_const_iterator init_begin() const { return BaseOrMemberInitializers; } + init_const_iterator init_begin() const { return CtorInitializers; } /// init_end() - Retrieve an iterator past the last initializer. init_iterator init_end() { - return BaseOrMemberInitializers + NumBaseOrMemberInitializers; + return CtorInitializers + NumCtorInitializers; } /// end() - Retrieve an iterator past the last initializer. init_const_iterator init_end() const { - return BaseOrMemberInitializers + NumBaseOrMemberInitializers; + return CtorInitializers + NumCtorInitializers; + } + + typedef std::reverse_iterator<init_iterator> init_reverse_iterator; + typedef std::reverse_iterator<init_const_iterator> init_const_reverse_iterator; + + init_reverse_iterator init_rbegin() { + return init_reverse_iterator(init_end()); + } + init_const_reverse_iterator init_rbegin() const { + return init_const_reverse_iterator(init_end()); + } + + init_reverse_iterator init_rend() { + return init_reverse_iterator(init_begin()); + } + init_const_reverse_iterator init_rend() const { + return init_const_reverse_iterator(init_begin()); } /// getNumArgs - Determine the number of arguments used to /// initialize the member or base. - unsigned getNumBaseOrMemberInitializers() const { - return NumBaseOrMemberInitializers; + unsigned getNumCtorInitializers() const { + return NumCtorInitializers; } - void setNumBaseOrMemberInitializers(unsigned numBaseOrMemberInitializers) { - NumBaseOrMemberInitializers = numBaseOrMemberInitializers; + void setNumCtorInitializers(unsigned numCtorInitializers) { + NumCtorInitializers = numCtorInitializers; } - void setBaseOrMemberInitializers(CXXBaseOrMemberInitializer ** initializers) { - BaseOrMemberInitializers = initializers; + void setCtorInitializers(CXXCtorInitializer ** initializers) { + CtorInitializers = initializers; } /// isDefaultConstructor - Whether this constructor is a default /// constructor (C++ [class.ctor]p5), which can be used to @@ -1502,15 +1499,44 @@ public: return isCopyConstructor(TypeQuals); } + /// \brief Determine whether this constructor is a move constructor + /// (C++0x [class.copy]p3), which can be used to move values of the class. + /// + /// \param TypeQuals If this constructor is a move constructor, will be set + /// to the type qualifiers on the referent of the first parameter's type. + bool isMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this constructor is a move constructor + /// (C++0x [class.copy]p3), which can be used to move values of the class. + bool isMoveConstructor() const; + + /// \brief Determine whether this is a copy or move constructor. + /// + /// \param TypeQuals Will be set to the type qualifiers on the reference + /// parameter, if in fact this is a copy or move constructor. + bool isCopyOrMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this a copy or move constructor. + bool isCopyOrMoveConstructor() const { + unsigned Quals; + return isCopyOrMoveConstructor(Quals); + } + /// isConvertingConstructor - Whether this constructor is a /// converting constructor (C++ [class.conv.ctor]), which can be /// used for user-defined conversions. bool isConvertingConstructor(bool AllowExplicit) const; /// \brief Determine whether this is a member template specialization that - /// looks like a copy constructor. Such constructors are never used to copy + /// would copy the object to itself. Such constructors are never used to copy /// an object. - bool isCopyConstructorLikeSpecialization() const; + bool isSpecializationCopyingObject() const; + + /// \brief Get the constructor that this inheriting constructor is based on. + const CXXConstructorDecl *getInheritedConstructor() const; + + /// \brief Set the constructor that this inheriting constructor is based on. + void setInheritedConstructor(const CXXConstructorDecl *BaseCtor); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -1542,8 +1568,9 @@ class CXXDestructorDecl : public CXXMethodDecl { FunctionDecl *OperatorDelete; CXXDestructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, - QualType T, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXDestructor, RD, NameInfo, T, /*TInfo=*/0, false, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXDestructor, RD, NameInfo, T, TInfo, false, SC_None, isInline), ImplicitlyDefined(false), OperatorDelete(0) { setImplicit(isImplicitlyDeclared); @@ -1553,7 +1580,8 @@ public: static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty); static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, - QualType T, bool isInline, + QualType T, TypeSourceInfo* TInfo, + bool isInline, bool isImplicitlyDeclared); /// isImplicitlyDefined - Whether this destructor was implicitly @@ -1918,13 +1946,16 @@ class UsingShadowDecl : public NamedDecl { /// The referenced declaration. NamedDecl *Underlying; - /// The using declaration which introduced this decl. - UsingDecl *Using; + /// \brief The using declaration which introduced this decl or the next using + /// shadow declaration contained in the aforementioned using declaration. + NamedDecl *UsingOrNextShadow; + friend class UsingDecl; UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target) : NamedDecl(UsingShadow, DC, Loc, DeclarationName()), - Underlying(Target), Using(Using) { + Underlying(Target), + UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) { if (Target) { setDeclName(Target->getDeclName()); IdentifierNamespace = Target->getIdentifierNamespace(); @@ -1952,15 +1983,20 @@ public: } /// \brief Gets the using declaration to which this declaration is tied. - UsingDecl *getUsingDecl() const { return Using; } + UsingDecl *getUsingDecl() const; - /// \brief Sets the using declaration that introduces this target - /// declaration. - void setUsingDecl(UsingDecl* UD) { Using = UD; } + /// \brief The next using shadow declaration contained in the shadow decl + /// chain of the using declaration which introduced this decl. + UsingShadowDecl *getNextUsingShadowDecl() const { + return dyn_cast_or_null<UsingShadowDecl>(UsingOrNextShadow); + } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingShadowDecl *D) { return true; } static bool classofKind(Kind K) { return K == Decl::UsingShadow; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// UsingDecl - Represents a C++ using-declaration. For example: @@ -1980,10 +2016,9 @@ class UsingDecl : public NamedDecl { /// declaration name embedded in the ValueDecl base class. DeclarationNameLoc DNLoc; - /// \brief The collection of shadow declarations associated with - /// this using declaration. This set can change as a class is - /// processed. - llvm::SmallPtrSet<UsingShadowDecl*, 8> Shadows; + /// \brief The first shadow declaration of the shadow decl chain associated + /// with this using declaration. + UsingShadowDecl *FirstUsingShadow; // \brief Has 'typename' keyword. bool IsTypeName; @@ -1993,7 +2028,7 @@ class UsingDecl : public NamedDecl { const DeclarationNameInfo &NameInfo, bool IsTypeNameArg) : NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()), NestedNameRange(NNR), UsingLocation(UL), TargetNestedName(TargetNNS), - DNLoc(NameInfo.getInfo()), IsTypeName(IsTypeNameArg) { + DNLoc(NameInfo.getInfo()), FirstUsingShadow(0),IsTypeName(IsTypeNameArg) { } public: @@ -2031,29 +2066,58 @@ public: /// \brief Sets whether the using declaration has 'typename'. void setTypeName(bool TN) { IsTypeName = TN; } - typedef llvm::SmallPtrSet<UsingShadowDecl*,8>::const_iterator shadow_iterator; - shadow_iterator shadow_begin() const { return Shadows.begin(); } - shadow_iterator shadow_end() const { return Shadows.end(); } + /// \brief Iterates through the using shadow declarations assosiated with + /// this using declaration. + class shadow_iterator { + /// \brief The current using shadow declaration. + UsingShadowDecl *Current; + + public: + typedef UsingShadowDecl* value_type; + typedef UsingShadowDecl* reference; + typedef UsingShadowDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + shadow_iterator() : Current(0) { } + explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { } - void addShadowDecl(UsingShadowDecl *S) { - assert(S->getUsingDecl() == this); - if (!Shadows.insert(S)) { - assert(false && "declaration already in set"); + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + shadow_iterator& operator++() { + Current = Current->getNextUsingShadowDecl(); + return *this; } - } - void removeShadowDecl(UsingShadowDecl *S) { - assert(S->getUsingDecl() == this); - if (!Shadows.erase(S)) { - assert(false && "declaration not in set"); + + shadow_iterator operator++(int) { + shadow_iterator tmp(*this); + ++(*this); + return tmp; } + + friend bool operator==(shadow_iterator x, shadow_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(shadow_iterator x, shadow_iterator y) { + return x.Current != y.Current; + } + }; + + shadow_iterator shadow_begin() const { + return shadow_iterator(FirstUsingShadow); } + shadow_iterator shadow_end() const { return shadow_iterator(); } /// \brief Return the number of shadowed declarations associated with this /// using declaration. - unsigned getNumShadowDecls() const { - return Shadows.size(); + unsigned shadow_size() const { + return std::distance(shadow_begin(), shadow_end()); } + void addShadowDecl(UsingShadowDecl *S); + void removeShadowDecl(UsingShadowDecl *S); + static UsingDecl *Create(ASTContext &C, DeclContext *DC, SourceRange NNR, SourceLocation UsingL, NestedNameSpecifier* TargetNNS, @@ -2145,6 +2209,9 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UnresolvedUsingValueDecl *D) { return true; } static bool classofKind(Kind K) { return K == UnresolvedUsingValue; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// UnresolvedUsingTypenameDecl - Represents a dependent using diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h index 4b5e6fd48bb3..20d6da19b8ca 100644 --- a/include/clang/AST/DeclFriend.h +++ b/include/clang/AST/DeclFriend.h @@ -43,11 +43,16 @@ private: FriendUnion Friend; // A pointer to the next friend in the sequence. - FriendDecl *NextFriend; + LazyDeclPtr NextFriend; // Location of the 'friend' specifier. SourceLocation FriendLoc; + /// True if this 'friend' declaration is unsupported. Eventually we + /// will support every possible friend declaration, but for now we + /// silently ignore some and set this flag to authorize all access. + bool UnsupportedFriend; + friend class CXXRecordDecl::friend_iterator; friend class CXXRecordDecl; @@ -55,13 +60,19 @@ private: SourceLocation FriendL) : Decl(Decl::Friend, DC, L), Friend(Friend), - NextFriend(0), - FriendLoc(FriendL) { + NextFriend(), + FriendLoc(FriendL), + UnsupportedFriend(false) { } explicit FriendDecl(EmptyShell Empty) - : Decl(Decl::Friend, Empty), NextFriend(0) { } + : Decl(Decl::Friend, Empty), NextFriend() { } + FriendDecl *getNextFriend() { + return cast_or_null<FriendDecl>( + NextFriend.get(getASTContext().getExternalSource())); + } + public: static FriendDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, @@ -87,6 +98,14 @@ public: return FriendLoc; } + /// Determines if this friend kind is unsupported. + bool isUnsupportedFriend() const { + return UnsupportedFriend; + } + void setUnsupportedFriend(bool Unsupported) { + UnsupportedFriend = Unsupported; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FriendDecl *D) { return true; } @@ -115,7 +134,7 @@ public: friend_iterator &operator++() { assert(Ptr && "attempt to increment past end of friend list"); - Ptr = Ptr->NextFriend; + Ptr = Ptr->getNextFriend(); return *this; } diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 030291ea7345..cb9e1681cc06 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_AST_DECLGROUP_H #define LLVM_CLANG_AST_DECLGROUP_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cassert> namespace clang { diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index ad26748e1343..b3ca474fcc19 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -28,7 +28,7 @@ class ObjCProtocolDecl; class ObjCCategoryDecl; class ObjCPropertyDecl; class ObjCPropertyImplDecl; -class CXXBaseOrMemberInitializer; +class CXXCtorInitializer; class ObjCListBase { void operator=(const ObjCListBase &); // DO NOT IMPLEMENT @@ -437,7 +437,7 @@ public: class ObjCInterfaceDecl : public ObjCContainerDecl { /// TypeForDecl - This indicates the Type object that represents this /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType - mutable Type *TypeForDecl; + mutable const Type *TypeForDecl; friend class ASTContext; /// Class's super class. @@ -449,8 +449,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { /// Protocols reference in both the @interface and class extensions. ObjCList<ObjCProtocolDecl> AllReferencedProtocols; - /// List of categories defined for this class. - /// FIXME: Why is this a linked list?? + /// \brief List of categories and class extensions defined for this class. + /// + /// Categories are stored as a linked list in the AST, since the categories + /// and class extensions come long after the initial interface declaration, + /// and we avoid dynamically-resized arrays in the AST whereever possible. ObjCCategoryDecl *CategoryList; /// IvarList - List of all ivars defined by this class; including class @@ -459,7 +462,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { bool ForwardDecl:1; // declared with @class. bool InternalInterface:1; // true - no @interface for @implementation - + + /// \brief Indicates that the contents of this Objective-C class will be + /// completed by the external AST source when required. + mutable bool ExternallyCompleted : 1; + SourceLocation ClassLoc; // location of the class identifier. SourceLocation SuperClassLoc; // location of the super class identifier. SourceLocation EndLoc; // marks the '>', '}', or identifier. @@ -467,6 +474,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, SourceLocation CLoc, bool FD, bool isInternal); + void LoadExternalDefinition() const; public: static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, @@ -474,7 +482,16 @@ public: SourceLocation ClassLoc = SourceLocation(), bool ForwardDecl = false, bool isInternal = false); + + /// \brief Indicate that this Objective-C class is complete, but that + /// the external AST source will be responsible for filling in its contents + /// when a complete class is required. + void setExternallyCompleted(); + const ObjCProtocolList &getReferencedProtocols() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return ReferencedProtocols; } @@ -494,29 +511,47 @@ public: typedef ObjCProtocolList::iterator protocol_iterator; protocol_iterator protocol_begin() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return ReferencedProtocols.begin(); } protocol_iterator protocol_end() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return ReferencedProtocols.end(); } typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; protocol_loc_iterator protocol_loc_begin() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return ReferencedProtocols.loc_begin(); } protocol_loc_iterator protocol_loc_end() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return ReferencedProtocols.loc_end(); } typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator; all_protocol_iterator all_referenced_protocol_begin() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return AllReferencedProtocols.empty() ? protocol_begin() : AllReferencedProtocols.begin(); } all_protocol_iterator all_referenced_protocol_end() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return AllReferencedProtocols.empty() ? protocol_end() : AllReferencedProtocols.end(); } @@ -551,10 +586,22 @@ public: bool isForwardDecl() const { return ForwardDecl; } void setForwardDecl(bool val) { ForwardDecl = val; } - ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } + ObjCInterfaceDecl *getSuperClass() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + + return SuperClass; + } + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } - ObjCCategoryDecl* getCategoryList() const { return CategoryList; } + ObjCCategoryDecl* getCategoryList() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + + return CategoryList; + } + void setCategoryList(ObjCCategoryDecl *category) { CategoryList = category; } @@ -595,7 +642,7 @@ public: ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); // Lookup a method in the classes implementation hierarchy. - ObjCMethodDecl *lookupPrivateInstanceMethod(const Selector &Sel); + ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true); // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } // '@'interface @@ -621,8 +668,8 @@ public: bool RHSIsQualifiedID = false); // Low-level accessor - Type *getTypeForDecl() const { return TypeForDecl; } - void setTypeForDecl(Type *TD) const { TypeForDecl = TD; } + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCInterfaceDecl *D) { return true; } @@ -991,6 +1038,7 @@ public: void insertNextClassCategory() { NextClassCategory = ClassInterface->getCategoryList(); ClassInterface->setCategoryList(this); + ClassInterface->setChangedSinceDeserialization(true); } bool IsClassExtension() const { return getIdentifier() == 0; } @@ -1168,7 +1216,7 @@ class ObjCImplementationDecl : public ObjCImplDecl { ObjCInterfaceDecl *SuperClass; /// Support for ivar initialization. /// IvarInitializers - The arguments used to initialize the ivars - CXXBaseOrMemberInitializer **IvarInitializers; + CXXCtorInitializer **IvarInitializers; unsigned NumIvarInitializers; /// true of class extension has at least one bitfield ivar. @@ -1187,10 +1235,10 @@ public: ObjCInterfaceDecl *superDecl); /// init_iterator - Iterates through the ivar initializer list. - typedef CXXBaseOrMemberInitializer **init_iterator; + typedef CXXCtorInitializer **init_iterator; /// init_const_iterator - Iterates through the ivar initializer list. - typedef CXXBaseOrMemberInitializer * const * init_const_iterator; + typedef CXXCtorInitializer * const * init_const_iterator; /// init_begin() - Retrieve an iterator to the first initializer. init_iterator init_begin() { return IvarInitializers; } @@ -1215,7 +1263,7 @@ public: } void setIvarInitializers(ASTContext &C, - CXXBaseOrMemberInitializer ** initializers, + CXXCtorInitializer ** initializers, unsigned numInitializers); bool hasSynthBitfield() const { return HasSynthBitfield; } @@ -1322,7 +1370,8 @@ public: OBJC_PR_retain = 0x10, OBJC_PR_copy = 0x20, OBJC_PR_nonatomic = 0x40, - OBJC_PR_setter = 0x80 + OBJC_PR_setter = 0x80, + OBJC_PR_atomic = 0x100 }; enum SetterKind { Assign, Retain, Copy }; @@ -1330,8 +1379,8 @@ public: private: SourceLocation AtLoc; // location of @property TypeSourceInfo *DeclType; - unsigned PropertyAttributes : 8; - unsigned PropertyAttributesAsWritten : 8; + unsigned PropertyAttributes : 9; + unsigned PropertyAttributesAsWritten : 9; // @required/@optional unsigned PropertyImplementation : 2; @@ -1429,6 +1478,10 @@ public: return PropertyIvarDecl; } + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, getLocation()); + } + /// Lookup a property by name in the specified DeclContext. static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC, IdentifierInfo *propertyID); @@ -1450,6 +1503,15 @@ public: }; private: SourceLocation AtLoc; // location of @synthesize or @dynamic + + /// \brief For @synthesize, the location of the ivar, if it was written in + /// the source code. + /// + /// \code + /// @synthesize int a = b + /// \endcode + SourceLocation IvarLoc; + /// Property declaration being implemented ObjCPropertyDecl *PropertyDecl; @@ -1466,9 +1528,10 @@ private: ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, Kind PK, - ObjCIvarDecl *ivarDecl) + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc) : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), - PropertyDecl(property), PropertyIvarDecl(ivarDecl), + IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl), GetterCXXConstructor(0), SetterCXXAssignment(0) { assert (PK == Dynamic || PropertyIvarDecl); } @@ -1478,11 +1541,11 @@ public: SourceLocation atLoc, SourceLocation L, ObjCPropertyDecl *property, Kind PK, - ObjCIvarDecl *ivarDecl); + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc); - virtual SourceRange getSourceRange() const { - return SourceRange(AtLoc, getLocation()); - } + virtual SourceRange getSourceRange() const; + SourceLocation getLocStart() const { return AtLoc; } void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } @@ -1498,7 +1561,13 @@ public: ObjCIvarDecl *getPropertyIvarDecl() const { return PropertyIvarDecl; } - void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } + SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar, + SourceLocation IvarLoc) { + PropertyIvarDecl = Ivar; + this->IvarLoc = IvarLoc; + } Expr *getGetterCXXConstructor() const { return GetterCXXConstructor; @@ -1517,6 +1586,8 @@ public: static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyImplDecl *D) { return true; } static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } + + friend class ASTDeclReader; }; } // end namespace clang diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index b532668242fd..176c6badae16 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -53,7 +53,7 @@ class TemplateParameterList { SourceLocation RAngleLoc); public: - static TemplateParameterList *Create(ASTContext &C, + static TemplateParameterList *Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, NamedDecl **Params, @@ -85,7 +85,7 @@ public: return begin()[Idx]; } - /// \btief Returns the minimum number of arguments needed to form a + /// \brief Returns the minimum number of arguments needed to form a /// template specialization. This may be fewer than the number of /// template parameters, if some of the parameters have default /// arguments or if there is a parameter pack. @@ -107,101 +107,57 @@ public: } }; -/// \brief A helper class for making template argument lists. -class TemplateArgumentListBuilder { - TemplateArgument *StructuredArgs; - unsigned MaxStructuredArgs; - unsigned NumStructuredArgs; - - llvm::SmallVector<TemplateArgument, 4> 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), - MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0), - AddingToPack(false), PackBeginIndex(0) { } - - void Append(const TemplateArgument &Arg); - void BeginPack(); - void EndPack(); - - unsigned flatSize() const { return FlatArgs.size(); } - const TemplateArgument *getFlatArguments() const { return FlatArgs.data(); } - - 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; - } -}; - /// \brief A template argument list. -/// -/// FIXME: In the future, this class will be extended to support -/// variadic templates and member templates, which will make some of -/// the function names below make more sense. class TemplateArgumentList { /// \brief The template argument list. /// /// The integer value will be non-zero to indicate that this /// template argument list does own the pointer. - llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments; + llvm::PointerIntPair<const TemplateArgument *, 1> Arguments; /// \brief The number of template arguments in this template /// argument list. - unsigned NumFlatArguments; - - llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments; - unsigned NumStructuredArguments; + unsigned NumArguments; TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL void operator=(const TemplateArgumentList &Other); // DO NOT IMPL + + TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs, + bool Owned) + : Arguments(Args, Owned), NumArguments(NumArgs) { } + public: - /// TemplateArgumentList - If this constructor is passed "true" for 'TakeArgs' - /// it copies them into a locally new[]'d array. If passed "false", then it - /// just references the array passed in. This is only safe if the builder - /// outlives it, but saves a copy. - TemplateArgumentList(ASTContext &Context, - TemplateArgumentListBuilder &Builder, - bool TakeArgs); - - /// TemplateArgumentList - It copies the template arguments into a locally - /// new[]'d array. - TemplateArgumentList(ASTContext &Context, - const TemplateArgument *Args, unsigned NumArgs); - - /// Produces a shallow copy of the given template argument list. This - /// assumes that the input argument list outlives it. This takes the list as - /// a pointer to avoid looking like a copy constructor, since this really - /// really isn't safe to use that way. - explicit TemplateArgumentList(const TemplateArgumentList *Other); - - TemplateArgumentList() : NumFlatArguments(0), NumStructuredArguments(0) { } - - /// \brief Copies the template arguments into a locally new[]'d array. - void init(ASTContext &Context, - const TemplateArgument *Args, unsigned NumArgs); + /// \brief Type used to indicate that the template argument list itself is a + /// stack object. It does not own its template arguments. + enum OnStackType { OnStack }; + + /// \brief Create a new template argument list that copies the given set of + /// template arguments. + static TemplateArgumentList *CreateCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Construct a new, temporary template argument list on the stack. + /// + /// The template argument list does not own the template arguments + /// provided. + explicit TemplateArgumentList(OnStackType, + const TemplateArgument *Args, unsigned NumArgs) + : Arguments(Args, false), NumArguments(NumArgs) { } + + /// \brief Produces a shallow copy of the given template argument list. + /// + /// This operation assumes that the input argument list outlives it. + /// This takes the list as a pointer to avoid looking like a copy + /// constructor, since this really really isn't safe to use that + /// way. + explicit TemplateArgumentList(const TemplateArgumentList *Other) + : Arguments(Other->data(), false), NumArguments(Other->size()) { } /// \brief Retrieve the template argument at a given index. const TemplateArgument &get(unsigned Idx) const { - assert(Idx < NumFlatArguments && "Invalid template argument index"); - return getFlatArgumentList()[Idx]; + assert(Idx < NumArguments && "Invalid template argument index"); + return data()[Idx]; } /// \brief Retrieve the template argument at a given index. @@ -209,15 +165,11 @@ public: /// \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; } + unsigned size() const { return NumArguments; } - /// \brief Retrieve the flattened template argument list. - const TemplateArgument *getFlatArgumentList() const { - return FlatArguments.getPointer(); + /// \brief Retrieve a pointer to the template argument list. + const TemplateArgument *data() const { + return Arguments.getPointer(); } }; @@ -292,7 +244,31 @@ public: /// which is a FunctionDecl that has been explicitly specialization or /// instantiated from a function template. class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { + FunctionTemplateSpecializationInfo(FunctionDecl *FD, + FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI) + : Function(FD), + Template(Template, TSK - 1), + TemplateArguments(TemplateArgs), + TemplateArgumentsAsWritten(TemplateArgsAsWritten), + PointOfInstantiation(POI) { } + public: + static FunctionTemplateSpecializationInfo * + Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI) { + return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK, + TemplateArgs, + TemplateArgsAsWritten, + POI); + } + /// \brief The function template specialization that this structure /// describes. FunctionDecl *Function; @@ -345,8 +321,8 @@ public: } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, TemplateArguments->getFlatArgumentList(), - TemplateArguments->flat_size(), + Profile(ID, TemplateArguments->data(), + TemplateArguments->size(), Function->getASTContext()); } @@ -441,11 +417,6 @@ class DependentFunctionTemplateSpecializationInfo { return reinterpret_cast<FunctionTemplateDecl*const*>(this+1); } - const TemplateArgumentLoc *getTemplateArgs() const { - return reinterpret_cast<const TemplateArgumentLoc*>( - &getTemplates()[getNumTemplates()]); - } - public: DependentFunctionTemplateSpecializationInfo( const UnresolvedSetImpl &Templates, @@ -463,6 +434,12 @@ public: return getTemplates()[I]; } + /// \brief Returns the explicit template arguments that were given. + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgumentLoc*>( + &getTemplates()[getNumTemplates()]); + } + /// \brief Returns the number of explicit template arguments that were given. unsigned getNumTemplateArgs() const { return d.NumArgs; @@ -584,7 +561,7 @@ protected: /// for the common pointer. CommonBase *getCommonPtr(); - virtual CommonBase *newCommon() = 0; + virtual CommonBase *newCommon(ASTContext &C) = 0; // Construct a template decl with name, parameters, and templated element. RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, @@ -789,19 +766,13 @@ protected: TemplateParameterList *Params, NamedDecl *Decl) : RedeclarableTemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { } - CommonBase *newCommon(); + CommonBase *newCommon(ASTContext &C); Common *getCommonPtr() { return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); } - friend void FunctionDecl::setFunctionTemplateSpecialization( - FunctionTemplateDecl *Template, - const TemplateArgumentList *TemplateArgs, - void *InsertPos, - TemplateSpecializationKind TSK, - const TemplateArgumentListInfo *TemplateArgsAsWritten, - SourceLocation PointOfInstantiation); + friend class FunctionDecl; /// \brief Retrieve the set of function template specializations of this /// function template. @@ -940,15 +911,15 @@ class TemplateTypeParmDecl : public TypeDecl { bool Typename, QualType Type, bool ParameterPack) : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename), InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() { - TypeForDecl = Type.getTypePtr(); + TypeForDecl = Type.getTypePtrOrNull(); } public: - static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC, + static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, bool ParameterPack); - static TemplateTypeParmDecl *Create(ASTContext &C, EmptyShell Empty); + static TemplateTypeParmDecl *Create(const ASTContext &C, EmptyShell Empty); /// \brief Whether this template type parameter was declared with /// the 'typename' keyword. If not, it was declared with the 'class' @@ -1014,22 +985,54 @@ public: /// template<int Size> class array { }; /// @endcode class NonTypeTemplateParmDecl - : public VarDecl, protected TemplateParmPosition { + : public DeclaratorDecl, protected TemplateParmPosition { /// \brief The default template argument, if any, and whether or not /// it was inherited. llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited; + // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index + // down here to save memory. + + /// \brief Whether this non-type template parameter is a parameter pack. + bool ParameterPack; + + /// \brief Whether this non-type template parameter is an "expanded" + /// parameter pack, meaning that its type is a pack expansion and we + /// already know the set of types that expansion expands to. + bool ExpandedParameterPack; + + /// \brief The number of types in an expanded parameter pack. + unsigned NumExpandedTypes; + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None), - TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false) + bool ParameterPack, TypeSourceInfo *TInfo) + : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo), + TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), + ParameterPack(ParameterPack), ExpandedParameterPack(false), + NumExpandedTypes(0) { } + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); + + friend class ASTDeclReader; + public: static NonTypeTemplateParmDecl * - Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo); + Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, + TypeSourceInfo *TInfo); + + static NonTypeTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); using TemplateParmPosition::getDepth; using TemplateParmPosition::setDepth; @@ -1037,6 +1040,9 @@ public: using TemplateParmPosition::setPosition; using TemplateParmPosition::getIndex; + SourceLocation getInnerLocStart() const; + SourceRange getSourceRange() const; + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { @@ -1071,6 +1077,65 @@ public: DefaultArgumentAndInherited.setInt(false); } + /// \brief Whether this parameter is a non-type template parameter pack. + /// + /// If the parameter is a parameter pack, the type may be a + /// \c PackExpansionType. In the following example, the \c Dims parameter + /// is a parameter pack (whose type is 'unsigned'). + /// + /// \code + /// template<typename T, unsigned ...Dims> struct multi_array; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + + /// \brief Whether this parameter is a non-type template parameter pack + /// that has different types at different positions. + /// + /// A parameter pack is an expanded parameter pack when the original + /// parameter pack's type was itself a pack expansion, and that expansion + /// has already been expanded. For example, given: + /// + /// \code + /// template<typename ...Types> + /// struct X { + /// template<Types ...Values> + /// struct Y { /* ... */ }; + /// }; + /// \endcode + /// + /// The parameter pack \c Values has a \c PackExpansionType as its type, + /// which expands \c Types. When \c Types is supplied with template arguments + /// by instantiating \c X, the instantiation of \c Values becomes an + /// expanded parameter pack. For example, instantiating + /// \c X<int, unsigned int> results in \c Values being an expanded parameter + /// pack with expansion types \c int and \c unsigned int. + /// + /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions + /// return the expansion types. + bool isExpandedParameterPack() const { return ExpandedParameterPack; } + + /// \brief Retrieves the number of expansion types in an expanded parameter pack. + unsigned getNumExpansionTypes() const { + assert(ExpandedParameterPack && "Not an expansion parameter pack"); + return NumExpandedTypes; + } + + /// \brief Retrieve a particular expansion type within an expanded parameter + /// pack. + QualType getExpansionType(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1); + return QualType::getFromOpaquePtr(TypesAndInfos[2*I]); + } + + /// \brief Retrieve a particular expansion type source info within an + /// expanded parameter pack. + TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1); + return static_cast<TypeSourceInfo *>(TypesAndInfos[2*I+1]); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NonTypeTemplateParmDecl *D) { return true; } @@ -1092,24 +1157,36 @@ class TemplateTemplateParmDecl /// Whether or not the default argument was inherited. bool DefaultArgumentWasInherited; + /// \brief Whether this parameter is a parameter pack. + bool ParameterPack; + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, + unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), TemplateParmPosition(D, P), DefaultArgument(), - DefaultArgumentWasInherited(false) + DefaultArgumentWasInherited(false), ParameterPack(ParameterPack) { } public: - static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC, + static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, + unsigned P, bool ParameterPack, + IdentifierInfo *Id, TemplateParameterList *Params); using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; using TemplateParmPosition::getIndex; + /// \brief Whether this template template parameter is a template + /// parameter pack. + /// + /// \code + /// template<template <class T> ...MetaFunctions> struct Apply; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { @@ -1211,7 +1288,7 @@ class ClassTemplateSpecializationDecl ExplicitSpecializationInfo *ExplicitInfo; /// \brief The template arguments used to describe this specialization. - TemplateArgumentList TemplateArgs; + TemplateArgumentList *TemplateArgs; /// \brief The point where this template was instantiated (if any) SourceLocation PointOfInstantiation; @@ -1224,7 +1301,8 @@ protected: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, ClassTemplateSpecializationDecl *PrevDecl); explicit ClassTemplateSpecializationDecl(Kind DK); @@ -1233,7 +1311,8 @@ public: static ClassTemplateSpecializationDecl * Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, ClassTemplateSpecializationDecl *PrevDecl); static ClassTemplateSpecializationDecl * Create(ASTContext &Context, EmptyShell Empty); @@ -1259,15 +1338,7 @@ public: /// \brief Retrieve the template arguments of the class template /// specialization. const TemplateArgumentList &getTemplateArgs() const { - return TemplateArgs; - } - - /// \brief Initialize the template arguments of the class template - /// specialization. - void initTemplateArgs(TemplateArgument *Args, unsigned NumArgs) { - assert(TemplateArgs.flat_size() == 0 && - "Template arguments already initialized!"); - TemplateArgs.init(getASTContext(), Args, NumArgs); + return *TemplateArgs; } /// \brief Determine the kind of specialization that this @@ -1357,18 +1428,6 @@ public: SpecializedTemplate = PS; } - /// \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, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - ASTContext &Ctx = getASTContext(); - setInstantiationOf(PartialSpec, - new (Ctx) TemplateArgumentList(Ctx, TemplateArgs, - NumTemplateArgs)); - } - /// \brief Note that this class template specialization is an instantiation /// of the given class template. void setInstantiationOf(ClassTemplateDecl *TemplDecl) { @@ -1415,8 +1474,7 @@ public: SourceLocation getInnerLocStart() const { return getTemplateKeywordLoc(); } void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), - getASTContext()); + Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext()); } static void @@ -1440,6 +1498,9 @@ public: static bool classof(const ClassTemplatePartialSpecializationDecl *) { return true; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; class ClassTemplatePartialSpecializationDecl @@ -1469,15 +1530,16 @@ class ClassTemplatePartialSpecializationDecl DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl, unsigned SequenceNumber) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, - TK, DC, L, SpecializedTemplate, Builder, - PrevDecl), + TK, DC, L, SpecializedTemplate, + Args, NumArgs, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), InstantiatedFromMember(0, false) { } @@ -1493,7 +1555,8 @@ public: Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, ClassTemplatePartialSpecializationDecl *PrevDecl, @@ -1512,18 +1575,11 @@ public: return TemplateParams; } - void initTemplateParameters(TemplateParameterList *Params) { - assert(TemplateParams == 0 && "TemplateParams already set"); - TemplateParams = Params; - } - /// Get the template arguments as written. TemplateArgumentLoc *getTemplateArgsAsWritten() const { return ArgsAsWritten; } - void initTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgInfos); - /// Get the number of template arguments as written. unsigned getNumTemplateArgsAsWritten() const { return NumArgsAsWritten; @@ -1532,8 +1588,7 @@ public: /// \brief Get the sequence number for this class template partial /// specialization. unsigned getSequenceNumber() const { return SequenceNumber; } - void setSequenceNumber(unsigned N) { SequenceNumber = N; } - + /// \brief Retrieve the member class template partial specialization from /// which this particular class template partial specialization was /// instantiated. @@ -1617,6 +1672,9 @@ public: static bool classof(const ClassTemplatePartialSpecializationDecl *) { return true; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// Declaration of a class template. @@ -1630,6 +1688,8 @@ protected: /// \brief Data that is common to all of the declarations of a given /// class template. struct Common : CommonBase { + Common() : LazySpecializations() { } + /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; @@ -1641,25 +1701,31 @@ protected: /// \brief The injected-class-name type for this class template. QualType InjectedClassNameType; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known ownly by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations/ + /// partial specializations that follow. + uint32_t *LazySpecializations; }; + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations(); + /// \brief Retrieve the set of specializations of this class template. - llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() { - return getCommonPtr()->Specializations; - } + llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations(); /// \brief Retrieve the set of partial specializations of this class /// template. llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & - getPartialSpecializations() { - return getCommonPtr()->PartialSpecializations; - } + getPartialSpecializations(); ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) : RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { } - CommonBase *newCommon(); + CommonBase *newCommon(ASTContext &C); Common *getCommonPtr() { return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); @@ -1693,9 +1759,7 @@ public: /// \brief Insert the specified specialization knowing that it is not already /// in. InsertPos must be obtained from findSpecialization. - void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - getSpecializations().InsertNode(D, InsertPos); - } + void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos); ClassTemplateDecl *getCanonicalDecl() { return redeclarable_base::getCanonicalDecl(); @@ -1729,9 +1793,7 @@ public: /// \brief Insert the specified partial specialization knowing that it is not /// already in. InsertPos must be obtained from findPartialSpecialization. void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D, - void *InsertPos) { - getPartialSpecializations().InsertNode(D, InsertPos); - } + void *InsertPos); /// \brief Return the next partial specialization sequence number. unsigned getNextPartialSpecSequenceNumber() { diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 8bb627597520..e54719b33d30 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -315,7 +315,7 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { /// retrieved using its member functions (e.g., /// getCXXConstructorName). class DeclarationNameTable { - ASTContext &Ctx; + const ASTContext &Ctx; void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * CXXOperatorIdName *CXXOperatorNames; // Operator names void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* @@ -324,7 +324,7 @@ class DeclarationNameTable { DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE public: - DeclarationNameTable(ASTContext &C); + DeclarationNameTable(const ASTContext &C); ~DeclarationNameTable(); /// getIdentifier - Create a declaration name that is a simple @@ -402,7 +402,7 @@ struct DeclarationNameLoc { DeclarationNameLoc(DeclarationName Name); // FIXME: this should go away once all DNLocs are properly initialized. - DeclarationNameLoc() { NamedType.TInfo = 0; } + DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); } }; // struct DeclarationNameLoc @@ -492,6 +492,10 @@ public: LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding(); } + /// \brief Determine whether this name contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + /// getAsString - Retrieve the human-readable string for this name. std::string getAsString() const; diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h new file mode 100644 index 000000000000..035f57c12ea7 --- /dev/null +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -0,0 +1,82 @@ +//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- 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 EvaluatedExprVisitor class template, which visits +// the potentially-evaluated subexpressions of a potentially-evaluated +// expression. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H +#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" + +namespace clang { + +class ASTContext; + +/// \begin Given a potentially-evaluated expression, this visitor visits all +/// of its potentially-evaluated subexpressions, recursively. +template<typename ImplClass> +class EvaluatedExprVisitor : public StmtVisitor<ImplClass> { + ASTContext &Context; + +public: + explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { } + + // Expressions that have no potentially-evaluated subexpressions (but may have + // other sub-expressions). + void VisitDeclRefExpr(DeclRefExpr *E) { } + void VisitOffsetOfExpr(OffsetOfExpr *E) { } + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { } + void VisitBlockExpr(BlockExpr *E) { } + void VisitCXXUuidofExpr(CXXUuidofExpr *E) { } + void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { } + + void VisitMemberExpr(MemberExpr *E) { + // Only the base matters. + return this->Visit(E->getBase()); + } + + void VisitChooseExpr(ChooseExpr *E) { + // Only the selected subexpression matters; the other one is not evaluated. + return this->Visit(E->getChosenSubExpr(Context)); + } + + void VisitDesignatedInitExpr(DesignatedInitExpr *E) { + // Only the actual initializer matters; the designators are all constant + // expressions. + return this->Visit(E->getInit()); + } + + void VisitCXXTypeidExpr(CXXTypeidExpr *E) { + // typeid(expression) is potentially evaluated when the argument is + // a glvalue of polymorphic type. (C++ 5.2.8p2-3) + if (!E->isTypeOperand() && E->Classify(Context).isGLValue()) + if (const RecordType *Record + = E->getExprOperand()->getType()->template getAs<RecordType>()) + if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic()) + return this->Visit(E->getExprOperand()); + } + + /// \brief The basis case walks all of the children of the statement or + /// expression, assuming they are all potentially evaluated. + void VisitStmt(Stmt *S) { + for (Stmt::child_range C = S->children(); C; ++C) + if (*C) + this->Visit(*C); + } +}; + +} + +#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 48130becf3b5..a17205c2b6b9 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -25,6 +25,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include <cctype> #include <vector> namespace clang { @@ -39,8 +40,10 @@ namespace clang { class CXXBaseSpecifier; class CXXOperatorCallExpr; class CXXMemberCallExpr; + class ObjCPropertyRefExpr; class TemplateArgumentLoc; class TemplateArgumentListInfo; + class OpaqueValueExpr; /// \brief A simple array of base specifiers. typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; @@ -52,24 +55,14 @@ typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; class Expr : public Stmt { QualType TR; - virtual void ANCHOR(); // key function. protected: - /// TypeDependent - Whether this expression is type-dependent - /// (C++ [temp.dep.expr]). - bool TypeDependent : 1; - - /// ValueDependent - Whether this expression is value-dependent - /// (C++ [temp.dep.constexpr]). - bool ValueDependent : 1; - - /// ValueKind - The value classification of this expression. - /// Only actually used by certain subclasses. - unsigned ValueKind : 2; - - enum { BitsRemaining = 28 }; - - Expr(StmtClass SC, QualType T, bool TD, bool VD) - : Stmt(SC), TypeDependent(TD), ValueDependent(VD), ValueKind(0) { + Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, bool ContainsUnexpandedParameterPack) : Stmt(SC) { + ExprBits.TypeDependent = TD; + ExprBits.ValueDependent = VD; + ExprBits.ValueKind = VK; + ExprBits.ObjectKind = OK; + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; setType(T); } @@ -77,15 +70,6 @@ protected: explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } 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) { // In C++, the type of an expression is always adjusted so that it @@ -108,10 +92,10 @@ public: /// @code /// template<int Size, char (&Chars)[Size]> struct meta_string; /// @endcode - bool isValueDependent() const { return ValueDependent; } + bool isValueDependent() const { return ExprBits.ValueDependent; } /// \brief Set whether this expression is value-dependent or not. - void setValueDependent(bool VD) { ValueDependent = VD; } + void setValueDependent(bool VD) { ExprBits.ValueDependent = VD; } /// isTypeDependent - Determines whether this expression is /// type-dependent (C++ [temp.dep.expr]), which means that its type @@ -124,19 +108,38 @@ public: /// x + y; /// } /// @endcode - bool isTypeDependent() const { return TypeDependent; } + bool isTypeDependent() const { return ExprBits.TypeDependent; } /// \brief Set whether this expression is type-dependent or not. - void setTypeDependent(bool TD) { TypeDependent = TD; } + void setTypeDependent(bool TD) { ExprBits.TypeDependent = TD; } + + /// \brief Whether this expression contains an unexpanded parameter + /// pack (for C++0x variadic templates). + /// + /// Given the following function template: + /// + /// \code + /// template<typename F, typename ...Types> + /// void forward(const F &f, Types &&...args) { + /// f(static_cast<Types&&>(args)...); + /// } + /// \endcode + /// + /// The expressions \c args and \c static_cast<Types&&>(args) both + /// contain parameter packs. + bool containsUnexpandedParameterPack() const { + return ExprBits.ContainsUnexpandedParameterPack; + } - /// 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. - virtual SourceRange getSourceRange() const = 0; + /// \brief Set the bit that describes whether this expression + /// contains an unexpanded parameter pack. + void setContainsUnexpandedParameterPack(bool PP = true) { + ExprBits.ContainsUnexpandedParameterPack = PP; + } /// getExprLoc - Return the preferred location for the arrow when diagnosing /// a problem with a generic expression. - virtual SourceLocation getExprLoc() const { return getLocStart(); } + SourceLocation getExprLoc() const; /// isUnusedResultAWarning - Return true if this immediate expression should /// be warned about if the result is unused. If so, fill in Loc and Ranges @@ -145,19 +148,25 @@ public: bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, SourceRange &R2, ASTContext &Ctx) 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 - /// - e[i] - /// - (e), where e must be an lvalue - /// - e.name, where e must be an lvalue - /// - e->name - /// - *e, the type of e cannot be a function type - /// - string-constant - /// - reference type [C++ [expr]] - /// - b ? x : y, where x and y are lvalues of suitable types [C++] + /// isLValue - True if this expression is an "l-value" according to + /// the rules of the current language. C and C++ give somewhat + /// different rules for this concept, but in general, the result of + /// an l-value expression identifies a specific object whereas the + /// result of an r-value expression is a value detached from any + /// specific storage. /// - enum isLvalueResult { + /// C++0x divides the concept of "r-value" into pure r-values + /// ("pr-values") and so-called expiring values ("x-values"), which + /// identify specific objects that can be safely cannibalized for + /// their resources. This is an unfortunate abuse of terminology on + /// the part of the C++ committee. In Clang, when we say "r-value", + /// we generally mean a pr-value. + bool isLValue() const { return getValueKind() == VK_LValue; } + bool isRValue() const { return getValueKind() == VK_RValue; } + bool isXValue() const { return getValueKind() == VK_XValue; } + bool isGLValue() const { return getValueKind() != VK_RValue; } + + enum LValueClassification { LV_Valid, LV_NotObjectType, LV_IncompleteVoidType, @@ -167,7 +176,8 @@ public: LV_SubObjCPropertySetting, LV_ClassTemporary }; - isLvalueResult isLvalue(ASTContext &Ctx) const; + /// Reasons why an expression might not be an l-value. + LValueClassification ClassifyLValue(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, @@ -252,8 +262,14 @@ public: bool isPRValue() const { return Kind >= CL_Function; } bool isRValue() const { return Kind >= CL_XValue; } bool isModifiable() const { return getModifiable() == CM_Modifiable; } + + /// \brief Create a simple, modifiably lvalue + static Classification makeSimpleLValue() { + return Classification(CL_LValue, CM_Modifiable); + } + }; - /// \brief classify - Classify this expression according to the C++0x + /// \brief Classify - Classify this expression according to the C++0x /// expression taxonomy. /// /// C++0x defines ([basic.lval]) a new taxonomy of expressions to replace the @@ -269,7 +285,7 @@ public: return ClassifyImpl(Ctx, 0); } - /// \brief classifyModifiable - Classify this expression according to the + /// \brief ClassifyModifiable - Classify this expression according to the /// C++0x expression taxonomy, and see if it is valid on the left side /// of an assignment. /// @@ -281,6 +297,40 @@ public: return ClassifyImpl(Ctx, &Loc); } + /// getValueKindForType - Given a formal return or parameter type, + /// give its value kind. + static ExprValueKind getValueKindForType(QualType T) { + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + return (isa<LValueReferenceType>(RT) + ? VK_LValue + : (RT->getPointeeType()->isFunctionType() + ? VK_LValue : VK_XValue)); + return VK_RValue; + } + + /// getValueKind - The value kind that this expression produces. + ExprValueKind getValueKind() const { + return static_cast<ExprValueKind>(ExprBits.ValueKind); + } + + /// getObjectKind - The object kind that this expression produces. + /// Object kinds are meaningful only for expressions that yield an + /// l-value or x-value. + ExprObjectKind getObjectKind() const { + return static_cast<ExprObjectKind>(ExprBits.ObjectKind); + } + + bool isOrdinaryOrBitFieldObject() const { + ExprObjectKind OK = getObjectKind(); + return (OK == OK_Ordinary || OK == OK_BitField); + } + + /// setValueKind - Set the value kind produced by this expression. + void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; } + + /// setObjectKind - Set the object kind produced by this expression. + void setObjectKind(ExprObjectKind Cat) { ExprBits.ObjectKind = Cat; } + private: Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const; @@ -294,6 +344,10 @@ public: return const_cast<Expr*>(this)->getBitField(); } + /// \brief If this expression is an l-value for an Objective C + /// property, find the underlying property reference expression. + const ObjCPropertyRefExpr *getObjCProperty() const; + /// \brief Returns whether this expression refers to a vector element. bool refersToVectorElement() const; @@ -355,33 +409,49 @@ public: /// any crazy technique (that has nothing to do with language standards) that /// we want to. If this function returns true, it returns the folded constant /// in Result. - bool Evaluate(EvalResult &Result, ASTContext &Ctx) const; + bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const; /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we we can fold and convert to a boolean condition using /// any crazy technique that we want to. - bool EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const; + bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. - bool isEvaluatable(ASTContext &Ctx) const; + bool isEvaluatable(const ASTContext &Ctx) const; /// HasSideEffects - This routine returns true for all those expressions - /// which must be evaluated each time and must not be optimization away + /// which must be evaluated each time and must not be optimized away /// or evaluated at compile time. Example is a function call, volatile /// variable read. - bool HasSideEffects(ASTContext &Ctx) const; + bool HasSideEffects(const ASTContext &Ctx) const; /// EvaluateAsInt - Call Evaluate and return the folded integer. This /// must be called on an expression that constant folds to an integer. - llvm::APSInt EvaluateAsInt(ASTContext &Ctx) const; + llvm::APSInt EvaluateAsInt(const ASTContext &Ctx) const; /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue /// with link time known address. - bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const; + bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const; /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue. - bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const; + bool EvaluateAsAnyLValue(EvalResult &Result, const ASTContext &Ctx) const; + + /// \brief Enumeration used to describe the kind of Null pointer constant + /// returned from \c isNullPointerConstant(). + enum NullPointerConstantKind { + /// \brief Expression is not a Null pointer constant. + NPCK_NotNull = 0, + + /// \brief Expression is a Null pointer constant built from a zero integer. + NPCK_ZeroInteger, + + /// \brief Expression is a C++0X nullptr. + NPCK_CXX0X_nullptr, + + /// \brief Expression is a GNU-style __null constant. + NPCK_GNUNull + }; /// \brief Enumeration used to describe how \c isNullPointerConstant() /// should cope with value-dependent expressions. @@ -398,16 +468,30 @@ public: 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, - NullPointerConstantValueDependence NPC) const; + /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to + /// a Null pointer constant. The return value can further distinguish the + /// kind of NULL pointer constant that was detected. + NullPointerConstantKind isNullPointerConstant( + ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const; /// isOBJCGCCandidate - Return true if this expression may be used in a read/ /// write barrier. bool isOBJCGCCandidate(ASTContext &Ctx) const; + /// \brief Returns true if this expression is a bound member function. + bool isBoundMemberFunction(ASTContext &Ctx) const; + + /// \brief Result type of CanThrow(). + enum CanThrowResult { + CT_Cannot, + CT_Dependent, + CT_Can + }; + /// \brief Test if this expression, if evaluated, might throw, according to + /// the rules of C++ [expr.unary.noexcept]. + CanThrowResult CanThrow(ASTContext &C) const; + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return /// its subexpression. If that subexpression is also a ParenExpr, /// then this method recursively returns its subexpression, and so forth. @@ -422,6 +506,18 @@ public: /// ParenExpr or ImplicitCastExprs, returning their operand. Expr *IgnoreParenImpCasts(); + const Expr *IgnoreParenImpCasts() const { + return const_cast<Expr*>(this)->IgnoreParenImpCasts(); + } + + /// Ignore parentheses and lvalue casts. Strip off any ParenExpr and + /// CastExprs that represent lvalue casts, returning their operand. + Expr *IgnoreParenLValueCasts(); + + const Expr *IgnoreParenLValueCasts() const { + return const_cast<Expr*>(this)->IgnoreParenLValueCasts(); + } + /// 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. @@ -436,14 +532,9 @@ public: /// the expression is a default argument. bool isDefaultArgument() const; - /// \brief Determine whether this expression directly creates a - /// temporary object (of class type). - bool isTemporaryObject() const { return getTemporaryObject() != 0; } - - /// \brief If this expression directly creates a temporary object of - /// class type, return the expression that actually constructs that - /// temporary object. - const Expr *getTemporaryObject() const; + /// \brief Determine whether the result of this expression is a + /// temporary object of the given class type. + bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const; const Expr *IgnoreParens() const { return const_cast<Expr*>(this)->IgnoreParens(); @@ -470,6 +561,63 @@ public: // Primary Expressions. //===----------------------------------------------------------------------===// +/// OpaqueValueExpr - An expression referring to an opaque object of a +/// fixed type and value class. These don't correspond to concrete +/// syntax; instead they're used to express operations (usually copy +/// operations) on values whose source is generally obvious from +/// context. +class OpaqueValueExpr : public Expr { + friend class ASTStmtReader; + Expr *SourceExpr; + SourceLocation Loc; + +public: + OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, + ExprObjectKind OK = OK_Ordinary) + : Expr(OpaqueValueExprClass, T, VK, OK, + T->isDependentType(), T->isDependentType(), false), + SourceExpr(0), Loc(Loc) { + } + + /// Given an expression which invokes a copy constructor --- i.e. a + /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- + /// find the OpaqueValueExpr that's the source of the construction. + static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); + + explicit OpaqueValueExpr(EmptyShell Empty) + : Expr(OpaqueValueExprClass, Empty) { } + + /// \brief Retrieve the location of this expression. + SourceLocation getLocation() const { return Loc; } + + SourceRange getSourceRange() const { + if (SourceExpr) return SourceExpr->getSourceRange(); + return Loc; + } + SourceLocation getExprLoc() const { + if (SourceExpr) return SourceExpr->getExprLoc(); + return Loc; + } + + child_range children() { return child_range(); } + + /// The source expression of an opaque value expression is the + /// expression which originally generated the value. This is + /// provided as a convenience for analyses that don't wish to + /// precisely model the execution behavior of the program. + /// + /// The source expression is typically set when building the + /// expression which binds the opaque value expression in the first + /// place. + Expr *getSourceExpr() const { return SourceExpr; } + void setSourceExpr(Expr *e) { SourceExpr = e; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpaqueValueExprClass; + } + static bool classof(const OpaqueValueExpr *) { return true; } +}; + /// \brief Represents the qualifier that may precede a C++ name, e.g., the /// "std::" in "std::sort". struct NameQualifier { @@ -505,6 +653,8 @@ struct ExplicitTemplateArgumentList { } void initializeFrom(const TemplateArgumentListInfo &List); + void initializeFrom(const TemplateArgumentListInfo &List, + bool &Dependent, bool &ContainsUnexpandedParameterPack); void copyInto(TemplateArgumentListInfo &List) const; static std::size_t sizeFor(unsigned NumTemplateArgs); static std::size_t sizeFor(const TemplateArgumentListInfo &List); @@ -551,12 +701,12 @@ class DeclRefExpr : public Expr { DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, ValueDecl *D, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs, - QualType T); + QualType T, ExprValueKind VK); DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, ValueDecl *D, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, - QualType T); + QualType T, ExprValueKind VK); /// \brief Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) @@ -567,8 +717,9 @@ class DeclRefExpr : public Expr { void computeDependence(); public: - DeclRefExpr(ValueDecl *d, QualType t, SourceLocation l) : - Expr(DeclRefExprClass, t, false, false), DecoratedD(d, 0), Loc(l) { + DeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK, SourceLocation l) : + Expr(DeclRefExprClass, t, VK, OK_Ordinary, false, false, false), + DecoratedD(d, 0), Loc(l) { computeDependence(); } @@ -577,7 +728,7 @@ public: SourceRange QualifierRange, ValueDecl *D, SourceLocation NameLoc, - QualType T, + QualType T, ExprValueKind VK, const TemplateArgumentListInfo *TemplateArgs = 0); static DeclRefExpr *Create(ASTContext &Context, @@ -585,12 +736,14 @@ public: SourceRange QualifierRange, ValueDecl *D, const DeclarationNameInfo &NameInfo, - QualType T, + QualType T, ExprValueKind VK, const TemplateArgumentListInfo *TemplateArgs = 0); /// \brief Construct an empty declaration reference expression. static DeclRefExpr *CreateEmpty(ASTContext &Context, - bool HasQualifier, unsigned NumTemplateArgs); + bool HasQualifier, + bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); ValueDecl *getDecl() { return DecoratedD.getPointer(); } const ValueDecl *getDecl() const { return DecoratedD.getPointer(); } @@ -602,7 +755,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; /// \brief Determine whether this declaration reference was preceded by a /// C++ nested-name-specifier, e.g., \c N::foo. @@ -706,8 +859,7 @@ public: static bool classof(const DeclRefExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } friend class ASTStmtReader; friend class ASTStmtWriter; @@ -730,8 +882,10 @@ private: IdentType Type; public: PredefinedExpr(SourceLocation l, QualType type, IdentType IT) - : Expr(PredefinedExprClass, type, type->isDependentType(), - type->isDependentType()), Loc(l), Type(IT) {} + : Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary, + type->isDependentType(), type->isDependentType(), + /*ContainsUnexpandedParameterPack=*/false), + Loc(l), Type(IT) {} /// \brief Construct an empty predefined expression. explicit PredefinedExpr(EmptyShell Empty) @@ -745,7 +899,7 @@ public: static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } static bool classof(const Stmt *T) { return T->getStmtClass() == PredefinedExprClass; @@ -753,8 +907,7 @@ public: static bool classof(const PredefinedExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without @@ -817,7 +970,9 @@ public: // or UnsignedLongLongTy IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) - : Expr(IntegerLiteralClass, type, false, false), Loc(l) { + : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false), + Loc(l) { assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); setValue(C, V); } @@ -829,7 +984,7 @@ public: static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty); llvm::APInt getValue() const { return Num.getValue(); } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } /// \brief Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } @@ -843,8 +998,7 @@ public: static bool classof(const IntegerLiteral *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; class CharacterLiteral : public Expr { @@ -854,8 +1008,9 @@ class CharacterLiteral : public Expr { public: // type should be IntTy CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l) - : Expr(CharacterLiteralClass, type, false, false), Value(value), Loc(l), - IsWide(iswide) { + : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false), + Value(value), Loc(l), IsWide(iswide) { } /// \brief Construct an empty character literal. @@ -864,7 +1019,7 @@ public: SourceLocation getLocation() const { return Loc; } bool isWide() const { return IsWide; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } unsigned getValue() const { return Value; } @@ -878,8 +1033,7 @@ public: static bool classof(const CharacterLiteral *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; class FloatingLiteral : public Expr { @@ -889,7 +1043,8 @@ class FloatingLiteral : public Expr { FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) - : Expr(FloatingLiteralClass, Type, false, false), + : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, + false), IsExact(isexact), Loc(L) { setValue(C, V); } @@ -919,7 +1074,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } static bool classof(const Stmt *T) { return T->getStmtClass() == FloatingLiteralClass; @@ -927,8 +1082,7 @@ public: static bool classof(const FloatingLiteral *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// ImaginaryLiteral - We support imaginary integer and floating point literals, @@ -940,7 +1094,9 @@ class ImaginaryLiteral : public Expr { Stmt *Val; public: ImaginaryLiteral(Expr *val, QualType Ty) - : Expr(ImaginaryLiteralClass, Ty, false, false), Val(val) {} + : Expr(ImaginaryLiteralClass, Ty, VK_RValue, OK_Ordinary, false, false, + false), + Val(val) {} /// \brief Build an empty imaginary literal. explicit ImaginaryLiteral(EmptyShell Empty) @@ -950,15 +1106,14 @@ public: Expr *getSubExpr() { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } - virtual SourceRange getSourceRange() const { return Val->getSourceRange(); } + SourceRange getSourceRange() const { return Val->getSourceRange(); } 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(); + child_range children() { return child_range(&Val, &Val+1); } }; /// StringLiteral - This represents a string literal expression, e.g. "foo" @@ -984,7 +1139,8 @@ class StringLiteral : public Expr { unsigned NumConcatenated; SourceLocation TokLocs[1]; - StringLiteral(QualType Ty) : Expr(StringLiteralClass, Ty, false, false) {} + StringLiteral(QualType Ty) : + Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false) {} public: /// This is the "fully general" constructor that allows representation of @@ -1034,12 +1190,23 @@ public: assert(TokNum < NumConcatenated && "Invalid tok number"); TokLocs[TokNum] = L; } + + /// getLocationOfByte - Return a source location that points to the specified + /// byte of this string literal. + /// + /// Strings are amazingly complex. They can be formed from multiple tokens + /// and can have escape sequences in them in addition to the usual trigraph + /// and escaped newline business. This routine handles this complexity. + /// + SourceLocation getLocationOfByte(unsigned ByteNo, const SourceManager &SM, + const LangOptions &Features, + const TargetInfo &Target) const; typedef const SourceLocation *tokloc_iterator; tokloc_iterator tokloc_begin() const { return TokLocs; } tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]); } static bool classof(const Stmt *T) { @@ -1048,8 +1215,7 @@ public: static bool classof(const StringLiteral *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This @@ -1060,7 +1226,9 @@ class ParenExpr : public Expr { public: ParenExpr(SourceLocation l, SourceLocation r, Expr *val) : Expr(ParenExprClass, val->getType(), - val->isTypeDependent(), val->isValueDependent()), + val->getValueKind(), val->getObjectKind(), + val->isTypeDependent(), val->isValueDependent(), + val->containsUnexpandedParameterPack()), L(l), R(r), Val(val) {} /// \brief Construct an empty parenthesized expression. @@ -1071,7 +1239,7 @@ public: Expr *getSubExpr() { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } - virtual SourceRange getSourceRange() const { return SourceRange(L, R); } + SourceRange getSourceRange() const { return SourceRange(L, R); } /// \brief Get the location of the left parentheses '('. SourceLocation getLParen() const { return L; } @@ -1087,8 +1255,7 @@ public: static bool classof(const ParenExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Val, &Val+1); } }; @@ -1112,10 +1279,12 @@ private: Stmt *Val; public: - UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l) - : Expr(UnaryOperatorClass, type, + UnaryOperator(Expr *input, Opcode opc, QualType type, + ExprValueKind VK, ExprObjectKind OK, SourceLocation l) + : Expr(UnaryOperatorClass, type, VK, OK, input->isTypeDependent() || type->isDependentType(), - input->isValueDependent()), + input->isValueDependent(), + input->containsUnexpandedParameterPack()), Opc(opc), Loc(l), Val(input) {} /// \brief Build an empty unary operator. @@ -1137,7 +1306,7 @@ public: return Op == UO_PostInc || Op == UO_PostDec; } - /// isPostfix - Return true if this is a prefix operation, like --x. + /// isPrefix - Return true if this is a prefix operation, like --x. static bool isPrefix(Opcode Op) { return Op == UO_PreInc || Op == UO_PreDec; } @@ -1167,13 +1336,13 @@ public: /// the given unary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { if (isPostfix()) return SourceRange(Val->getLocStart(), Loc); else return SourceRange(Loc, Val->getLocEnd()); } - virtual SourceLocation getExprLoc() const { return Loc; } + SourceLocation getExprLoc() const { return Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryOperatorClass; @@ -1181,8 +1350,7 @@ public: static bool classof(const UnaryOperator *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Val, &Val+1); } }; /// OffsetOfExpr - [C99 7.17] - This represents an expression of the form @@ -1369,7 +1537,7 @@ public: return NumExprs; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(OperatorLoc, RParenLoc); } @@ -1380,8 +1548,12 @@ public: static bool classof(const OffsetOfExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + Stmt **begin = + reinterpret_cast<Stmt**>(reinterpret_cast<OffsetOfNode*>(this + 1) + + NumComps); + return child_range(begin, begin + NumExprs); + } }; /// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of @@ -1399,10 +1571,11 @@ public: SizeOfAlignOfExpr(bool issizeof, TypeSourceInfo *TInfo, QualType resultType, SourceLocation op, SourceLocation rp) : - Expr(SizeOfAlignOfExprClass, resultType, + Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. - TInfo->getType()->isDependentType()), + TInfo->getType()->isDependentType(), + TInfo->getType()->containsUnexpandedParameterPack()), isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) { Argument.Ty = TInfo; } @@ -1410,10 +1583,11 @@ public: SizeOfAlignOfExpr(bool issizeof, Expr *E, QualType resultType, SourceLocation op, SourceLocation rp) : - Expr(SizeOfAlignOfExprClass, resultType, + Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. - E->isTypeDependent()), + E->isTypeDependent(), + E->containsUnexpandedParameterPack()), isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) { Argument.Ex = E; } @@ -1459,7 +1633,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(OpLoc, RParenLoc); } @@ -1469,8 +1643,7 @@ public: static bool classof(const SizeOfAlignOfExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children(); }; //===----------------------------------------------------------------------===// @@ -1484,10 +1657,13 @@ class ArraySubscriptExpr : public Expr { SourceLocation RBracketLoc; public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, + ExprValueKind VK, ExprObjectKind OK, SourceLocation rbracketloc) - : Expr(ArraySubscriptExprClass, t, + : Expr(ArraySubscriptExprClass, t, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), - lhs->isValueDependent() || rhs->isValueDependent()), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), RBracketLoc(rbracketloc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; @@ -1530,14 +1706,14 @@ public: return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); } - virtual SourceRange getSourceRange() const { + 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(); } + SourceLocation getExprLoc() const { return getBase()->getExprLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ArraySubscriptExprClass; @@ -1545,8 +1721,9 @@ public: static bool classof(const ArraySubscriptExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } }; @@ -1557,19 +1734,36 @@ public: /// a subclass for overloaded operator calls that use operator syntax, e.g., /// "str1 + str2" to resolve to a function call. class CallExpr : public Expr { - enum { FN=0, ARGS_START=1 }; + enum { FN=0, PREARGS_START=1 }; 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); + // These versions of the constructor are for derived classes. + CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, + Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + SourceLocation rparenloc); + CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty); + + Stmt *getPreArg(unsigned i) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + const Stmt *getPreArg(unsigned i) const { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + void setPreArg(unsigned i, Stmt *PreArg) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + SubExprs[PREARGS_START+i] = PreArg; + } + + unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } public: CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t, - SourceLocation rparenloc); + ExprValueKind VK, SourceLocation rparenloc); /// \brief Build an empty call expression. CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty); @@ -1593,20 +1787,25 @@ public: /// unsigned getNumArgs() const { return NumArgs; } + /// \brief Retrieve the call arguments. + Expr **getArgs() { + return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START); + } + /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(SubExprs[Arg+ARGS_START]); + return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]); } const Expr *getArg(unsigned Arg) const { assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(SubExprs[Arg+ARGS_START]); + return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_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; + SubExprs[Arg+getNumPreArgs()+PREARGS_START] = ArgExpr; } /// setNumArgs - This changes the number of arguments present in this call. @@ -1617,10 +1816,16 @@ public: 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();} + arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); } + arg_iterator arg_end() { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } + const_arg_iterator arg_begin() const { + return SubExprs+PREARGS_START+getNumPreArgs(); + } + const_arg_iterator arg_end() const { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } /// getNumCommas - Return the number of commas that must have been present in /// this function call. @@ -1628,7 +1833,7 @@ public: /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If /// not, return 0. - unsigned isBuiltinCall(ASTContext &Context) const; + unsigned isBuiltinCall(const 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 @@ -1638,7 +1843,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getCallee()->getLocStart(), RParenLoc); } @@ -1649,8 +1854,10 @@ public: static bool classof(const CallExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], + &SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START); + } }; /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. @@ -1705,9 +1912,11 @@ class MemberExpr : public Expr { public: MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, - const DeclarationNameInfo &NameInfo, QualType ty) - : Expr(MemberExprClass, ty, - base->isTypeDependent(), base->isValueDependent()), + const DeclarationNameInfo &NameInfo, QualType ty, + ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, + base->isTypeDependent(), base->isValueDependent(), + base->containsUnexpandedParameterPack()), Base(base), MemberDecl(memberdecl), MemberLoc(NameInfo.getLoc()), MemberDNLoc(NameInfo.getInfo()), IsArrow(isarrow), HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) { @@ -1719,9 +1928,11 @@ public: // (i.e., source locations for C++ operator names or type source info // for constructors, destructors and conversion oeprators). MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, - SourceLocation l, QualType ty) - : Expr(MemberExprClass, ty, - base->isTypeDependent(), base->isValueDependent()), + SourceLocation l, QualType ty, + ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, + base->isTypeDependent(), base->isValueDependent(), + base->containsUnexpandedParameterPack()), Base(base), MemberDecl(memberdecl), MemberLoc(l), MemberDNLoc(), IsArrow(isarrow), HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {} @@ -1731,7 +1942,7 @@ public: ValueDecl *memberdecl, DeclAccessPair founddecl, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *targs, - QualType ty); + QualType ty, ExprValueKind VK, ExprObjectKind OK); void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast<Expr>(Base); } @@ -1866,7 +2077,7 @@ public: SourceLocation getMemberLoc() const { return MemberLoc; } void setMemberLoc(SourceLocation L) { MemberLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { // If we have an implicit base (like a C++ implicit this), // make sure not to return its location SourceLocation EndLoc = (HasExplicitTemplateArgumentList) @@ -1878,7 +2089,7 @@ public: return SourceRange(BaseLoc, EndLoc); } - virtual SourceLocation getExprLoc() const { return MemberLoc; } + SourceLocation getExprLoc() const { return MemberLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == MemberExprClass; @@ -1886,8 +2097,10 @@ public: static bool classof(const MemberExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Base, &Base+1); } + + friend class ASTReader; + friend class ASTStmtWriter; }; /// CompoundLiteralExpr - [C99 6.5.2.5] @@ -1904,11 +2117,12 @@ class CompoundLiteralExpr : public Expr { Stmt *Init; bool FileScope; public: - // FIXME: Can compound literals be value-dependent? CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, - QualType T, Expr *init, bool fileScope) - : Expr(CompoundLiteralExprClass, T, - tinfo->getType()->isDependentType(), false), + QualType T, ExprValueKind VK, Expr *init, bool fileScope) + : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary, + tinfo->getType()->isDependentType(), + init->isValueDependent(), + init->containsUnexpandedParameterPack()), LParenLoc(lparenloc), TInfo(tinfo), Init(init), FileScope(fileScope) {} /// \brief Construct an empty compound literal. @@ -1928,7 +2142,7 @@ public: TypeSourceInfo *getTypeSourceInfo() const { return TInfo; } void setTypeSourceInfo(TypeSourceInfo* tinfo) { TInfo = tinfo; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { // FIXME: Init should never be null. if (!Init) return SourceRange(); @@ -1943,8 +2157,7 @@ public: static bool classof(const CompoundLiteralExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Init, &Init+1); } }; /// CastExpr - Base class for type casts, including both implicit @@ -1956,11 +2169,9 @@ public: typedef clang::CastKind CastKind; private: - unsigned Kind : 5; - unsigned BasePathSize : BitsRemaining - 5; Stmt *Op; - void CheckBasePath() const { + void CheckCastConsistency() const { #ifndef NDEBUG switch (getCastKind()) { case CK_DerivedToBase: @@ -1972,16 +2183,13 @@ private: break; // These should not have an inheritance path. - case CK_Unknown: case CK_BitCast: - case CK_LValueBitCast: - case CK_NoOp: case CK_Dynamic: case CK_ToUnion: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_NullToMemberPointer: - case CK_UserDefinedConversion: + case CK_NullToPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToIntegral: @@ -1991,10 +2199,32 @@ private: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: - case CK_MemberPointerToBoolean: case CK_AnyPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + assert(!getType()->isBooleanType() && "unheralded conversion to bool"); + // fallthrough to check for null base path + + case CK_Dependent: + case CK_LValueToRValue: + case CK_GetObjCProperty: + case CK_NoOp: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_FloatingToBoolean: + case CK_MemberPointerToBoolean: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: + case CK_LValueBitCast: // -> bool& + case CK_UserDefinedConversion: // operator bool() assert(path_empty() && "Cast kind should not have a base path!"); break; } @@ -2007,26 +2237,33 @@ private: CXXBaseSpecifier **path_buffer(); protected: - CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op, - unsigned BasePathSize) : - Expr(SC, ty, + CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + const CastKind kind, Expr *op, unsigned BasePathSize) : + Expr(SC, ty, VK, OK_Ordinary, // 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())), - Kind(kind), BasePathSize(BasePathSize), Op(op) { - CheckBasePath(); + ty->isDependentType() || (op && op->isValueDependent()), + (ty->containsUnexpandedParameterPack() || + op->containsUnexpandedParameterPack())), + Op(op) { + assert(kind != CK_Invalid && "creating cast with invalid cast kind"); + CastExprBits.Kind = kind; + CastExprBits.BasePathSize = BasePathSize; + CheckCastConsistency(); } /// \brief Construct an empty cast. CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize) - : Expr(SC, Empty), BasePathSize(BasePathSize) { } + : Expr(SC, Empty) { + CastExprBits.BasePathSize = BasePathSize; + } public: - CastKind getCastKind() const { return static_cast<CastKind>(Kind); } - void setCastKind(CastKind K) { Kind = K; } + CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; } + void setCastKind(CastKind K) { CastExprBits.Kind = K; } const char *getCastKindName() const; Expr *getSubExpr() { return cast<Expr>(Op); } @@ -2043,8 +2280,8 @@ public: typedef CXXBaseSpecifier **path_iterator; typedef const CXXBaseSpecifier * const *path_const_iterator; - bool path_empty() const { return BasePathSize == 0; } - unsigned path_size() const { return BasePathSize; } + bool path_empty() const { return CastExprBits.BasePathSize == 0; } + unsigned path_size() const { return CastExprBits.BasePathSize; } path_iterator path_begin() { return path_buffer(); } path_iterator path_end() { return path_buffer() + path_size(); } path_const_iterator path_begin() const { return path_buffer(); } @@ -2059,8 +2296,7 @@ public: static bool classof(const CastExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Op, &Op+1); } }; /// ImplicitCastExpr - Allows us to explicitly represent implicit type @@ -2087,8 +2323,7 @@ class ImplicitCastExpr : public CastExpr { private: ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, unsigned BasePathLength, ExprValueKind VK) - : CastExpr(ImplicitCastExprClass, ty, kind, op, BasePathLength) { - ValueKind = VK; + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { } /// \brief Construct an empty implicit cast. @@ -2099,8 +2334,7 @@ public: enum OnStack_t { OnStack }; ImplicitCastExpr(OnStack_t _, QualType ty, CastKind kind, Expr *op, ExprValueKind VK) - : CastExpr(ImplicitCastExprClass, ty, kind, op, 0) { - ValueKind = VK; + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) { } static ImplicitCastExpr *Create(ASTContext &Context, QualType T, @@ -2110,18 +2344,10 @@ public: static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return getSubExpr()->getSourceRange(); } - /// getValueKind - The value kind that this cast produces. - ExprValueKind getValueKind() const { - return static_cast<ExprValueKind>(ValueKind); - } - - /// setValueKind - Set the value kind this cast produces. - void setValueKind(ExprValueKind Cat) { ValueKind = Cat; } - static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitCastExprClass; } @@ -2150,9 +2376,10 @@ class ExplicitCastExpr : public CastExpr { TypeSourceInfo *TInfo; protected: - ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind, - Expr *op, unsigned PathSize, TypeSourceInfo *writtenTy) - : CastExpr(SC, exprTy, kind, op, PathSize), TInfo(writtenTy) {} + ExplicitCastExpr(StmtClass SC, QualType exprTy, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy) + : CastExpr(SC, exprTy, VK, kind, op, PathSize), TInfo(writtenTy) {} /// \brief Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) @@ -2182,10 +2409,10 @@ class CStyleCastExpr : public ExplicitCastExpr { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren - CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, + CStyleCastExpr(QualType exprTy, ExprValueKind vk, CastKind kind, Expr *op, unsigned PathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation r) - : ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, PathSize, + : ExplicitCastExpr(CStyleCastExprClass, exprTy, vk, kind, op, PathSize, writtenTy), LPLoc(l), RPLoc(r) {} /// \brief Construct an empty C-style explicit cast. @@ -2193,7 +2420,8 @@ class CStyleCastExpr : public ExplicitCastExpr { : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } public: - static CStyleCastExpr *Create(ASTContext &Context, QualType T, CastKind K, + static CStyleCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation R); @@ -2206,7 +2434,7 @@ public: SourceLocation getRParenLoc() const { return RPLoc; } void setRParenLoc(SourceLocation L) { RPLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd()); } static bool classof(const Stmt *T) { @@ -2246,10 +2474,13 @@ private: public: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc) - : Expr(BinaryOperatorClass, ResTy, + : Expr(BinaryOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), - lhs->isValueDependent() || rhs->isValueDependent()), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), Opc(opc), OpLoc(opLoc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; @@ -2272,7 +2503,7 @@ public: Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd()); } @@ -2291,6 +2522,7 @@ public: static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); /// predicates to categorize the respective opcodes. + bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } bool isMultiplicativeOp() const { return Opc >= BO_Mul && Opc <= BO_Rem; } static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; } bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); } @@ -2312,13 +2544,24 @@ public: static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; } bool isLogicalOp() const { return isLogicalOp(getOpcode()); } - bool isAssignmentOp() const { return Opc >= BO_Assign && Opc <= BO_OrAssign; } - bool isCompoundAssignmentOp() const { + static bool isAssignmentOp(Opcode Opc) { + return Opc >= BO_Assign && Opc <= BO_OrAssign; + } + bool isAssignmentOp() const { return isAssignmentOp(getOpcode()); } + + static bool isCompoundAssignmentOp(Opcode Opc) { return Opc > BO_Assign && Opc <= BO_OrAssign; } - bool isShiftAssignOp() const { + bool isCompoundAssignmentOp() const { + return isCompoundAssignmentOp(getOpcode()); + } + + static bool isShiftAssignOp(Opcode Opc) { return Opc == BO_ShlAssign || Opc == BO_ShrAssign; } + bool isShiftAssignOp() const { + return isShiftAssignOp(getOpcode()); + } static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && @@ -2327,15 +2570,19 @@ public: static bool classof(const BinaryOperator *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } protected: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, bool dead) - : Expr(CompoundAssignOperatorClass, ResTy, + : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), - lhs->isValueDependent() || rhs->isValueDependent()), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), Opc(opc), OpLoc(opLoc) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; @@ -2355,11 +2602,11 @@ class CompoundAssignOperator : public BinaryOperator { QualType ComputationLHSType; QualType ComputationResultType; public: - CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, - QualType ResType, QualType CompLHSType, - QualType CompResultType, + CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, + ExprValueKind VK, ExprObjectKind OK, + QualType CompLHSType, QualType CompResultType, SourceLocation OpLoc) - : BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true), + : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { assert(isCompoundAssignmentOp() && @@ -2385,75 +2632,97 @@ public: } }; -/// ConditionalOperator - The ?: operator. Note that LHS may be null when the -/// GNU "missing LHS" extension is in use. -/// -class ConditionalOperator : public Expr { +/// AbstractConditionalOperator - An abstract base class for +/// ConditionalOperator and BinaryConditionalOperator. +class AbstractConditionalOperator : public Expr { + SourceLocation QuestionLoc, ColonLoc; + friend class ASTStmtReader; + +protected: + AbstractConditionalOperator(StmtClass SC, QualType T, + ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, + bool ContainsUnexpandedParameterPack, + SourceLocation qloc, + SourceLocation cloc) + : Expr(SC, T, VK, OK, TD, VD, ContainsUnexpandedParameterPack), + QuestionLoc(qloc), ColonLoc(cloc) {} + + AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty) { } + +public: + // getCond - Return the expression representing the condition for + // the ?: operator. + Expr *getCond() const; + + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const; + + // getFalseExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to false. This is + // the same as getRHS. + Expr *getFalseExpr() const; + + SourceLocation getQuestionLoc() const { return QuestionLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass || + T->getStmtClass() == BinaryConditionalOperatorClass; + } + static bool classof(const AbstractConditionalOperator *) { return true; } +}; + +/// ConditionalOperator - The ?: ternary operator. The GNU "missing +/// middle" extension is a BinaryConditionalOperator. +class ConditionalOperator : public AbstractConditionalOperator { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. - Stmt* Save; - SourceLocation QuestionLoc, ColonLoc; + + friend class ASTStmtReader; public: ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, - SourceLocation CLoc, Expr *rhs, Expr *save, QualType t) - : Expr(ConditionalOperatorClass, t, + SourceLocation CLoc, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK, // 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() || - (lhs && lhs->isValueDependent()) || - (rhs && rhs->isValueDependent()))), - QuestionLoc(QLoc), - ColonLoc(CLoc) { + (lhs->isTypeDependent() || rhs->isTypeDependent()), + (cond->isValueDependent() || lhs->isValueDependent() || + rhs->isValueDependent()), + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + QLoc, CLoc) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - Save = save; } /// \brief Build an empty conditional operator. explicit ConditionalOperator(EmptyShell Empty) - : Expr(ConditionalOperatorClass, Empty) { } + : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } // getCond - Return the expression representing the condition for - // the ?: operator. + // the ?: operator. Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } - void setCond(Expr *E) { SubExprs[COND] = E; } - // getTrueExpr - Return the subexpression representing the value of the ?: - // expression if the condition evaluates to true. - Expr *getTrueExpr() const { - return cast<Expr>(!Save ? SubExprs[LHS] : SubExprs[COND]); - } + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); } - // getFalseExpr - Return the subexpression representing the value of the ?: - // expression if the condition evaluates to false. This is the same as getRHS. + // getFalseExpr - 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]); } - // getSaveExpr - In most cases this value will be null. Except a GCC extension - // allows the left subexpression to be omitted, and instead of that condition - // be returned. e.g: x ?: y is shorthand for x ? x : y, except that the - // expression "x" is only evaluated once. Under this senario, this function - // returns the original, non-converted condition expression for the ?:operator - Expr *getSaveExpr() const { return Save? cast<Expr>(Save) : (Expr*)0; } - - Expr *getLHS() const { return Save ? 0 : cast<Expr>(SubExprs[LHS]); } - void setLHS(Expr *E) { SubExprs[LHS] = E; } - + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } - void setRHS(Expr *E) { SubExprs[RHS] = E; } - - Expr *getSAVE() const { return Save? cast<Expr>(Save) : (Expr*)0; } - void setSAVE(Expr *E) { Save = 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 { + SourceRange getSourceRange() const { return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd()); } static bool classof(const Stmt *T) { @@ -2462,18 +2731,118 @@ public: static bool classof(const ConditionalOperator *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// BinaryConditionalOperator - The GNU extension to the conditional +/// operator which allows the middle operand to be omitted. +/// +/// This is a different expression kind on the assumption that almost +/// every client ends up needing to know that these are different. +class BinaryConditionalOperator : public AbstractConditionalOperator { + enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS }; + + /// - the common condition/left-hand-side expression, which will be + /// evaluated as the opaque value + /// - the condition, expressed in terms of the opaque value + /// - the left-hand-side, expressed in terms of the opaque value + /// - the right-hand-side + Stmt *SubExprs[NUM_SUBEXPRS]; + OpaqueValueExpr *OpaqueValue; + + friend class ASTStmtReader; +public: + BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue, + Expr *cond, Expr *lhs, Expr *rhs, + SourceLocation qloc, SourceLocation cloc, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, + (common->isTypeDependent() || rhs->isTypeDependent()), + (common->isValueDependent() || rhs->isValueDependent()), + (common->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + qloc, cloc), + OpaqueValue(opaqueValue) { + SubExprs[COMMON] = common; + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + + OpaqueValue->setSourceExpr(common); + } + + /// \brief Build an empty conditional operator. + explicit BinaryConditionalOperator(EmptyShell Empty) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { } + + /// \brief getCommon - Return the common expression, written to the + /// left of the condition. The opaque value will be bound to the + /// result of this expression. + Expr *getCommon() const { return cast<Expr>(SubExprs[COMMON]); } + + /// \brief getOpaqueValue - Return the opaque value placeholder. + OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } + + /// \brief getCond - Return the condition expression; this is defined + /// in terms of the opaque value. + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + + /// \brief getTrueExpr - Return the subexpression which will be + /// evaluated if the condition evaluates to true; this is defined + /// in terms of the opaque value. + Expr *getTrueExpr() const { + return cast<Expr>(SubExprs[LHS]); + } + + /// \brief getFalseExpr - Return the subexpression which will be + /// evaluated if the condnition evaluates to false; this is + /// defined in terms of the opaque value. + Expr *getFalseExpr() const { + return cast<Expr>(SubExprs[RHS]); + } + + SourceRange getSourceRange() const { + return SourceRange(getCommon()->getLocStart(), getFalseExpr()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == BinaryConditionalOperatorClass; + } + static bool classof(const BinaryConditionalOperator *) { return true; } + + // Iterators + child_range children() { + return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); + } }; +inline Expr *AbstractConditionalOperator::getCond() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getCond(); + return cast<BinaryConditionalOperator>(this)->getCond(); +} + +inline Expr *AbstractConditionalOperator::getTrueExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getTrueExpr(); + return cast<BinaryConditionalOperator>(this)->getTrueExpr(); +} + +inline Expr *AbstractConditionalOperator::getFalseExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getFalseExpr(); + return cast<BinaryConditionalOperator>(this)->getFalseExpr(); +} + /// AddrLabelExpr - The GNU address of label extension, representing &&label. class AddrLabelExpr : public Expr { SourceLocation AmpAmpLoc, LabelLoc; - LabelStmt *Label; + LabelDecl *Label; public: - AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L, + AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, QualType t) - : Expr(AddrLabelExprClass, t, false, false), + : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} /// \brief Build an empty address of a label expression. @@ -2485,12 +2854,12 @@ public: SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AmpAmpLoc, LabelLoc); } - LabelStmt *getLabel() const { return Label; } - void setLabel(LabelStmt *S) { Label = S; } + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *L) { Label = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == AddrLabelExprClass; @@ -2498,13 +2867,15 @@ public: static bool classof(const AddrLabelExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). /// The StmtExpr contains a single CompoundStmt node, which it evaluates and /// takes the value of the last subexpression. +/// +/// A StmtExpr is always an r-value; values "returned" out of a +/// StmtExpr will be copied. class StmtExpr : public Expr { Stmt *SubStmt; SourceLocation LParenLoc, RParenLoc; @@ -2512,7 +2883,8 @@ public: // FIXME: Does type-dependence need to be computed differently? StmtExpr(CompoundStmt *substmt, QualType T, SourceLocation lp, SourceLocation rp) : - Expr(StmtExprClass, T, T->isDependentType(), false), + Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, + T->isDependentType(), false, false), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } /// \brief Build an empty statement expression. @@ -2522,7 +2894,7 @@ public: const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); } void setSubStmt(CompoundStmt *S) { SubStmt = S; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(LParenLoc, RParenLoc); } @@ -2537,55 +2909,9 @@ public: static bool classof(const StmtExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&SubStmt, &SubStmt+1); } }; -/// TypesCompatibleExpr - GNU builtin-in function __builtin_types_compatible_p. -/// This AST node represents a function that returns 1 if two *types* (not -/// expressions) are compatible. The result of this built-in function can be -/// used in integer constant expressions. -class TypesCompatibleExpr : public Expr { - TypeSourceInfo *TInfo1; - TypeSourceInfo *TInfo2; - SourceLocation BuiltinLoc, RParenLoc; -public: - TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc, - TypeSourceInfo *tinfo1, TypeSourceInfo *tinfo2, - SourceLocation RP) : - Expr(TypesCompatibleExprClass, ReturnType, false, false), - TInfo1(tinfo1), TInfo2(tinfo2), BuiltinLoc(BLoc), RParenLoc(RP) {} - - /// \brief Build an empty __builtin_type_compatible_p expression. - explicit TypesCompatibleExpr(EmptyShell Empty) - : Expr(TypesCompatibleExprClass, Empty) { } - - TypeSourceInfo *getArgTInfo1() const { return TInfo1; } - void setArgTInfo1(TypeSourceInfo *TInfo) { TInfo1 = TInfo; } - TypeSourceInfo *getArgTInfo2() const { return TInfo2; } - void setArgTInfo2(TypeSourceInfo *TInfo) { TInfo2 = TInfo; } - - QualType getArgType1() const { return TInfo1->getType(); } - QualType getArgType2() const { return TInfo2->getType(); } - - 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; - } - static bool classof(const TypesCompatibleExpr *) { return true; } - - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; /// ShuffleVectorExpr - clang-specific builtin-in function /// __builtin_shufflevector. @@ -2604,18 +2930,9 @@ class ShuffleVectorExpr : public Expr { unsigned NumExprs; public: - // FIXME: Can a shufflevector be value-dependent? Does type-dependence need - // to be computed differently? ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, QualType Type, SourceLocation BLoc, - SourceLocation RP) : - Expr(ShuffleVectorExprClass, Type, Type->isDependentType(), false), - BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) { - - SubExprs = new (C) Stmt*[nexpr]; - for (unsigned i = 0; i < nexpr; i++) - SubExprs[i] = args[i]; - } + SourceLocation RP); /// \brief Build an empty vector-shuffle expression. explicit ShuffleVectorExpr(EmptyShell Empty) @@ -2627,7 +2944,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -2640,6 +2957,9 @@ public: /// pointers. unsigned getNumSubExprs() const { return NumExprs; } + /// \brief Retrieve the array of expressions. + Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } + /// getExpr - Return the Expr at the specified index. Expr *getExpr(unsigned Index) { assert((Index < NumExprs) && "Arg access out of range!"); @@ -2658,8 +2978,9 @@ public: } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); + } }; /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. @@ -2676,9 +2997,13 @@ class ChooseExpr : public Expr { Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. SourceLocation BuiltinLoc, RParenLoc; public: - ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t, + ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation RP, bool TypeDependent, bool ValueDependent) - : Expr(ChooseExprClass, t, TypeDependent, ValueDependent), + : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), BuiltinLoc(BLoc), RParenLoc(RP) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; @@ -2690,11 +3015,11 @@ public: /// isConditionTrue - Return whether the condition is true (i.e. not /// equal to zero). - bool isConditionTrue(ASTContext &C) const; + bool isConditionTrue(const ASTContext &C) const; /// getChosenSubExpr - Return the subexpression chosen according to the /// condition. - Expr *getChosenSubExpr(ASTContext &C) const { + Expr *getChosenSubExpr(const ASTContext &C) const { return isConditionTrue(C) ? getLHS() : getRHS(); } @@ -2711,7 +3036,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -2720,8 +3045,9 @@ public: static bool classof(const ChooseExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } }; /// GNUNullExpr - Implements the GNU __null extension, which is a name @@ -2736,7 +3062,8 @@ class GNUNullExpr : public Expr { public: GNUNullExpr(QualType Ty, SourceLocation Loc) - : Expr(GNUNullExprClass, Ty, false, false), TokenLoc(Loc) { } + : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false), + TokenLoc(Loc) { } /// \brief Build an empty GNU __null expression. explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } @@ -2745,7 +3072,7 @@ public: SourceLocation getTokenLocation() const { return TokenLoc; } void setTokenLocation(SourceLocation L) { TokenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(TokenLoc); } static bool classof(const Stmt *T) { @@ -2754,8 +3081,7 @@ public: static bool classof(const GNUNullExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// VAArgExpr, used for the builtin function __builtin_va_arg. @@ -2766,7 +3092,10 @@ class VAArgExpr : public Expr { public: VAArgExpr(SourceLocation BLoc, Expr* e, TypeSourceInfo *TInfo, SourceLocation RPLoc, QualType t) - : Expr(VAArgExprClass, t, t->isDependentType(), false), + : Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, + t->isDependentType(), false, + (TInfo->getType()->containsUnexpandedParameterPack() || + e->containsUnexpandedParameterPack())), Val(e), TInfo(TInfo), BuiltinLoc(BLoc), RParenLoc(RPLoc) { } @@ -2787,7 +3116,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -2796,8 +3125,7 @@ public: static bool classof(const VAArgExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Val, &Val+1); } }; /// @brief Describes an C or C++ initializer list. @@ -2866,12 +3194,15 @@ public: unsigned getNumInits() const { return InitExprs.size(); } - const Expr* getInit(unsigned Init) const { + /// \brief Retrieve the set of initializers. + Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); } + + 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]); } @@ -2933,17 +3264,18 @@ public: HadArrayRangeDesignator = ARD; } - virtual SourceRange getSourceRange() const { - return SourceRange(LBraceLoc, RBraceLoc); - } + SourceRange getSourceRange() const; + static bool classof(const Stmt *T) { return T->getStmtClass() == InitListExprClass; } static bool classof(const InitListExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + if (InitExprs.empty()) return child_range(); + return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); + } typedef InitExprsTy::iterator iterator; typedef InitExprsTy::const_iterator const_iterator; @@ -3182,6 +3514,15 @@ public: return Designators + NumDesignators; } + typedef std::reverse_iterator<designators_iterator> + reverse_designators_iterator; + reverse_designators_iterator designators_rbegin() { + return reverse_designators_iterator(designators_end()); + } + reverse_designators_iterator designators_rend() { + return reverse_designators_iterator(designators_begin()); + } + Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } void setDesignators(ASTContext &C, const Designator *Desigs, @@ -3235,7 +3576,7 @@ public: void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last); - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitExprClass; @@ -3243,8 +3584,10 @@ public: static bool classof(const DesignatedInitExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + Stmt **begin = reinterpret_cast<Stmt**>(this + 1); + return child_range(begin, begin + NumSubExprs); + } }; /// \brief Represents an implicitly-generated value initialization of @@ -3258,7 +3601,8 @@ public: class ImplicitValueInitExpr : public Expr { public: explicit ImplicitValueInitExpr(QualType ty) - : Expr(ImplicitValueInitExprClass, ty, false, false) { } + : Expr(ImplicitValueInitExprClass, ty, VK_RValue, OK_Ordinary, + false, false, false) { } /// \brief Construct an empty implicit value initialization. explicit ImplicitValueInitExpr(EmptyShell Empty) @@ -3269,13 +3613,12 @@ public: } static bool classof(const ImplicitValueInitExpr *) { return true; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(); } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; @@ -3308,7 +3651,7 @@ public: SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(LParenLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -3317,8 +3660,9 @@ public: static bool classof(const ParenListExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&Exprs[0], &Exprs[0]+NumExprs); + } friend class ASTStmtReader; friend class ASTStmtWriter; @@ -3342,10 +3686,12 @@ class ExtVectorElementExpr : public Expr { IdentifierInfo *Accessor; SourceLocation AccessorLoc; public: - ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor, - SourceLocation loc) - : Expr(ExtVectorElementExprClass, ty, base->isTypeDependent(), - base->isValueDependent()), + ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, + IdentifierInfo &accessor, SourceLocation loc) + : Expr(ExtVectorElementExprClass, ty, VK, + (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), + base->isTypeDependent(), base->isValueDependent(), + base->containsUnexpandedParameterPack()), Base(base), Accessor(&accessor), AccessorLoc(loc) {} /// \brief Build an empty vector element expression. @@ -3373,7 +3719,7 @@ public: /// aggregate Constant of ConstantInt(s). void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const; - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), AccessorLoc); } @@ -3387,8 +3733,7 @@ public: static bool classof(const ExtVectorElementExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Base, &Base+1); } }; @@ -3397,11 +3742,11 @@ public: class BlockExpr : public Expr { protected: BlockDecl *TheBlock; - bool HasBlockDeclRefExprs; public: - BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs) - : Expr(BlockExprClass, ty, ty->isDependentType(), false), - TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {} + BlockExpr(BlockDecl *BD, QualType ty) + : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, + ty->isDependentType(), false, false), + TheBlock(BD) {} /// \brief Build an empty block expression. explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } @@ -3415,58 +3760,46 @@ public: const Stmt *getBody() const; Stmt *getBody(); - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getCaretLocation(), getBody()->getLocEnd()); } /// getFunctionType - Return the underlying function type for this block. const FunctionType *getFunctionType() const; - /// hasBlockDeclRefExprs - Return true iff the block has BlockDeclRefExpr - /// inside of the block that reference values outside the block. - bool hasBlockDeclRefExprs() const { return HasBlockDeclRefExprs; } - void setHasBlockDeclRefExprs(bool BDRE) { HasBlockDeclRefExprs = BDRE; } - 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(); + child_range children() { return child_range(); } }; -/// BlockDeclRefExpr - A reference to a declared variable, function, -/// enum, etc. +/// BlockDeclRefExpr - A reference to a local variable declared in an +/// enclosing scope. class BlockDeclRefExpr : public Expr { - ValueDecl *D; + VarDecl *D; SourceLocation Loc; bool IsByRef : 1; bool ConstQualAdded : 1; - Stmt *CopyConstructorVal; public: - // FIXME: Fix type/value dependence! - BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef, - bool constAdded = false, - Stmt *copyConstructorVal = 0) - : Expr(BlockDeclRefExprClass, t, (!t.isNull() && t->isDependentType()),false), - D(d), Loc(l), IsByRef(ByRef), - ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal) {} + BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, + SourceLocation l, bool ByRef, bool constAdded = false); // \brief Build an empty reference to a declared variable in a // block. explicit BlockDeclRefExpr(EmptyShell Empty) : Expr(BlockDeclRefExprClass, Empty) { } - ValueDecl *getDecl() { return D; } - const ValueDecl *getDecl() const { return D; } - void setDecl(ValueDecl *VD) { D = VD; } + VarDecl *getDecl() { return D; } + const VarDecl *getDecl() const { return D; } + void setDecl(VarDecl *VD) { D = VD; } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } bool isByRef() const { return IsByRef; } void setByRef(bool BR) { IsByRef = BR; } @@ -3474,20 +3807,13 @@ public: bool isConstQualAdded() const { return ConstQualAdded; } void setConstQualAdded(bool C) { ConstQualAdded = C; } - const Expr *getCopyConstructorExpr() const - { return cast_or_null<Expr>(CopyConstructorVal); } - Expr *getCopyConstructorExpr() - { return cast_or_null<Expr>(CopyConstructorVal); } - void setCopyConstructorExpr(Expr *E) { CopyConstructorVal = E; } - 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(); + child_range children() { return child_range(); } }; } // end namespace clang diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 0a9435479d93..85ce9621d928 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -21,11 +21,11 @@ namespace clang { - class CXXConstructorDecl; - class CXXDestructorDecl; - class CXXMethodDecl; - class CXXTemporary; - class TemplateArgumentListInfo; +class CXXConstructorDecl; +class CXXDestructorDecl; +class CXXMethodDecl; +class CXXTemporary; +class TemplateArgumentListInfo; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -51,8 +51,9 @@ class CXXOperatorCallExpr : public CallExpr { public: CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, Expr **args, unsigned numargs, QualType t, - SourceLocation operatorloc) - : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc), + ExprValueKind VK, SourceLocation operatorloc) + : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, numargs, t, VK, + operatorloc), Operator(Op) {} explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : CallExpr(C, CXXOperatorCallExprClass, Empty) { } @@ -70,7 +71,7 @@ public: /// bracket. SourceLocation getOperatorLoc() const { return getRParenLoc(); } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXOperatorCallExprClass; @@ -89,8 +90,8 @@ public: class CXXMemberCallExpr : public CallExpr { public: CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs, - QualType t, SourceLocation rparenloc) - : CallExpr(C, CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) {} + QualType t, ExprValueKind VK, SourceLocation RP) + : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, numargs, t, VK, RP) {} CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) : CallExpr(C, CXXMemberCallExprClass, Empty) { } @@ -100,7 +101,14 @@ public: /// operation would return "x". Expr *getImplicitObjectArgument(); - virtual SourceRange getSourceRange() const; + /// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of + /// the implicit object argument. Note that this is may not be the same + /// declaration as that of the class context of the CXXMethodDecl which this + /// function is calling. + /// FIXME: Returns 0 for member pointer call exprs. + CXXRecordDecl *getRecordDecl(); + + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXMemberCallExprClass; @@ -108,6 +116,35 @@ public: static bool classof(const CXXMemberCallExpr *) { return true; } }; +/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function. +class CUDAKernelCallExpr : public CallExpr { +private: + enum { CONFIG, END_PREARG }; + +public: + CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config, + Expr **args, unsigned numargs, QualType t, + ExprValueKind VK, SourceLocation RP) + : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, numargs, t, VK, + RP) { + setConfig(Config); + } + + CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { } + + const CallExpr *getConfig() const { + return cast_or_null<CallExpr>(getPreArg(CONFIG)); + } + CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); } + void setConfig(CallExpr *E) { setPreArg(CONFIG, E); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CUDAKernelCallExprClass; + } + static bool classof(const CUDAKernelCallExpr *) { return true; } +}; + /// CXXNamedCastExpr - Abstract class common to all of the C++ "named" /// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c /// const_cast. @@ -118,26 +155,33 @@ public: class CXXNamedCastExpr : public ExplicitCastExpr { private: SourceLocation Loc; // the location of the casting op - + SourceLocation RParenLoc; // the location of the right parenthesis + protected: - CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op, - unsigned PathSize, TypeSourceInfo *writtenTy, - SourceLocation l) - : ExplicitCastExpr(SC, ty, kind, op, PathSize, writtenTy), Loc(l) {} + CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l), + RParenLoc(RParenLoc) {} explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) : ExplicitCastExpr(SC, Shell, PathSize) { } + friend class ASTStmtReader; + public: const char *getCastName() const; /// \brief Retrieve the location of the cast operator keyword, e.g., /// "static_cast". SourceLocation getOperatorLoc() const { return Loc; } - void setOperatorLoc(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { - return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd()); + /// \brief Retrieve the location of the closing parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const { + return SourceRange(Loc, RParenLoc); } static bool classof(const Stmt *T) { switch (T->getStmtClass()) { @@ -158,20 +202,21 @@ public: /// This expression node represents a C++ static cast, e.g., /// @c static_cast<int>(1.0). class CXXStaticCastExpr : public CXXNamedCastExpr { - CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op, + CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, - SourceLocation l) - : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, pathSize, - writtenTy, l) {} + SourceLocation l, SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize, + writtenTy, l, RParenLoc) {} explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize) : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { } public: static CXXStaticCastExpr *Create(ASTContext &Context, QualType T, - CastKind K, Expr *Op, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *Path, - TypeSourceInfo *Written, SourceLocation L); + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc); static CXXStaticCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); @@ -188,20 +233,21 @@ public: /// This expression node represents a dynamic cast, e.g., /// @c dynamic_cast<Derived*>(BasePtr). class CXXDynamicCastExpr : public CXXNamedCastExpr { - CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, - unsigned pathSize, TypeSourceInfo *writtenTy, - SourceLocation l) - : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, pathSize, - writtenTy, l) {} + CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind, + Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize, + writtenTy, l, RParenLoc) {} explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize) : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { } public: static CXXDynamicCastExpr *Create(ASTContext &Context, QualType T, - CastKind Kind, Expr *Op, + ExprValueKind VK, CastKind Kind, Expr *Op, const CXXCastPath *Path, - TypeSourceInfo *Written, SourceLocation L); + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc); static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context, unsigned pathSize); @@ -219,20 +265,22 @@ public: /// This expression node represents a reinterpret cast, e.g., /// @c reinterpret_cast<int>(VoidPtr). class CXXReinterpretCastExpr : public CXXNamedCastExpr { - CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op, - unsigned pathSize, - TypeSourceInfo *writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, pathSize, - writtenTy, l) {} + CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind, + Expr *op, unsigned pathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op, + pathSize, writtenTy, l, RParenLoc) {} CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize) : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { } public: static CXXReinterpretCastExpr *Create(ASTContext &Context, QualType T, - CastKind Kind, Expr *Op, - const CXXCastPath *Path, - TypeSourceInfo *WrittenTy, SourceLocation L); + ExprValueKind VK, CastKind Kind, + Expr *Op, const CXXCastPath *Path, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc); static CXXReinterpretCastExpr *CreateEmpty(ASTContext &Context, unsigned pathSize); @@ -248,17 +296,20 @@ public: /// This expression node represents a const cast, e.g., /// @c const_cast<char*>(PtrToConstChar). class CXXConstCastExpr : public CXXNamedCastExpr { - CXXConstCastExpr(QualType ty, Expr *op, TypeSourceInfo *writtenTy, - SourceLocation l) - : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, - 0, writtenTy, l) {} + CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, + 0, writtenTy, l, RParenLoc) {} explicit CXXConstCastExpr(EmptyShell Empty) : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { } public: - static CXXConstCastExpr *Create(ASTContext &Context, QualType T, Expr *Op, - TypeSourceInfo *WrittenTy, SourceLocation L); + static CXXConstCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, Expr *Op, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc); static CXXConstCastExpr *CreateEmpty(ASTContext &Context); static bool classof(const Stmt *T) { @@ -274,7 +325,9 @@ class CXXBoolLiteralExpr : public Expr { SourceLocation Loc; public: CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : - Expr(CXXBoolLiteralExprClass, Ty, false, false), Value(val), Loc(l) {} + Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false), + Value(val), Loc(l) {} explicit CXXBoolLiteralExpr(EmptyShell Empty) : Expr(CXXBoolLiteralExprClass, Empty) { } @@ -282,7 +335,7 @@ public: bool getValue() const { return Value; } void setValue(bool V) { Value = V; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -293,8 +346,7 @@ public: static bool classof(const CXXBoolLiteralExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal @@ -302,12 +354,14 @@ class CXXNullPtrLiteralExpr : public Expr { SourceLocation Loc; public: CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : - Expr(CXXNullPtrLiteralExprClass, Ty, false, false), Loc(l) {} + Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false), + Loc(l) {} explicit CXXNullPtrLiteralExpr(EmptyShell Empty) : Expr(CXXNullPtrLiteralExprClass, Empty) { } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -317,8 +371,7 @@ public: } static bool classof(const CXXNullPtrLiteralExpr *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets @@ -333,19 +386,21 @@ private: public: CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) - : Expr(CXXTypeidExprClass, Ty, + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, // typeid is never type-dependent (C++ [temp.dep.expr]p4) false, // typeid is value-dependent if the type or expression are dependent - Operand->getType()->isDependentType()), + Operand->getType()->isDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R) - : Expr(CXXTypeidExprClass, Ty, + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, // typeid is never type-dependent (C++ [temp.dep.expr]p4) - false, + false, // typeid is value-dependent if the type or expression are dependent - Operand->isTypeDependent() || Operand->isValueDependent()), + Operand->isTypeDependent() || Operand->isValueDependent(), + Operand->containsUnexpandedParameterPack()), Operand(Operand), Range(R) { } CXXTypeidExpr(EmptyShell Empty, bool isExpr) @@ -383,7 +438,7 @@ public: Operand = E; } - virtual SourceRange getSourceRange() const { return Range; } + SourceRange getSourceRange() const { return Range; } void setSourceRange(SourceRange R) { Range = R; } static bool classof(const Stmt *T) { @@ -392,8 +447,84 @@ public: static bool classof(const CXXTypeidExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + if (isTypeOperand()) return child_range(); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } +}; + +/// CXXUuidofExpr - A microsoft C++ @c __uuidof expression, which gets +/// the _GUID that corresponds to the supplied type or expression. +/// +/// This represents code like @c __uuidof(COMTYPE) or @c __uuidof(*comPtr) +class CXXUuidofExpr : public Expr { +private: + llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand; + SourceRange Range; + +public: + CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->getType()->isDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->isTypeDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXUuidofExprClass, Empty) { + if (isExpr) + Operand = (Expr*)0; + else + Operand = (TypeSourceInfo*)0; + } + + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } + + /// \brief Retrieves the type operand of this __uuidof() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand() const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get<TypeSourceInfo *>(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + return static_cast<Expr*>(Operand.get<Stmt *>()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + Operand = E; + } + + SourceRange getSourceRange() const { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUuidofExprClass; + } + static bool classof(const CXXUuidofExpr *) { return true; } + + // Iterators + child_range children() { + if (isTypeOperand()) return child_range(); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } }; /// CXXThisExpr - Represents the "this" expression in C++, which is a @@ -413,10 +544,11 @@ class CXXThisExpr : public Expr { public: CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit) - : Expr(CXXThisExprClass, Type, + : Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary, // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) - Type->isDependentType(), Type->isDependentType()), + Type->isDependentType(), Type->isDependentType(), + /*ContainsUnexpandedParameterPack=*/false), Loc(L), Implicit(isImplicit) { } CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} @@ -424,7 +556,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceRange getSourceRange() const { return SourceRange(Loc); } bool isImplicit() const { return Implicit; } void setImplicit(bool I) { Implicit = I; } @@ -435,8 +567,7 @@ public: static bool classof(const CXXThisExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles @@ -451,7 +582,9 @@ public: // exepression. The l is the location of the throw keyword. expr // can by null, if the optional expression to throw isn't present. CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) : - Expr(CXXThrowExprClass, Ty, false, false), Op(expr), ThrowLoc(l) {} + Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + expr && expr->containsUnexpandedParameterPack()), + Op(expr), ThrowLoc(l) {} CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } @@ -461,7 +594,7 @@ public: SourceLocation getThrowLoc() const { return ThrowLoc; } void setThrowLoc(SourceLocation L) { ThrowLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { if (getSubExpr() == 0) return SourceRange(ThrowLoc, ThrowLoc); return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd()); @@ -473,8 +606,9 @@ public: static bool classof(const CXXThrowExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&Op, Op ? &Op+1 : &Op); + } }; /// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a @@ -497,12 +631,16 @@ class CXXDefaultArgExpr : public Expr { param->hasUnparsedDefaultArg() ? param->getType().getNonReferenceType() : param->getDefaultArg()->getType(), - false, false), + param->getDefaultArg()->getValueKind(), + param->getDefaultArg()->getObjectKind(), false, false, false), Param(param, false), Loc(Loc) { } CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param, Expr *SubExpr) - : Expr(SC, SubExpr->getType(), false, false), Param(param, true), Loc(Loc) { + : Expr(SC, SubExpr->getType(), + SubExpr->getValueKind(), SubExpr->getObjectKind(), + false, false, false), + Param(param, true), Loc(Loc) { *reinterpret_cast<Expr **>(this + 1) = SubExpr; } @@ -544,7 +682,7 @@ public: /// used. SourceLocation getUsedLocation() const { return Loc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { // Default argument expressions have no representation in the // source, so they have an empty source range. return SourceRange(); @@ -556,8 +694,7 @@ public: static bool classof(const CXXDefaultArgExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } friend class ASTStmtReader; friend class ASTStmtWriter; @@ -597,9 +734,12 @@ class CXXBindTemporaryExpr : public Expr { Stmt *SubExpr; - CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr) - : Expr(CXXBindTemporaryExprClass, subexpr->getType(), false, false), - Temp(temp), SubExpr(subexpr) { } + CXXBindTemporaryExpr(CXXTemporary *temp, Expr* SubExpr) + : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), + VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), + SubExpr->isValueDependent(), + SubExpr->containsUnexpandedParameterPack()), + Temp(temp), SubExpr(SubExpr) { } public: CXXBindTemporaryExpr(EmptyShell Empty) @@ -616,7 +756,7 @@ public: Expr *getSubExpr() { return cast<Expr>(SubExpr); } void setSubExpr(Expr *E) { SubExpr = E; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SubExpr->getSourceRange(); } @@ -627,8 +767,7 @@ public: static bool classof(const CXXBindTemporaryExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } }; /// CXXConstructExpr - Represents a call to a C++ constructor. @@ -644,6 +783,7 @@ private: CXXConstructorDecl *Constructor; SourceLocation Loc; + SourceRange ParenRange; bool Elidable : 1; bool ZeroInitialization : 1; unsigned ConstructKind : 2; @@ -656,7 +796,8 @@ protected: CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs, bool ZeroInitialization = false, - ConstructionKind ConstructKind = CK_Complete); + ConstructionKind ConstructKind = CK_Complete, + SourceRange ParenRange = SourceRange()); /// \brief Construct an empty C++ construction expression. CXXConstructExpr(StmtClass SC, EmptyShell Empty) @@ -675,7 +816,8 @@ public: CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization = false, - ConstructionKind ConstructKind = CK_Complete); + ConstructionKind ConstructKind = CK_Complete, + SourceRange ParenRange = SourceRange()); CXXConstructorDecl* getConstructor() const { return Constructor; } @@ -731,7 +873,8 @@ public: Args[Arg] = ArgExpr; } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; + SourceRange getParenRange() const { return ParenRange; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstructExprClass || @@ -740,8 +883,9 @@ public: static bool classof(const CXXConstructExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&Args[0], &Args[0]+NumArgs); + } friend class ASTStmtReader; }; @@ -753,12 +897,13 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr { SourceLocation TyBeginLoc; SourceLocation RParenLoc; - CXXFunctionalCastExpr(QualType ty, TypeSourceInfo *writtenTy, + CXXFunctionalCastExpr(QualType ty, ExprValueKind VK, + TypeSourceInfo *writtenTy, SourceLocation tyBeginLoc, CastKind kind, Expr *castExpr, unsigned pathSize, SourceLocation rParenLoc) - : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr, - pathSize, writtenTy), + : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind, + castExpr, pathSize, writtenTy), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize) @@ -766,6 +911,7 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr { public: static CXXFunctionalCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, TypeSourceInfo *Written, SourceLocation TyBeginLoc, CastKind Kind, Expr *Op, @@ -779,7 +925,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -804,24 +950,21 @@ public: /// }; /// @endcode class CXXTemporaryObjectExpr : public CXXConstructExpr { - SourceLocation TyBeginLoc; - SourceLocation RParenLoc; + TypeSourceInfo *Type; public: CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, - QualType writtenTy, SourceLocation tyBeginLoc, + TypeSourceInfo *Type, Expr **Args,unsigned NumArgs, - SourceLocation rParenLoc, + SourceRange parenRange, bool ZeroInitialization = false); explicit CXXTemporaryObjectExpr(EmptyShell Empty) - : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty) { } + : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { } - SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } - SourceLocation getRParenLoc() const { return RParenLoc; } + TypeSourceInfo *getTypeSourceInfo() const { return Type; } - virtual SourceRange getSourceRange() const { - return SourceRange(TyBeginLoc, RParenLoc); - } + SourceRange getSourceRange() const; + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXTemporaryObjectExprClass; } @@ -835,32 +978,31 @@ public: /// T, which is a non-class type. /// class CXXScalarValueInitExpr : public Expr { - SourceLocation TyBeginLoc; SourceLocation RParenLoc; + TypeSourceInfo *TypeInfo; + friend class ASTStmtReader; + public: - CXXScalarValueInitExpr(QualType ty, SourceLocation tyBeginLoc, - SourceLocation rParenLoc ) : - Expr(CXXScalarValueInitExprClass, ty, false, false), - TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + /// \brief Create an explicitly-written scalar-value initialization + /// expression. + CXXScalarValueInitExpr(QualType Type, + TypeSourceInfo *TypeInfo, + SourceLocation rParenLoc ) : + Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, + false, false, false), + RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} + explicit CXXScalarValueInitExpr(EmptyShell Shell) : Expr(CXXScalarValueInitExprClass, Shell) { } - SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } - SourceLocation getRParenLoc() const { return RParenLoc; } - - void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } - void setRParenLoc(SourceLocation L) { RParenLoc = L; } - - /// @brief Whether this initialization expression was - /// implicitly-generated. - bool isImplicit() const { - return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); + TypeSourceInfo *getTypeSourceInfo() const { + return TypeInfo; } + + SourceLocation getRParenLoc() const { return RParenLoc; } - virtual SourceRange getSourceRange() const { - return SourceRange(TyBeginLoc, RParenLoc); - } + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXScalarValueInitExprClass; @@ -868,8 +1010,7 @@ public: static bool classof(const CXXScalarValueInitExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// CXXNewExpr - A new expression for memory allocation and constructor calls, @@ -882,8 +1023,11 @@ class CXXNewExpr : public Expr { bool Initializer : 1; // Do we allocate an array? If so, the first SubExpr is the size expression. bool Array : 1; + // If this is an array allocation, does the usual deallocation + // function for the allocated type want to know the allocated size? + bool UsualArrayDeleteWantsSize : 1; // The number of placement new arguments. - unsigned NumPlacementArgs : 15; + unsigned NumPlacementArgs : 14; // The number of constructor arguments. This may be 1 even for non-class // types; use the pseudo copy constructor. unsigned NumConstructorArgs : 14; @@ -900,12 +1044,17 @@ class CXXNewExpr : public Expr { // Must be null for all other types. CXXConstructorDecl *Constructor; + /// \brief The allocated type-source information, as written in the source. + TypeSourceInfo *AllocatedTypeInfo; + /// \brief If the allocated type was expressed as a parenthesized type-id, /// the source range covering the parenthesized type-id. SourceRange TypeIdParens; SourceLocation StartLoc; SourceLocation EndLoc; + SourceLocation ConstructorLParen; + SourceLocation ConstructorRParen; friend class ASTStmtReader; public: @@ -914,8 +1063,11 @@ public: SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, - FunctionDecl *operatorDelete, QualType ty, - SourceLocation startLoc, SourceLocation endLoc); + FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, + QualType ty, TypeSourceInfo *AllocatedTypeInfo, + SourceLocation startLoc, SourceLocation endLoc, + SourceLocation constructorLParen, + SourceLocation constructorRParen); explicit CXXNewExpr(EmptyShell Shell) : Expr(CXXNewExprClass, Shell), SubExprs(0) { } @@ -927,6 +1079,10 @@ public: return getType()->getAs<PointerType>()->getPointeeType(); } + TypeSourceInfo *getAllocatedTypeSourceInfo() const { + return AllocatedTypeInfo; + } + FunctionDecl *getOperatorNew() const { return OperatorNew; } void setOperatorNew(FunctionDecl *D) { OperatorNew = D; } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } @@ -943,6 +1099,10 @@ public: } unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + Expr **getPlacementArgs() { + return reinterpret_cast<Expr **>(SubExprs + Array); + } + Expr *getPlacementArg(unsigned i) { assert(i < NumPlacementArgs && "Index out of range"); return cast<Expr>(SubExprs[Array + i]); @@ -956,11 +1116,21 @@ public: SourceRange getTypeIdParens() const { return TypeIdParens; } bool isGlobalNew() const { return GlobalNew; } - void setGlobalNew(bool V) { GlobalNew = V; } bool hasInitializer() const { return Initializer; } - void setHasInitializer(bool V) { Initializer = V; } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } unsigned getNumConstructorArgs() const { return NumConstructorArgs; } + + Expr **getConstructorArgs() { + return reinterpret_cast<Expr **>(SubExprs + Array + NumPlacementArgs); + } + Expr *getConstructorArg(unsigned i) { assert(i < NumConstructorArgs && "Index out of range"); return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]); @@ -1007,13 +1177,13 @@ public: const_arg_iterator raw_arg_begin() const { return SubExprs; } const_arg_iterator raw_arg_end() const { return constructor_arg_end(); } - SourceLocation getStartLoc() const { return StartLoc; } - void setStartLoc(SourceLocation L) { StartLoc = L; } SourceLocation getEndLoc() const { return EndLoc; } - void setEndLoc(SourceLocation L) { EndLoc = L; } - - virtual SourceRange getSourceRange() const { + + SourceLocation getConstructorLParen() const { return ConstructorLParen; } + SourceLocation getConstructorRParen() const { return ConstructorRParen; } + + SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); } @@ -1023,8 +1193,11 @@ public: static bool classof(const CXXNewExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], + &SubExprs[0] + Array + getNumPlacementArgs() + + getNumConstructorArgs()); + } }; /// CXXDeleteExpr - A delete expression for memory deallocation and destructor @@ -1034,6 +1207,13 @@ class CXXDeleteExpr : public Expr { bool GlobalDelete : 1; // Is this the array form of delete, i.e. "delete[]"? bool ArrayForm : 1; + // ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied + // to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm + // will be true). + bool ArrayFormAsWritten : 1; + // Does the usual deallocation function for the element type require + // a size_t argument? + bool UsualArrayDeleteWantsSize : 1; // Points to the operator delete overload that is used. Could be a member. FunctionDecl *OperatorDelete; // The pointer expression to be deleted. @@ -1042,30 +1222,42 @@ class CXXDeleteExpr : public Expr { SourceLocation Loc; public: CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, + bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) - : Expr(CXXDeleteExprClass, ty, false, false), GlobalDelete(globalDelete), - ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg), - Loc(loc) { } + : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, + arg->containsUnexpandedParameterPack()), + GlobalDelete(globalDelete), + ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), + OperatorDelete(operatorDelete), Argument(arg), Loc(loc) { } explicit CXXDeleteExpr(EmptyShell Shell) : Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { } bool isGlobalDelete() const { return GlobalDelete; } bool isArrayForm() const { return ArrayForm; } - - void setGlobalDelete(bool V) { GlobalDelete = V; } - void setArrayForm(bool V) { ArrayForm = V; } + bool isArrayFormAsWritten() const { return ArrayFormAsWritten; } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. This can be true even if the actual deallocation + /// function that we're using doesn't want a size. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } - void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } Expr *getArgument() { return cast<Expr>(Argument); } const Expr *getArgument() const { return cast<Expr>(Argument); } - void setArgument(Expr *E) { Argument = E; } - virtual SourceRange getSourceRange() const { + /// \brief Retrieve the type being destroyed. If the type being + /// destroyed is a dependent type which may or may not be a pointer, + /// return an invalid type. + QualType getDestroyedType() const; + + SourceRange getSourceRange() const { return SourceRange(Loc, Argument->getLocEnd()); } - void setStartLoc(SourceLocation L) { Loc = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDeleteExprClass; @@ -1073,8 +1265,9 @@ public: static bool classof(const CXXDeleteExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Argument, &Argument+1); } + + friend class ASTStmtReader; }; /// \brief Structure used to store the type being destroyed by a @@ -1171,21 +1364,7 @@ public: TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, SourceLocation TildeLoc, - PseudoDestructorTypeStorage DestroyedType) - : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, - false, 0, false, - false, 0, 0, - FunctionType::ExtInfo())), - /*isTypeDependent=*/(Base->isTypeDependent() || - (DestroyedType.getTypeSourceInfo() && - DestroyedType.getTypeSourceInfo()->getType()->isDependentType())), - /*isValueDependent=*/Base->isValueDependent()), - Base(static_cast<Stmt *>(Base)), IsArrow(isArrow), - OperatorLoc(OperatorLoc), Qualifier(Qualifier), - QualifierRange(QualifierRange), - ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), - DestroyedType(DestroyedType) { } + PseudoDestructorTypeStorage DestroyedType); explicit CXXPseudoDestructorExpr(EmptyShell Shell) : Expr(CXXPseudoDestructorExprClass, Shell), @@ -1278,7 +1457,7 @@ public: DestroyedType = PseudoDestructorTypeStorage(Info); } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXPseudoDestructorExprClass; @@ -1286,8 +1465,7 @@ public: static bool classof(const CXXPseudoDestructorExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Base, &Base + 1); } }; /// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the @@ -1296,8 +1474,10 @@ public: /// __is_pod(int) == true /// __is_enum(std::string) == false class UnaryTypeTraitExpr : public Expr { - /// UTT - The trait. - UnaryTypeTrait UTT; + /// UTT - The trait. A UnaryTypeTrait enum in MSVC compat unsigned. + unsigned UTT : 31; + /// The value of the type trait. Unspecified if dependent. + bool Value : 1; /// Loc - The location of the type trait keyword. SourceLocation Loc; @@ -1305,25 +1485,31 @@ class UnaryTypeTraitExpr : public Expr { /// RParen - The location of the closing paren. SourceLocation RParen; - /// QueriedType - The type we're testing. - QualType QueriedType; + /// The type being queried. + TypeSourceInfo *QueriedType; public: - UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried, + UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, + TypeSourceInfo *queried, bool value, SourceLocation rparen, QualType ty) - : Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()), - UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { } + : Expr(UnaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, + false, queried->getType()->isDependentType(), + queried->getType()->containsUnexpandedParameterPack()), + UTT(utt), Value(value), Loc(loc), RParen(rparen), QueriedType(queried) { } explicit UnaryTypeTraitExpr(EmptyShell Empty) - : Expr(UnaryTypeTraitExprClass, Empty), UTT((UnaryTypeTrait)0) { } + : Expr(UnaryTypeTraitExprClass, Empty), UTT(0), Value(false), + QueriedType() { } - virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);} + SourceRange getSourceRange() const { return SourceRange(Loc, RParen);} - UnaryTypeTrait getTrait() const { return UTT; } + UnaryTypeTrait getTrait() const { return static_cast<UnaryTypeTrait>(UTT); } - QualType getQueriedType() const { return QueriedType; } + QualType getQueriedType() const { return QueriedType->getType(); } - bool EvaluateTrait(ASTContext&) const; + TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; } + + bool getValue() const { return Value; } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryTypeTraitExprClass; @@ -1331,8 +1517,74 @@ public: static bool classof(const UnaryTypeTraitExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } + + friend class ASTStmtReader; +}; + +/// BinaryTypeTraitExpr - A GCC or MS binary type trait, as used in the +/// implementation of TR1/C++0x type trait templates. +/// Example: +/// __is_base_of(Base, Derived) == true +class BinaryTypeTraitExpr : public Expr { + /// BTT - The trait. A BinaryTypeTrait enum in MSVC compat unsigned. + unsigned BTT : 8; + + /// The value of the type trait. Unspecified if dependent. + bool Value : 1; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + /// The lhs type being queried. + TypeSourceInfo *LhsType; + + /// The rhs type being queried. + TypeSourceInfo *RhsType; + +public: + BinaryTypeTraitExpr(SourceLocation loc, BinaryTypeTrait btt, + TypeSourceInfo *lhsType, TypeSourceInfo *rhsType, + bool value, SourceLocation rparen, QualType ty) + : Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false, + lhsType->getType()->isDependentType() || + rhsType->getType()->isDependentType(), + (lhsType->getType()->containsUnexpandedParameterPack() || + rhsType->getType()->containsUnexpandedParameterPack())), + BTT(btt), Value(value), Loc(loc), RParen(rparen), + LhsType(lhsType), RhsType(rhsType) { } + + + explicit BinaryTypeTraitExpr(EmptyShell Empty) + : Expr(BinaryTypeTraitExprClass, Empty), BTT(0), Value(false), + LhsType(), RhsType() { } + + SourceRange getSourceRange() const { + return SourceRange(Loc, RParen); + } + + BinaryTypeTrait getTrait() const { + return static_cast<BinaryTypeTrait>(BTT); + } + + QualType getLhsType() const { return LhsType->getType(); } + QualType getRhsType() const { return RhsType->getType(); } + + TypeSourceInfo *getLhsTypeSourceInfo() const { return LhsType; } + TypeSourceInfo *getRhsTypeSourceInfo() const { return RhsType; } + + bool getValue() const { assert(!isTypeDependent()); return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BinaryTypeTraitExprClass; + } + static bool classof(const BinaryTypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } friend class ASTStmtReader; }; @@ -1360,23 +1612,23 @@ protected: /// True if the name was a template-id. bool HasExplicitTemplateArgs; - OverloadExpr(StmtClass K, ASTContext &C, QualType T, bool Dependent, + OverloadExpr(StmtClass K, ASTContext &C, NestedNameSpecifier *Qualifier, SourceRange QRange, const DeclarationNameInfo &NameInfo, - bool HasTemplateArgs, - UnresolvedSetIterator Begin, UnresolvedSetIterator End); + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End, + bool KnownDependent = false, + bool KnownContainsUnexpandedParameterPack = false); OverloadExpr(StmtClass K, EmptyShell Empty) : Expr(K, Empty), Results(0), NumResults(0), Qualifier(0), HasExplicitTemplateArgs(false) { } -public: - /// Computes whether an unresolved lookup on the given declarations - /// and optional template arguments is type- and value-dependent. - static bool ComputeDependence(UnresolvedSetIterator Begin, - UnresolvedSetIterator End, - const TemplateArgumentListInfo *Args); + void initializeResults(ASTContext &C, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); +public: struct FindResult { OverloadExpr *Expression; bool IsAddressOfOperand; @@ -1420,9 +1672,6 @@ public: return UnresolvedSetIterator(Results + NumResults); } - void initializeResults(ASTContext &C, - UnresolvedSetIterator Begin,UnresolvedSetIterator End); - /// Gets the number of declarations in the unresolved set. unsigned getNumDecls() const { return NumResults; } @@ -1469,6 +1718,9 @@ public: T->getStmtClass() == UnresolvedMemberExprClass; } static bool classof(const OverloadExpr *) { return true; } + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// \brief A reference to a name which we were able to look up during @@ -1498,14 +1750,15 @@ class UnresolvedLookupExpr : public OverloadExpr { /// against the qualified-lookup bits. CXXRecordDecl *NamingClass; - UnresolvedLookupExpr(ASTContext &C, QualType T, bool Dependent, + UnresolvedLookupExpr(ASTContext &C, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QRange, const DeclarationNameInfo &NameInfo, - bool RequiresADL, bool Overloaded, bool HasTemplateArgs, + bool RequiresADL, bool Overloaded, + const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedLookupExprClass, C, T, Dependent, Qualifier, - QRange, NameInfo, HasTemplateArgs, Begin, End), + : OverloadExpr(UnresolvedLookupExprClass, C, Qualifier, QRange, NameInfo, + TemplateArgs, Begin, End), RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass) {} @@ -1516,7 +1769,6 @@ class UnresolvedLookupExpr : public OverloadExpr { public: static UnresolvedLookupExpr *Create(ASTContext &C, - bool Dependent, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1524,16 +1776,12 @@ public: bool ADL, bool Overloaded, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { - return new(C) UnresolvedLookupExpr(C, - Dependent ? C.DependentTy : C.OverloadTy, - Dependent, NamingClass, - Qualifier, QualifierRange, NameInfo, - ADL, Overloaded, false, - Begin, End); + return new(C) UnresolvedLookupExpr(C, NamingClass, Qualifier, + QualifierRange, NameInfo, ADL, + Overloaded, 0, Begin, End); } static UnresolvedLookupExpr *Create(ASTContext &C, - bool Dependent, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1544,6 +1792,7 @@ public: UnresolvedSetIterator End); static UnresolvedLookupExpr *CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs); /// True if this declaration should be extended by @@ -1606,15 +1855,14 @@ public: return getExplicitTemplateArgs().NumTemplateArgs; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { SourceRange Range(getNameInfo().getSourceRange()); if (getQualifier()) Range.setBegin(getQualifierRange().getBegin()); if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); return Range; } - virtual StmtIterator child_begin(); - virtual StmtIterator child_end(); + child_range children() { return child_range(); } static bool classof(const Stmt *T) { return T->getStmtClass() == UnresolvedLookupExprClass; @@ -1655,11 +1903,7 @@ class DependentScopeDeclRefExpr : public Expr { NestedNameSpecifier *Qualifier, SourceRange QualifierRange, const DeclarationNameInfo &NameInfo, - bool HasExplicitTemplateArgs) - : Expr(DependentScopeDeclRefExprClass, T, true, true), - NameInfo(NameInfo), QualifierRange(QualifierRange), Qualifier(Qualifier), - HasExplicitTemplateArgs(HasExplicitTemplateArgs) - {} + const TemplateArgumentListInfo *Args); public: static DependentScopeDeclRefExpr *Create(ASTContext &C, @@ -1669,6 +1913,7 @@ public: const TemplateArgumentListInfo *TemplateArgs = 0); static DependentScopeDeclRefExpr *CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs); /// \brief Retrieve the name that this expression refers to. @@ -1740,7 +1985,7 @@ public: return getExplicitTemplateArgs().NumTemplateArgs; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { SourceRange Range(QualifierRange.getBegin(), getLocation()); if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); @@ -1752,25 +1997,32 @@ public: } static bool classof(const DependentScopeDeclRefExpr *) { return true; } - virtual StmtIterator child_begin(); - virtual StmtIterator child_end(); + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; -class CXXExprWithTemporaries : public Expr { +/// Represents an expression --- generally a full-expression --- which +/// introduces cleanups to be run at the end of the sub-expression's +/// evaluation. The most common source of expression-introduced +/// cleanups is temporary objects in C++, but several other C++ +/// expressions can create cleanups. +class ExprWithCleanups : public Expr { Stmt *SubExpr; CXXTemporary **Temps; unsigned NumTemps; - CXXExprWithTemporaries(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, - unsigned NumTemps); - + ExprWithCleanups(ASTContext &C, Expr *SubExpr, + CXXTemporary **Temps, unsigned NumTemps); + public: - CXXExprWithTemporaries(EmptyShell Empty) - : Expr(CXXExprWithTemporariesClass, Empty), + ExprWithCleanups(EmptyShell Empty) + : Expr(ExprWithCleanupsClass, Empty), SubExpr(0), Temps(0), NumTemps(0) {} - static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, + static ExprWithCleanups *Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, unsigned NumTemps); @@ -1782,7 +2034,7 @@ public: return Temps[i]; } const CXXTemporary *getTemporary(unsigned i) const { - return const_cast<CXXExprWithTemporaries*>(this)->getTemporary(i); + return const_cast<ExprWithCleanups*>(this)->getTemporary(i); } void setTemporary(unsigned i, CXXTemporary *T) { assert(i < NumTemps && "Index out of range"); @@ -1793,19 +2045,18 @@ public: const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } void setSubExpr(Expr *E) { SubExpr = E; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SubExpr->getSourceRange(); } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXExprWithTemporariesClass; + return T->getStmtClass() == ExprWithCleanupsClass; } - static bool classof(const CXXExprWithTemporaries *) { return true; } + static bool classof(const ExprWithCleanups *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } }; /// \brief Describes an explicit type conversion that uses functional @@ -1830,12 +2081,9 @@ public: /// constructor call, conversion function call, or some kind of type /// conversion. class CXXUnresolvedConstructExpr : public Expr { - /// \brief The starting location of the type - SourceLocation TyBeginLoc; - /// \brief The type being constructed. - QualType Type; - + TypeSourceInfo *Type; + /// \brief The location of the left parentheses ('('). SourceLocation LParenLoc; @@ -1845,20 +2093,20 @@ class CXXUnresolvedConstructExpr : public Expr { /// \brief The number of arguments used to construct the type. unsigned NumArgs; - CXXUnresolvedConstructExpr(SourceLocation TyBegin, - QualType T, + CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) - : Expr(CXXUnresolvedConstructExprClass, Empty), NumArgs(NumArgs) { } + : Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { } + friend class ASTStmtReader; + public: static CXXUnresolvedConstructExpr *Create(ASTContext &C, - SourceLocation TyBegin, - QualType T, + TypeSourceInfo *Type, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -1867,15 +2115,14 @@ public: static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C, unsigned NumArgs); - /// \brief Retrieve the source location where the type begins. - SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } - void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } - /// \brief Retrieve the type that is being constructed, as specified /// in the source code. - QualType getTypeAsWritten() const { return Type; } - void setTypeAsWritten(QualType T) { Type = T; } + QualType getTypeAsWritten() const { return Type->getType(); } + /// \brief Retrieve the type source information for the type being + /// constructed. + TypeSourceInfo *getTypeSourceInfo() const { return Type; } + /// \brief Retrieve the location of the left parentheses ('(') that /// precedes the argument list. SourceLocation getLParenLoc() const { return LParenLoc; } @@ -1916,17 +2163,18 @@ public: *(arg_begin() + I) = E; } - virtual SourceRange getSourceRange() const { - return SourceRange(TyBeginLoc, RParenLoc); - } + SourceRange getSourceRange() const; + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXUnresolvedConstructExprClass; } static bool classof(const CXXUnresolvedConstructExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + Stmt **begin = reinterpret_cast<Stmt**>(this+1); + return child_range(begin, begin + NumArgs); + } }; /// \brief Represents a C++ member access expression where the actual @@ -1987,19 +2235,13 @@ class CXXDependentScopeMemberExpr : public Expr { public: CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, QualType BaseType, - bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - NamedDecl *FirstQualifierFoundInScope, - DeclarationNameInfo MemberNameInfo) - : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), BaseType(BaseType), IsArrow(IsArrow), - HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), - Qualifier(Qualifier), QualifierRange(QualifierRange), - FirstQualifierFoundInScope(FirstQualifierFoundInScope), - MemberNameInfo(MemberNameInfo) { } + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo); static CXXDependentScopeMemberExpr * Create(ASTContext &C, @@ -2012,7 +2254,8 @@ public: const TemplateArgumentListInfo *TemplateArgs); static CXXDependentScopeMemberExpr * - CreateEmpty(ASTContext &C, unsigned NumTemplateArgs); + CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source @@ -2147,7 +2390,7 @@ public: return getExplicitTemplateArgs().RAngleLoc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { SourceRange Range; if (!isImplicitAccess()) Range.setBegin(Base->getSourceRange().getBegin()); @@ -2169,8 +2412,13 @@ public: static bool classof(const CXXDependentScopeMemberExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + if (isImplicitAccess()) return child_range(); + return child_range(&Base, &Base + 1); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// \brief Represents a C++ member access expression for which lookup @@ -2206,8 +2454,7 @@ class UnresolvedMemberExpr : public OverloadExpr { /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; - UnresolvedMemberExpr(ASTContext &C, QualType T, bool Dependent, - bool HasUnresolvedUsing, + UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -2222,7 +2469,7 @@ class UnresolvedMemberExpr : public OverloadExpr { public: static UnresolvedMemberExpr * - Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, + Create(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -2232,7 +2479,8 @@ public: UnresolvedSetIterator Begin, UnresolvedSetIterator End); static UnresolvedMemberExpr * - CreateEmpty(ASTContext &C, unsigned NumTemplateArgs); + CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs); /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source @@ -2337,7 +2585,7 @@ public: return getExplicitTemplateArgs().RAngleLoc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { SourceRange Range = getMemberNameInfo().getSourceRange(); if (!isImplicitAccess()) Range.setBegin(Base->getSourceRange().getBegin()); @@ -2355,10 +2603,130 @@ public: static bool classof(const UnresolvedMemberExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + if (isImplicitAccess()) return child_range(); + return child_range(&Base, &Base + 1); + } +}; + +/// \brief Represents a C++0x noexcept expression (C++ [expr.unary.noexcept]). +/// +/// The noexcept expression tests whether a given expression might throw. Its +/// result is a boolean constant. +class CXXNoexceptExpr : public Expr { + bool Value : 1; + Stmt *Operand; + SourceRange Range; + + friend class ASTStmtReader; + +public: + CXXNoexceptExpr(QualType Ty, Expr *Operand, CanThrowResult Val, + SourceLocation Keyword, SourceLocation RParen) + : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, + /*TypeDependent*/false, + /*ValueDependent*/Val == CT_Dependent, + Operand->containsUnexpandedParameterPack()), + Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) + { } + + CXXNoexceptExpr(EmptyShell Empty) + : Expr(CXXNoexceptExprClass, Empty) + { } + + Expr *getOperand() const { return static_cast<Expr*>(Operand); } + + SourceRange getSourceRange() const { return Range; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNoexceptExprClass; + } + static bool classof(const CXXNoexceptExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Operand, &Operand + 1); } }; +/// \brief Represents a C++0x pack expansion that produces a sequence of +/// expressions. +/// +/// A pack expansion expression contains a pattern (which itself is an +/// expression) followed by an ellipsis. For example: +/// +/// \code +/// template<typename F, typename ...Types> +/// void forward(F f, Types &&...args) { +/// f(static_cast<Types&&>(args)...); +/// } +/// \endcode +/// +/// Here, the argument to the function object \c f is a pack expansion whose +/// pattern is \c static_cast<Types&&>(args). When the \c forward function +/// template is instantiated, the pack expansion will instantiate to zero or +/// or more function arguments to the function object \c f. +class PackExpansionExpr : public Expr { + SourceLocation EllipsisLoc; + + /// \brief The number of expansions that will be produced by this pack + /// expansion expression, if known. + /// + /// When zero, the number of expansions is not known. Otherwise, this value + /// is the number of expansions + 1. + unsigned NumExpansions; + + Stmt *Pattern; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) + : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), + Pattern->getObjectKind(), /*TypeDependent=*/true, + /*ValueDependent=*/true, /*ContainsUnexpandedParameterPack=*/false), + EllipsisLoc(EllipsisLoc), + NumExpansions(NumExpansions? *NumExpansions + 1 : 0), + Pattern(Pattern) { } + + PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { } + + /// \brief Retrieve the pattern of the pack expansion. + Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the pattern of the pack expansion. + const Expr *getPattern() const { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the location of the ellipsis that describes this pack + /// expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// \brief Determine the number of expansions that will be produced when + /// this pack expansion is instantiated, if already known. + llvm::Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return llvm::Optional<unsigned>(); + } + + SourceRange getSourceRange() const { + return SourceRange(Pattern->getLocStart(), EllipsisLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PackExpansionExprClass; + } + static bool classof(const PackExpansionExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&Pattern, &Pattern + 1); + } +}; + inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() { if (isa<UnresolvedLookupExpr>(this)) return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs(); @@ -2366,6 +2734,159 @@ inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() { return cast<UnresolvedMemberExpr>(this)->getExplicitTemplateArgs(); } +/// \brief Represents an expression that computes the length of a parameter +/// pack. +/// +/// \code +/// template<typename ...Types> +/// struct count { +/// static const unsigned value = sizeof...(Types); +/// }; +/// \endcode +class SizeOfPackExpr : public Expr { + /// \brief The location of the 'sizeof' keyword. + SourceLocation OperatorLoc; + + /// \brief The location of the name of the parameter pack. + SourceLocation PackLoc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + /// \brief The length of the parameter pack, if known. + /// + /// When this expression is value-dependent, the length of the parameter pack + /// is unknown. When this expression is not value-dependent, the length is + /// known. + unsigned Length; + + /// \brief The parameter pack itself. + NamedDecl *Pack; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + /// \brief Creates a value-dependent expression that computes the length of + /// the given parameter pack. + SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, SourceLocation RParenLoc) + : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), + OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), + Length(0), Pack(Pack) { } + + /// \brief Creates an expression that computes the length of + /// the given parameter pack, which is already known. + SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, SourceLocation RParenLoc, + unsigned Length) + : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), + OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), + Length(Length), Pack(Pack) { } + + /// \brief Create an empty expression. + SizeOfPackExpr(EmptyShell Empty) : Expr(SizeOfPackExprClass, Empty) { } + + /// \brief Determine the location of the 'sizeof' keyword. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Determine the location of the parameter pack. + SourceLocation getPackLoc() const { return PackLoc; } + + /// \brief Determine the location of the right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// \brief Retrieve the parameter pack. + NamedDecl *getPack() const { return Pack; } + + /// \brief Retrieve the length of the parameter pack. + /// + /// This routine may only be invoked when the expression is not + /// value-dependent. + unsigned getPackLength() const { + assert(!isValueDependent() && + "Cannot get the length of a value-dependent pack size expression"); + return Length; + } + + SourceRange getSourceRange() const { + return SourceRange(OperatorLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SizeOfPackExprClass; + } + static bool classof(const SizeOfPackExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// \brief Represents a reference to a non-type template parameter pack that +/// has been substituted with a non-template argument pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this node node is used to represent a non-type template +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the appropriate underlying +/// expression at the current pack substitution index. +class SubstNonTypeTemplateParmPackExpr : public Expr { + /// \brief The non-type template parameter pack itself. + NonTypeTemplateParmDecl *Param; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + /// \brief The location of the non-type template parameter pack reference. + SourceLocation NameLoc; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack); + + SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } + + /// \brief Retrieve the non-type template parameter pack being substituted. + NonTypeTemplateParmDecl *getParameterPack() const { return Param; } + + /// \brief Retrieve the location of the parameter pack name. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Retrieve the template argument pack containing the substituted + /// template arguments. + TemplateArgument getArgumentPack() const; + + SourceRange getSourceRange() const { return NameLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass; + } + static bool classof(const SubstNonTypeTemplateParmPackExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(); } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 8a09f4e9a6a9..285efb757bbb 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -14,14 +14,13 @@ #ifndef LLVM_CLANG_AST_EXPROBJC_H #define LLVM_CLANG_AST_EXPROBJC_H +#include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/IdentifierTable.h" namespace clang { class IdentifierInfo; class ASTContext; - class ObjCMethodDecl; - class ObjCPropertyDecl; /// ObjCStringLiteral, used for Objective-C string literals /// i.e. @"foo". @@ -30,7 +29,9 @@ class ObjCStringLiteral : public Expr { SourceLocation AtLoc; public: ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) - : Expr(ObjCStringLiteralClass, T, false, false), String(SL), AtLoc(L) {} + : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, + false), + String(SL), AtLoc(L) {} explicit ObjCStringLiteral(EmptyShell Empty) : Expr(ObjCStringLiteralClass, Empty) {} @@ -41,7 +42,7 @@ public: SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtLoc, String->getLocEnd()); } @@ -51,8 +52,7 @@ public: static bool classof(const ObjCStringLiteral *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&String, &String+1); } }; /// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type @@ -64,8 +64,10 @@ class ObjCEncodeExpr : public Expr { public: ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, SourceLocation at, SourceLocation rp) - : Expr(ObjCEncodeExprClass, T, EncodedType->getType()->isDependentType(), - EncodedType->getType()->isDependentType()), + : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isDependentType(), + EncodedType->getType()->containsUnexpandedParameterPack()), EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} @@ -83,7 +85,7 @@ public: EncodedType = EncType; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } @@ -93,8 +95,7 @@ public: static bool classof(const ObjCEncodeExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// ObjCSelectorExpr used for @selector in Objective-C. @@ -104,8 +105,9 @@ class ObjCSelectorExpr : public Expr { public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, SourceLocation rp) - : Expr(ObjCSelectorExprClass, T, false, false), SelName(selInfo), AtLoc(at), - RParenLoc(rp){} + : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, + false), + SelName(selInfo), AtLoc(at), RParenLoc(rp){} explicit ObjCSelectorExpr(EmptyShell Empty) : Expr(ObjCSelectorExprClass, Empty) {} @@ -117,7 +119,7 @@ public: void setAtLoc(SourceLocation L) { AtLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } @@ -130,8 +132,7 @@ public: static bool classof(const ObjCSelectorExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// ObjCProtocolExpr used for protocol expression in Objective-C. This is used @@ -144,8 +145,9 @@ class ObjCProtocolExpr : public Expr { public: ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, SourceLocation at, SourceLocation rp) - : Expr(ObjCProtocolExprClass, T, false, false), TheProtocol(protocol), - AtLoc(at), RParenLoc(rp) {} + : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, + false), + TheProtocol(protocol), AtLoc(at), RParenLoc(rp) {} explicit ObjCProtocolExpr(EmptyShell Empty) : Expr(ObjCProtocolExprClass, Empty) {} @@ -157,7 +159,7 @@ public: void setAtLoc(SourceLocation L) { AtLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } @@ -167,8 +169,7 @@ public: static bool classof(const ObjCProtocolExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// ObjCIvarRefExpr - A reference to an ObjC instance variable. @@ -180,13 +181,13 @@ class ObjCIvarRefExpr : public Expr { bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). public: - ObjCIvarRefExpr(ObjCIvarDecl *d, - QualType t, SourceLocation l, Expr *base, + ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, + SourceLocation l, Expr *base, bool arrow = false, bool freeIvar = false) : - Expr(ObjCIvarRefExprClass, t, /*TypeDependent=*/false, - base->isValueDependent()), D(d), - Loc(l), Base(base), IsArrow(arrow), - IsFreeIvar(freeIvar) {} + Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->containsUnexpandedParameterPack()), + D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {} explicit ObjCIvarRefExpr(EmptyShell Empty) : Expr(ObjCIvarRefExprClass, Empty) {} @@ -207,7 +208,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return isFreeIvar() ? SourceRange(Loc) : SourceRange(getBase()->getLocStart(), Loc); } @@ -218,8 +219,7 @@ public: static bool classof(const ObjCIvarRefExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Base, &Base+1); } }; /// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC @@ -227,32 +227,127 @@ public: /// class ObjCPropertyRefExpr : public Expr { private: - ObjCPropertyDecl *AsProperty; + /// If the bool is true, this is an implicit property reference; the + /// pointer is an (optional) ObjCMethodDecl and Setter may be set. + /// if the bool is false, this is an explicit property reference; + /// the pointer is an ObjCPropertyDecl and Setter is always null. + llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; + ObjCMethodDecl *Setter; + SourceLocation IdLoc; - Stmt *Base; + + /// \brief When the receiver in property access is 'super', this is + /// the location of the 'super' keyword. When it's an interface, + /// this is that interface. + SourceLocation ReceiverLoc; + llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver; + public: ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, SourceLocation l, Expr *base) - : Expr(ObjCPropertyRefExprClass, t, /*TypeDependent=*/false, - base->isValueDependent()), - AsProperty(PD), IdLoc(l), Base(base) { + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, base->isValueDependent(), + base->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), Setter(0), + IdLoc(l), ReceiverLoc(), Receiver(base) { + } + + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation l, SourceLocation sl, QualType st) + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, false, + st->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), Setter(0), + IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, Expr *Base) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, + Base->isValueDependent(), + Base->containsUnexpandedParameterPack()), + PropertyOrGetter(Getter, true), Setter(Setter), + IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation SuperLoc, QualType SuperTy) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false), + PropertyOrGetter(Getter, true), Setter(Setter), + IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false), + PropertyOrGetter(Getter, true), Setter(Setter), + IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { } explicit ObjCPropertyRefExpr(EmptyShell Empty) : Expr(ObjCPropertyRefExprClass, Empty) {} - ObjCPropertyDecl *getProperty() const { return AsProperty; } - void setProperty(ObjCPropertyDecl *D) { AsProperty = D; } + bool isImplicitProperty() const { return PropertyOrGetter.getInt(); } + bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); } - const Expr *getBase() const { return cast<Expr>(Base); } - Expr *getBase() { return cast<Expr>(Base); } - void setBase(Expr *base) { Base = base; } + ObjCPropertyDecl *getExplicitProperty() const { + assert(!isImplicitProperty()); + return cast<ObjCPropertyDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertyGetter() const { + assert(isImplicitProperty()); + return cast_or_null<ObjCMethodDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertySetter() const { + assert(isImplicitProperty()); + return Setter; + } + + Selector getGetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertyGetter()->getSelector(); + return getExplicitProperty()->getGetterName(); + } + + Selector getSetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertySetter()->getSelector(); + return getExplicitProperty()->getSetterName(); + } + + const Expr *getBase() const { + return cast<Expr>(Receiver.get<Stmt*>()); + } + Expr *getBase() { + return cast<Expr>(Receiver.get<Stmt*>()); + } SourceLocation getLocation() const { return IdLoc; } - void setLocation(SourceLocation L) { IdLoc = L; } + + SourceLocation getReceiverLocation() const { return ReceiverLoc; } + QualType getSuperReceiverType() const { + return QualType(Receiver.get<const Type*>(), 0); + } + ObjCInterfaceDecl *getClassReceiver() const { + return Receiver.get<ObjCInterfaceDecl*>(); + } + bool isObjectReceiver() const { return Receiver.is<Stmt*>(); } + bool isSuperReceiver() const { return Receiver.is<const Type*>(); } + bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } - virtual SourceRange getSourceRange() const { - return SourceRange(getBase()->getLocStart(), IdLoc); + SourceRange getSourceRange() const { + return SourceRange((isObjectReceiver() ? getBase()->getLocStart() + : getReceiverLocation()), + IdLoc); } static bool classof(const Stmt *T) { @@ -261,89 +356,32 @@ public: static bool classof(const ObjCPropertyRefExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; - -/// 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; - /// 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 *InterfaceDecl; - /// Location of the receiver class in the dot syntax notation - /// used to call a class method setter/getter. - SourceLocation ClassLoc; - -public: - ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter, - QualType t, - ObjCMethodDecl *setter, - SourceLocation l, Expr *base) - : Expr(ObjCImplicitSetterGetterRefExprClass, t, /*TypeDependent=*/false, - base->isValueDependent()), - Setter(setter), Getter(getter), MemberLoc(l), Base(base), - InterfaceDecl(0), ClassLoc(SourceLocation()) { - } - ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter, - QualType t, - ObjCMethodDecl *setter, - SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL) - : Expr(ObjCImplicitSetterGetterRefExprClass, t, false, false), - Setter(setter), Getter(getter), MemberLoc(l), Base(0), InterfaceDecl(C), - ClassLoc(CL) { + child_range children() { + if (Receiver.is<Stmt*>()) { + Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack! + return child_range(begin, begin+1); } - explicit ObjCImplicitSetterGetterRefExpr(EmptyShell Empty) - : Expr(ObjCImplicitSetterGetterRefExprClass, Empty){} - - ObjCMethodDecl *getGetterMethod() const { return Getter; } - ObjCMethodDecl *getSetterMethod() const { return Setter; } - ObjCInterfaceDecl *getInterfaceDecl() const { return InterfaceDecl; } - void setGetterMethod(ObjCMethodDecl *D) { Getter = D; } - void setSetterMethod(ObjCMethodDecl *D) { Setter = D; } - void setInterfaceDecl(ObjCInterfaceDecl *D) { InterfaceDecl = D; } - - virtual SourceRange getSourceRange() const { - if (Base) - 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 MemberLoc; } - void setLocation(SourceLocation L) { MemberLoc = L; } - SourceLocation getClassLoc() const { return ClassLoc; } - void setClassLoc(SourceLocation L) { ClassLoc = L; } + return child_range(); + } - static bool classof(const Stmt *T) { - return T->getStmtClass() == ObjCImplicitSetterGetterRefExprClass; +private: + friend class ASTStmtReader; + void setExplicitProperty(ObjCPropertyDecl *D) { + PropertyOrGetter.setPointer(D); + PropertyOrGetter.setInt(false); + Setter = 0; + } + void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter) { + PropertyOrGetter.setPointer(Getter); + PropertyOrGetter.setInt(true); + this->Setter = Setter; } - static bool classof(const ObjCImplicitSetterGetterRefExpr *) { return true; } + void setBase(Expr *Base) { Receiver = Base; } + void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } + void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; } - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + void setLocation(SourceLocation L) { IdLoc = L; } + void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; } }; /// \brief An expression that sends a message to the given Objective-C @@ -396,6 +434,9 @@ class ObjCMessageExpr : public Expr { /// referring to the method that we type-checked against. uintptr_t SelectorOrMethod; + /// \brief Location of the selector. + SourceLocation SelectorLoc; + /// \brief The source locations of the open and close square /// brackets ('[' and ']', respectively). SourceLocation LBracLoc, RBracLoc; @@ -404,26 +445,29 @@ class ObjCMessageExpr : public Expr { : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0), HasMethod(0), SelectorOrMethod(0) { } - ObjCMessageExpr(QualType T, + ObjCMessageExpr(QualType T, ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, bool IsInstanceSuper, QualType SuperType, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); - ObjCMessageExpr(QualType T, + ObjCMessageExpr(QualType T, ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); - ObjCMessageExpr(QualType T, + ObjCMessageExpr(QualType T, ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); @@ -458,6 +502,10 @@ public: /// /// \param T The result type of this message. /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// /// \param LBrac The location of the open square bracket '['. /// /// \param SuperLoc The location of the "super" keyword. @@ -475,12 +523,14 @@ public: /// \param NumArgs The number of arguments. /// /// \param RBracLoc The location of the closing square bracket ']'. - static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, bool IsInstanceSuper, QualType SuperType, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); @@ -491,6 +541,10 @@ public: /// /// \param T The result type of this message. /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// /// \param LBrac The location of the open square bracket '['. /// /// \param Receiver The type of the receiver, including @@ -507,9 +561,11 @@ public: /// /// \param RBracLoc The location of the closing square bracket ']'. static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); @@ -520,6 +576,10 @@ public: /// /// \param T The result type of this message. /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// /// \param LBrac The location of the open square bracket '['. /// /// \param Receiver The expression used to produce the object that @@ -536,9 +596,11 @@ public: /// /// \param RBracLoc The location of the closing square bracket ']'. static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc); @@ -556,6 +618,9 @@ public: /// sent to. ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; } + /// \brief Source range of the receiver. + SourceRange getReceiverRange() const; + /// \brief Determine whether this is an instance message to either a /// computed object or to super. bool isInstanceMessage() const { @@ -682,11 +747,11 @@ public: /// \brief Retrieve the arguments to this message, not including the /// receiver. - Stmt **getArgs() { - return reinterpret_cast<Stmt **>(this + 1) + 1; + Expr **getArgs() { + return reinterpret_cast<Expr **>(this + 1) + 1; } - const Stmt * const *getArgs() const { - return reinterpret_cast<const Stmt * const *>(this + 1) + 1; + const Expr * const *getArgs() const { + return reinterpret_cast<const Expr * const *>(this + 1) + 1; } /// getArg - Return the specified argument. @@ -706,15 +771,13 @@ public: SourceLocation getLeftLoc() const { return LBracLoc; } SourceLocation getRightLoc() const { return RBracLoc; } - - void setLeftLoc(SourceLocation L) { LBracLoc = L; } - void setRightLoc(SourceLocation L) { RBracLoc = L; } + SourceLocation getSelectorLoc() const { return SelectorLoc; } void setSourceRange(SourceRange R) { LBracLoc = R.getBegin(); RBracLoc = R.getEnd(); } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(LBracLoc, RBracLoc); } @@ -724,43 +787,24 @@ public: static bool classof(const ObjCMessageExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children(); typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; - arg_iterator arg_begin() { return getArgs(); } - arg_iterator arg_end() { return getArgs() + NumArgs; } - const_arg_iterator arg_begin() const { return getArgs(); } - const_arg_iterator arg_end() const { return getArgs() + NumArgs; } -}; - -/// ObjCSuperExpr - Represents the "super" expression in Objective-C, -/// which refers to the object on which the current method is executing. -/// -/// FIXME: This class is intended for removal, once its remaining -/// clients have been altered to represent "super" internally. -class ObjCSuperExpr : public Expr { - SourceLocation Loc; -public: - ObjCSuperExpr(SourceLocation L, QualType Type) - : Expr(ObjCSuperExprClass, Type, false, false), 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) { - return T->getStmtClass() == ObjCSuperExprClass; + arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); } + arg_iterator arg_end() { + return reinterpret_cast<Stmt **>(getArgs() + NumArgs); + } + const_arg_iterator arg_begin() const { + return reinterpret_cast<Stmt const * const*>(getArgs()); + } + const_arg_iterator arg_end() const { + return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs); } - static bool classof(const ObjCSuperExpr *) { return true; } - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. @@ -776,8 +820,9 @@ class ObjCIsaExpr : public Expr { bool IsArrow; public: ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) - : Expr(ObjCIsaExprClass, ty, /*TypeDependent=*/false, - base->isValueDependent()), + : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + /*ContainsUnexpandedParameterPack=*/false), Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} /// \brief Build an empty expression. @@ -794,11 +839,11 @@ public: SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; } void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), IsaMemberLoc); } - virtual SourceLocation getExprLoc() const { return IsaMemberLoc; } + SourceLocation getExprLoc() const { return IsaMemberLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCIsaExprClass; @@ -806,8 +851,7 @@ public: static bool classof(const ObjCIsaExpr *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Base, &Base+1); } }; } // end namespace clang diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index a8ef0053a442..7b23766b0714 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H #define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H +#include "clang/AST/DeclBase.h" #include <cassert> #include <vector> @@ -24,6 +25,7 @@ template <class T> class SmallVectorImpl; namespace clang { class ASTConsumer; +class CXXBaseSpecifier; class Decl; class DeclContext; class DeclContextLookupResult; @@ -32,6 +34,7 @@ class ExternalSemaSource; // layering violation required for downcasting class NamedDecl; class Selector; class Stmt; +class TagDecl; /// \brief Abstract interface for external sources of AST nodes. /// @@ -91,6 +94,10 @@ public: /// FunctionDecl::setLazyBody when building decls. virtual Stmt *GetExternalDeclStmt(uint64_t Offset) = 0; + /// \brief Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) = 0; + /// \brief Finds all declarations with the given name in the /// given context. /// @@ -110,12 +117,44 @@ public: virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0; /// \brief Finds all declarations lexically contained within the given - /// DeclContext. + /// DeclContext, after applying an optional filter predicate. + /// + /// \param isKindWeWant a predicate function that returns true if the passed + /// declaration kind is one we are looking for. If NULL, all declarations + /// are returned. /// /// \return true if an error occurred virtual bool FindExternalLexicalDecls(const DeclContext *DC, - llvm::SmallVectorImpl<Decl*> &Result) = 0; + bool (*isKindWeWant)(Decl::Kind), + llvm::SmallVectorImpl<Decl*> &Result) = 0; + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext. + /// + /// \return true if an error occurred + bool FindExternalLexicalDecls(const DeclContext *DC, + llvm::SmallVectorImpl<Decl*> &Result) { + return FindExternalLexicalDecls(DC, 0, Result); + } + + template <typename DeclTy> + bool FindExternalLexicalDeclsBy(const DeclContext *DC, + llvm::SmallVectorImpl<Decl*> &Result) { + return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result); + } + + /// \brief Gives the external AST source an opportunity to complete + /// an incomplete type. + virtual void CompleteType(TagDecl *Tag) {} + /// \brief Gives the external AST source an opportunity to complete an + /// incomplete Objective-C class. + /// + /// This routine will only be invoked if the "externally completed" bit is + /// set on the ObjCInterfaceDecl via the function + /// \c ObjCInterfaceDecl::setExternallyCompleted(). + virtual void CompleteType(ObjCInterfaceDecl *Class) { } + /// \brief Notify ExternalASTSource that we started deserialization of /// a decl or type so until FinishedDeserializing is called there may be /// decls that are initializing. Must be paired with FinishedDeserializing. @@ -227,6 +266,11 @@ typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> LazyDeclPtr; +/// \brief A lazy pointer to a set of CXXBaseSpecifiers. +typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, + &ExternalASTSource::GetExternalCXXBaseSpecifiers> + LazyCXXBaseSpecifiersPtr; + } // end namespace clang #endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H diff --git a/include/clang/AST/FullExpr.h b/include/clang/AST/FullExpr.h deleted file mode 100644 index 6ceefed8a63a..000000000000 --- a/include/clang/AST/FullExpr.h +++ /dev/null @@ -1,88 +0,0 @@ -//===--- FullExpr.h - C++ full expression class -----------------*- 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 FullExpr interface, to be used for type safe handling -// of full expressions. -// -// Full expressions are described in C++ [intro.execution]p12. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_FULLEXPR_H -#define LLVM_CLANG_AST_FULLEXPR_H - -#include "llvm/ADT/PointerUnion.h" - -namespace clang { - class ASTContext; - class CXXTemporary; - class Expr; - -class FullExpr { - struct ExprAndTemporaries { - Expr *SubExpr; - - unsigned NumTemps; - - typedef CXXTemporary** temps_iterator; - - temps_iterator temps_begin() { - return reinterpret_cast<CXXTemporary **>(this + 1); - } - temps_iterator temps_end() { - return temps_begin() + NumTemps; - } - }; - - typedef llvm::PointerUnion<Expr *, ExprAndTemporaries *> SubExprTy; - SubExprTy SubExpr; - - FullExpr() { } - -public: - static FullExpr Create(ASTContext &Context, Expr *SubExpr, - CXXTemporary **Temps, unsigned NumTemps); - - Expr *getExpr() { - if (Expr *E = SubExpr.dyn_cast<Expr *>()) - return E; - - return SubExpr.get<ExprAndTemporaries *>()->SubExpr; - } - - const Expr *getExpr() const { - return const_cast<FullExpr*>(this)->getExpr(); - } - - typedef CXXTemporary** temps_iterator; - - temps_iterator temps_begin() { - if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>()) - return ET->temps_begin(); - - return 0; - } - temps_iterator temps_end() { - if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>()) - return ET->temps_end(); - - return 0; - } - - void *getAsOpaquePtr() const { return SubExpr.getOpaqueValue(); } - - static FullExpr getFromOpaquePtr(void *Ptr) { - FullExpr E; - E.SubExpr = SubExprTy::getFromOpaqueValue(Ptr); - return E; - } -}; - -} // end namespace clang - -#endif diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h new file mode 100644 index 000000000000..7af7702027a4 --- /dev/null +++ b/include/clang/AST/Mangle.h @@ -0,0 +1,150 @@ +//===--- Mangle.h - Mangle C++ Names ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the C++ name mangling interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MANGLE_H +#define LLVM_CLANG_AST_MANGLE_H + +#include "clang/AST/Type.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + class ASTContext; + class BlockDecl; + class CXXConstructorDecl; + class CXXDestructorDecl; + class CXXMethodDecl; + class FunctionDecl; + class NamedDecl; + class ObjCMethodDecl; + class VarDecl; + struct ThisAdjustment; + struct ThunkInfo; + +/// MangleBuffer - a convenient class for storing a name which is +/// either the result of a mangling or is a constant string with +/// external memory ownership. +class MangleBuffer { +public: + void setString(llvm::StringRef Ref) { + String = Ref; + } + + llvm::SmallVectorImpl<char> &getBuffer() { + return Buffer; + } + + llvm::StringRef getString() const { + if (!String.empty()) return String; + return Buffer.str(); + } + + operator llvm::StringRef() const { + return getString(); + } + +private: + llvm::StringRef String; + llvm::SmallString<256> Buffer; +}; + +/// MangleContext - Context for tracking state which persists across multiple +/// calls to the C++ name mangler. +class MangleContext { + ASTContext &Context; + Diagnostic &Diags; + + llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; + llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; + +public: + explicit MangleContext(ASTContext &Context, + Diagnostic &Diags) + : Context(Context), Diags(Diags) { } + + virtual ~MangleContext() { } + + ASTContext &getASTContext() const { return Context; } + + Diagnostic &getDiags() const { return Diags; } + + virtual void startNewFunction() { LocalBlockIds.clear(); } + + unsigned getBlockId(const BlockDecl *BD, bool Local) { + llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds + = Local? LocalBlockIds : GlobalBlockIds; + std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool> + Result = BlockIds.insert(std::make_pair(BD, BlockIds.size())); + return Result.first->second; + } + + /// @name Mangler Entry Points + /// @{ + + virtual bool shouldMangleDeclName(const NamedDecl *D) = 0; + virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &)=0; + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &) = 0; + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &) = 0; + virtual void mangleReferenceTemporary(const VarDecl *D, + llvm::raw_ostream &) = 0; + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &) = 0; + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &) = 0; + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &) = 0; + virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &) = 0; + virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &) = 0; + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::raw_ostream &) = 0; + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::raw_ostream &) = 0; + + void mangleGlobalBlock(const BlockDecl *BD, + llvm::raw_ostream &Out); + void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT, + const BlockDecl *BD, llvm::raw_ostream &Out); + void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT, + const BlockDecl *BD, llvm::raw_ostream &Out); + void mangleBlock(const DeclContext *DC, const BlockDecl *BD, + llvm::raw_ostream &Out); + // Do the right thing. + void mangleBlock(const BlockDecl *BD, llvm::raw_ostream &Out); + + void mangleObjCMethodName(const ObjCMethodDecl *MD, + llvm::raw_ostream &); + + // This is pretty lame. + virtual void mangleItaniumGuardVariable(const VarDecl *D, + llvm::raw_ostream &) { + assert(0 && "Target does not support mangling guard variables"); + } + /// @} +}; + +MangleContext *createItaniumMangleContext(ASTContext &Context, + Diagnostic &Diags); +MangleContext *createMicrosoftMangleContext(ASTContext &Context, + Diagnostic &Diags); + +} + +#endif diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 3b25f3bb403f..99cc1f268fb2 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -90,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(const ASTContext &Context, const NestedNameSpecifier &Mockup); public: @@ -99,19 +99,19 @@ 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, + static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, IdentifierInfo *II); /// \brief Builds a nested name specifier that names a namespace. - static NestedNameSpecifier *Create(ASTContext &Context, + static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, NamespaceDecl *NS); /// \brief Builds a nested name specifier that names a type. - static NestedNameSpecifier *Create(ASTContext &Context, + static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - bool Template, Type *T); + bool Template, const Type *T); /// \brief Builds a specifier that consists of just an identifier. /// @@ -119,11 +119,12 @@ public: /// 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); + static NestedNameSpecifier *Create(const ASTContext &Context, + IdentifierInfo *II); /// \brief Returns the nested name specifier representing the global /// scope. - static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context); + static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); /// \brief Return the prefix of this nested name specifier. /// @@ -160,10 +161,10 @@ public: } /// \brief Retrieve the type stored in this nested name specifier. - Type *getAsType() const { + const Type *getAsType() const { if (Prefix.getInt() == TypeSpec || Prefix.getInt() == TypeSpecWithTemplate) - return (Type *)Specifier; + return (const Type *)Specifier; return 0; } @@ -172,6 +173,10 @@ public: /// type or not. bool isDependent() const; + /// \brief Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++0x variadic templates). + bool containsUnexpandedParameterPack() const; + /// \brief Print this nested name specifier to the given output /// stream. void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index 804531192971..35c72c45ce7c 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -17,107 +17,238 @@ namespace clang { -/// CastKind - the kind of cast this represents. +/// CastKind - The kind of operation required for a conversion. 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_Dependent - A conversion which cannot yet be analyzed because + /// either the expression or target type is dependent. These are + /// created only for explicit casts; dependent ASTs aren't required + /// to even approximately type-check. + /// (T*) malloc(sizeof(T)) + /// reinterpret_cast<intptr_t>(A<T>::alloc()); + CK_Dependent, - /// CK_BitCast - Used for reinterpret_cast. + /// CK_BitCast - A conversion which causes a bit pattern of one type + /// to be reinterpreted as a bit pattern of another type. Generally + /// the operands must have equivalent size and unrelated types. + /// + /// The pointer conversion char* -> int* is a bitcast. Many other + /// pointer conversions which are "physically" bitcasts are given + /// special cast kinds. + /// + /// Vector coercions are bitcasts. CK_BitCast, - /// CK_LValueBitCast - Used for reinterpret_cast of expressions to - /// a reference type. + /// CK_LValueBitCast - A conversion which reinterprets the address of + /// an l-value as an l-value of a different kind. Used for + /// reinterpret_casts of l-value expressions to reference types. + /// bool b; reinterpret_cast<char&>(b) = 'a'; CK_LValueBitCast, + + /// CK_LValueToRValue - A conversion which causes the extraction of + /// an r-value from the operand gl-value. The result of an r-value + /// conversion is always unqualified. + CK_LValueToRValue, + + /// CK_GetObjCProperty - A conversion which calls an Objective-C + /// property getter. The operand is an OK_ObjCProperty l-value; the + /// result will generally be an r-value, but could be an ordinary + /// gl-value if the property reference is to an implicit property + /// for a method that returns a reference type. + CK_GetObjCProperty, - /// CK_NoOp - Used for const_cast. + /// CK_NoOp - A conversion which does not affect the type other than + /// (possibly) adding qualifiers. + /// int -> int + /// char** -> const char * const * CK_NoOp, - /// CK_BaseToDerived - Base to derived class casts. + /// CK_BaseToDerived - A conversion from a C++ class pointer/reference + /// to a derived class pointer/reference. + /// B *b = static_cast<B*>(a); CK_BaseToDerived, - /// CK_DerivedToBase - Derived to base class casts. + /// CK_DerivedToBase - A conversion from a C++ class pointer + /// to a base class pointer. + /// A *a = new B(); CK_DerivedToBase, - /// CK_UncheckedDerivedToBase - Derived to base class casts that - /// assume that the derived pointer is not null. + /// CK_UncheckedDerivedToBase - A conversion from a C++ class + /// pointer/reference to a base class that can assume that the + /// derived pointer is not null. + /// const A &a = B(); + /// b->method_from_a(); CK_UncheckedDerivedToBase, - /// CK_Dynamic - Dynamic cast. + /// CK_Dynamic - A C++ dynamic_cast. CK_Dynamic, - /// CK_ToUnion - Cast to union (GCC extension). + /// CK_ToUnion - The GCC cast-to-union extension. + /// int -> union { int x; float y; } + /// float -> union { int x; float y; } CK_ToUnion, /// CK_ArrayToPointerDecay - Array to pointer decay. + /// int[10] -> int* + /// char[5][6] -> char(*)[6] CK_ArrayToPointerDecay, - // CK_FunctionToPointerDecay - Function to pointer decay. + /// CK_FunctionToPointerDecay - Function to pointer decay. + /// void(int) -> void(*)(int) CK_FunctionToPointerDecay, - /// CK_NullToMemberPointer - Null pointer to member pointer. + /// CK_NullToPointer - Null pointer constant to pointer, ObjC + /// pointer, or block pointer. + /// (void*) 0 + /// void (^block)() = 0; + CK_NullToPointer, + + /// CK_NullToMemberPointer - Null pointer constant to member pointer. + /// int A::*mptr = 0; + /// int (A::*fptr)(int) = nullptr; CK_NullToMemberPointer, /// CK_BaseToDerivedMemberPointer - Member pointer in base class to /// member pointer in derived class. + /// int B::*mptr = &A::member; CK_BaseToDerivedMemberPointer, /// CK_DerivedToBaseMemberPointer - Member pointer in derived class to /// member pointer in base class. + /// int A::*mptr = static_cast<int A::*>(&B::member); CK_DerivedToBaseMemberPointer, + /// CK_MemberPointerToBoolean - Member pointer to boolean. A check + /// against the null member pointer. + CK_MemberPointerToBoolean, + /// CK_UserDefinedConversion - Conversion using a user defined type /// conversion function. + /// struct A { operator int(); }; int i = int(A()); CK_UserDefinedConversion, - /// CK_ConstructorConversion - Conversion by constructor + /// CK_ConstructorConversion - Conversion by constructor. + /// struct A { A(int); }; A a = A(10); CK_ConstructorConversion, - /// CK_IntegralToPointer - Integral to pointer + /// CK_IntegralToPointer - Integral to pointer. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (char*) 0x1001aab0 + /// reinterpret_cast<int*>(0) CK_IntegralToPointer, - /// CK_PointerToIntegral - Pointer to integral + /// CK_PointerToIntegral - Pointer to integral. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (intptr_t) "help!" CK_PointerToIntegral, + + /// CK_PointerToBoolean - Pointer to boolean conversion. A check + /// against null. Applies to normal, ObjC, and block pointers. + CK_PointerToBoolean, - /// CK_ToVoid - Cast to void. + /// CK_ToVoid - Cast to void, discarding the computed value. + /// (void) malloc(2048) CK_ToVoid, - /// CK_VectorSplat - Casting from an integer/floating type to an extended - /// vector type with the same element type as the src type. Splats the - /// src expression into the destination expression. + /// CK_VectorSplat - A conversion from an arithmetic type to a + /// vector of that element type. Fills all elements ("splats") with + /// the source value. + /// __attribute__((ext_vector_type(4))) int v = 5; CK_VectorSplat, - /// CK_IntegralCast - Casting between integral types of different size. + /// CK_IntegralCast - A cast between integral types (other than to + /// boolean). Variously a bitcast, a truncation, a sign-extension, + /// or a zero-extension. + /// long l = 5; + /// (unsigned) i CK_IntegralCast, + /// CK_IntegralToBoolean - Integral to boolean. A check against zero. + /// (bool) i + CK_IntegralToBoolean, + /// CK_IntegralToFloating - Integral to floating point. + /// float f = i; CK_IntegralToFloating, - /// CK_FloatingToIntegral - Floating point to integral. + /// CK_FloatingToIntegral - Floating point to integral. Rounds + /// towards zero, discarding any fractional component. + /// (int) f CK_FloatingToIntegral, + + /// CK_FloatingToBoolean - Floating point to boolean. + /// (bool) f + CK_FloatingToBoolean, /// CK_FloatingCast - Casting between floating types of different size. + /// (double) f + /// (float) ld CK_FloatingCast, - /// CK_MemberPointerToBoolean - Member pointer to boolean - CK_MemberPointerToBoolean, - - /// CK_AnyPointerToObjCPointerCast - Casting any pointer to objective-c - /// pointer + /// CK_AnyPointerToObjCPointerCast - Casting any other pointer kind + /// to an Objective-C pointer. CK_AnyPointerToObjCPointerCast, - /// CK_AnyPointerToBlockPointerCast - Casting any pointer to block - /// pointer + /// CK_AnyPointerToBlockPointerCast - Casting any other pointer kind + /// to a block pointer. CK_AnyPointerToBlockPointerCast, /// \brief Converting between two Objective-C object types, which /// can occur when performing reference binding to an Objective-C /// object. - CK_ObjCObjectLValueCast + CK_ObjCObjectLValueCast, + + /// \brief A conversion of a floating point real to a floating point + /// complex of the original type. Injects the value as the real + /// component with a zero imaginary component. + /// float -> _Complex float + CK_FloatingRealToComplex, + + /// \brief Converts a floating point complex to floating point real + /// of the source's element type. Just discards the imaginary + /// component. + /// _Complex long double -> long double + CK_FloatingComplexToReal, + + /// \brief Converts a floating point complex to bool by comparing + /// against 0+0i. + CK_FloatingComplexToBoolean, + + /// \brief Converts between different floating point complex types. + /// _Complex float -> _Complex double + CK_FloatingComplexCast, + + /// \brief Converts from a floating complex to an integral complex. + /// _Complex float -> _Complex int + CK_FloatingComplexToIntegralComplex, + + /// \brief Converts from an integral real to an integral complex + /// whose element type matches the source. Injects the value as + /// the real component with a zero imaginary component. + /// long -> _Complex long + CK_IntegralRealToComplex, + + /// \brief Converts an integral complex to an integral real of the + /// source's element type by discarding the imaginary component. + /// _Complex short -> short + CK_IntegralComplexToReal, + + /// \brief Converts an integral complex to bool by comparing against + /// 0+0i. + CK_IntegralComplexToBoolean, + + /// \brief Converts between different integral complex types. + /// _Complex char -> _Complex long long + /// _Complex unsigned int -> _Complex signed int + CK_IntegralComplexCast, + + /// \brief Converts from an integral complex to a floating complex. + /// _Complex unsigned -> _Complex float + CK_IntegralComplexToFloatingComplex }; +#define CK_Invalid ((CastKind) -1) enum BinaryOperatorKind { // Operators listed in order of precedence. diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h index f826e1117b66..9ea5a0930d32 100644 --- a/include/clang/AST/ParentMap.h +++ b/include/clang/AST/ParentMap.h @@ -24,8 +24,14 @@ public: ParentMap(Stmt* ASTRoot); ~ParentMap(); + /// \brief Adds and/or updates the parent/child-relations of the complete + /// stmt tree of S. All children of S including indirect descendants are + /// visited and updated or inserted but not the parents of S. + void addStmt(Stmt* S); + Stmt *getParent(Stmt*) const; Stmt *getParentIgnoreParens(Stmt *) const; + Stmt *getParentIgnoreParenCasts(Stmt *) const; const Stmt *getParent(const Stmt* S) const { return getParent(const_cast<Stmt*>(S)); @@ -35,6 +41,10 @@ public: return getParentIgnoreParens(const_cast<Stmt*>(S)); } + const Stmt *getParentIgnoreParenCasts(const Stmt *S) const { + return getParentIgnoreParenCasts(const_cast<Stmt*>(S)); + } + bool hasParent(Stmt* S) const { return getParent(S) != 0; } diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 70d65d35fef8..a59c302ffc1e 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H #define LLVM_CLANG_AST_PRETTY_PRINTER_H +#include "clang/Basic/LangOptions.h" + namespace llvm { class raw_ostream; } @@ -44,7 +46,7 @@ struct PrintingPolicy { unsigned Indentation : 8; /// \brief What language we're printing. - const LangOptions &LangOpts; + const LangOptions LangOpts; /// \brief Whether we should suppress printing of the actual specifiers for /// the given type or declaration. diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 2b3229e8fae9..d7bab80afc5e 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -14,8 +14,9 @@ #ifndef LLVM_CLANG_AST_LAYOUTINFO_H #define LLVM_CLANG_AST_LAYOUTINFO_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" namespace clang { @@ -32,93 +33,41 @@ namespace clang { /// ObjCInterfaceDecl. FIXME - Find appropriate name. /// These objects are managed by ASTContext. class ASTRecordLayout { - /// Size - Size of record in bits. - uint64_t Size; + /// Size - Size of record in characters. + CharUnits Size; - /// DataSize - Size of record in bits without tail padding. - uint64_t DataSize; + /// DataSize - Size of record in characters without tail padding. + CharUnits DataSize; /// FieldOffsets - Array of field offsets in bits. uint64_t *FieldOffsets; - // Alignment - Alignment of record in bits. - unsigned Alignment; + // Alignment - Alignment of record in characters. + CharUnits Alignment; // FieldCount - Number of fields. unsigned FieldCount; -public: - /// PrimaryBaseInfo - Contains info about a primary base. - struct PrimaryBaseInfo { - PrimaryBaseInfo() {} - - PrimaryBaseInfo(const CXXRecordDecl *Base, bool IsVirtual) - : Value(Base, Base && IsVirtual) {} - - /// Value - Points to the primary base. The single-bit value - /// will be non-zero when the primary base is virtual. - llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Value; - - /// getBase - Returns the primary base. - const CXXRecordDecl *getBase() const { return Value.getPointer(); } - - /// isVirtual - Returns whether the primary base is virtual or not. - bool isVirtual() const { return Value.getInt(); } - - friend bool operator==(const PrimaryBaseInfo &X, const PrimaryBaseInfo &Y) { - return X.Value == Y.Value; - } - }; - - /// primary_base_info_iterator - An iterator for iterating the primary base - /// class chain. - class primary_base_info_iterator { - /// Current - The current base class info. - PrimaryBaseInfo Current; - - public: - primary_base_info_iterator() {} - primary_base_info_iterator(PrimaryBaseInfo Info) : Current(Info) {} - - const PrimaryBaseInfo &operator*() const { return Current; } - - primary_base_info_iterator& operator++() { - const CXXRecordDecl *RD = Current.getBase(); - Current = RD->getASTContext().getASTRecordLayout(RD).getPrimaryBaseInfo(); - return *this; - } - - friend bool operator==(const primary_base_info_iterator &X, - const primary_base_info_iterator &Y) { - return X.Current == Y.Current; - } - friend bool operator!=(const primary_base_info_iterator &X, - const primary_base_info_iterator &Y) { - return !(X == Y); - } - }; - -private: /// CXXRecordLayoutInfo - Contains C++ specific layout information. struct CXXRecordLayoutInfo { - /// NonVirtualSize - The non-virtual size (in bits) of an object, which is + /// NonVirtualSize - The non-virtual size (in chars) of an object, which is /// the size of the object without virtual bases. - uint64_t NonVirtualSize; + CharUnits NonVirtualSize; - /// NonVirtualAlign - The non-virtual alignment (in bits) of an object, + /// NonVirtualAlign - The non-virtual alignment (in chars) of an object, /// which is the alignment of the object without virtual bases. - uint64_t NonVirtualAlign; + CharUnits NonVirtualAlign; /// SizeOfLargestEmptySubobject - The size of the largest empty subobject /// (either a base or a member). Will be zero if the class doesn't contain /// any empty subobjects. - uint64_t SizeOfLargestEmptySubobject; + CharUnits SizeOfLargestEmptySubobject; /// PrimaryBase - The primary base info for this record. - PrimaryBaseInfo PrimaryBase; + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase; /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) - typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy; + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// BaseOffsets - Contains a map from base classes to their offset. BaseOffsetsMapTy BaseOffsets; @@ -133,35 +82,35 @@ private: friend class ASTContext; - ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment, - unsigned datasize, const uint64_t *fieldoffsets, + ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, + CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount); // Constructor for C++ records. typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; - ASTRecordLayout(ASTContext &Ctx, - uint64_t size, unsigned alignment, uint64_t datasize, + ASTRecordLayout(const ASTContext &Ctx, + CharUnits size, CharUnits alignment, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, - uint64_t nonvirtualsize, unsigned nonvirtualalign, - uint64_t SizeOfLargestEmptySubobject, + CharUnits nonvirtualsize, CharUnits nonvirtualalign, + CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseIsVirtual, + bool IsPrimaryBaseVirtual, const BaseOffsetsMapTy& BaseOffsets, const BaseOffsetsMapTy& VBaseOffsets); ~ASTRecordLayout() {} void Destroy(ASTContext &Ctx); - + 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; } + /// getAlignment - Get the record alignment in characters. + CharUnits getAlignment() const { return Alignment; } - /// getSize - Get the record size in bits. - uint64_t getSize() const { return Size; } + /// getSize - Get the record size in characters. + CharUnits getSize() const { return Size; } /// getFieldCount - Get the number of fields in the layout. unsigned getFieldCount() const { return FieldCount; } @@ -174,75 +123,81 @@ public: } /// getDataSize() - Get the record data size, which is the record size - /// without tail padding, in bits. - uint64_t getDataSize() const { + /// without tail padding, in characters. + CharUnits getDataSize() const { return DataSize; } - /// getNonVirtualSize - Get the non-virtual size (in bits) of an object, + /// getNonVirtualSize - Get the non-virtual size (in chars) of an object, /// which is the size of the object without virtual bases. - uint64_t getNonVirtualSize() const { + CharUnits 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, + /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object, /// which is the alignment of the object without virtual bases. - unsigned getNonVirtualAlign() const { + CharUnits getNonVirtualAlign() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); return CXXInfo->NonVirtualAlign; } - /// getPrimaryBaseInfo - Get the primary base info. - const PrimaryBaseInfo &getPrimaryBaseInfo() const { + /// getPrimaryBase - Get the primary base for this record. + const CXXRecordDecl *getPrimaryBase() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); - return CXXInfo->PrimaryBase; + return CXXInfo->PrimaryBase.getPointer(); } - // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. - const CXXRecordDecl *getPrimaryBase() const { - return getPrimaryBaseInfo().getBase(); - } + /// isPrimaryBaseVirtual - Get whether the primary base for this record + /// is virtual or not. + bool isPrimaryBaseVirtual() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); - // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. - bool getPrimaryBaseWasVirtual() const { - return getPrimaryBaseInfo().isVirtual(); + return CXXInfo->PrimaryBase.getInt(); } - /// getBaseClassOffset - Get the offset, in bits, for the given base class. - uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const { + /// getBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits 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 { + /// getVBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits 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]; } - - uint64_t getSizeOfLargestEmptySubobject() const { + + /// getBaseClassOffsetInBits - Get the offset, in bits, for the given + /// base class. + uint64_t getBaseClassOffsetInBits(const CXXRecordDecl *Base) const { assert(CXXInfo && "Record layout does not have C++ specific info!"); - return CXXInfo->SizeOfLargestEmptySubobject; + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return getBaseClassOffset(Base).getQuantity() * + Base->getASTContext().getCharWidth(); } - primary_base_info_iterator primary_base_begin() const { + /// getVBaseClassOffsetInBits - Get the offset, in bits, for the given + /// base class. + uint64_t getVBaseClassOffsetInBits(const CXXRecordDecl *VBase) const { assert(CXXInfo && "Record layout does not have C++ specific info!"); - - return primary_base_info_iterator(getPrimaryBaseInfo()); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return getVBaseClassOffset(VBase).getQuantity() * + VBase->getASTContext().getCharWidth(); } - primary_base_info_iterator primary_base_end() const { + CharUnits getSizeOfLargestEmptySubobject() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); - - return primary_base_info_iterator(); + return CXXInfo->SizeOfLargestEmptySubobject; } }; diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 232e47b03ae5..921b799b94b5 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -143,6 +143,10 @@ public: /// \brief Return whether this visitor should recurse into /// template instantiations. bool shouldVisitTemplateInstantiations() const { return false; } + + /// \brief Return whether this visitor should recurse into the types of + /// TypeLocs. + bool shouldWalkTypesOfTypeLocs() const { return true; } /// \brief Recursively visit a statement or expression, by /// dispatching to Traverse*() based on the argument's dynamic type. @@ -211,7 +215,7 @@ public: /// be overridden for clients that need access to the name. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseConstructorInitializer(CXXBaseOrMemberInitializer *Init); + bool TraverseConstructorInitializer(CXXCtorInitializer *Init); // ---- Methods on Stmts ---- @@ -368,7 +372,7 @@ private: bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern); bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ; - bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, + bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, unsigned Count); bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); bool TraverseRecordHelper(RecordDecl *D); @@ -393,7 +397,7 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) { if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { switch (BinOp->getOpcode()) { #define OPERATOR(NAME) \ - case BO_##NAME: DISPATCH(Bin##PtrMemD, BinaryOperator, S); + case BO_##NAME: DISPATCH(Bin##NAME, BinaryOperator, S); BINOP_LIST() #undef OPERATOR @@ -438,7 +442,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ - case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, T.getTypePtr()); + case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, \ + const_cast<Type*>(T.getTypePtr())); #include "clang/AST/TypeNodes.def" } @@ -531,7 +536,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument( return getDerived().TraverseType(Arg.getAsType()); case TemplateArgument::Template: - return getDerived().TraverseTemplateName(Arg.getAsTemplate()); + case TemplateArgument::TemplateExpansion: + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); case TemplateArgument::Expression: return getDerived().TraverseStmt(Arg.getAsExpr()); @@ -566,7 +573,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc( } case TemplateArgument::Template: - return getDerived().TraverseTemplateName(Arg.getAsTemplate()); + case TemplateArgument::TemplateExpansion: + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); case TemplateArgument::Expression: return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); @@ -592,7 +601,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments( template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer( - CXXBaseOrMemberInitializer *Init) { + CXXCtorInitializer *Init) { // FIXME: recurse on TypeLoc of the base initializer if isBaseInitializer()? if (Init->isWritten()) TRY_TO(TraverseStmt(Init->getInit())); @@ -706,10 +715,15 @@ DEF_TRAVERSE_TYPE(DecltypeType, { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) +DEF_TRAVERSE_TYPE(AutoType, { + TRY_TO(TraverseType(T->getDeducedType())); + }) + DEF_TRAVERSE_TYPE(RecordType, { }) DEF_TRAVERSE_TYPE(EnumType, { }) DEF_TRAVERSE_TYPE(TemplateTypeParmType, { }) DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { }) DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); @@ -718,6 +732,14 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, { DEF_TRAVERSE_TYPE(InjectedClassNameType, { }) +DEF_TRAVERSE_TYPE(AttributedType, { + TRY_TO(TraverseType(T->getModifiedType())); + }) + +DEF_TRAVERSE_TYPE(ParenType, { + TRY_TO(TraverseType(T->getInnerType())); + }) + DEF_TRAVERSE_TYPE(ElaboratedType, { if (T->getQualifier()) { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); @@ -734,6 +756,10 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); }) +DEF_TRAVERSE_TYPE(PackExpansionType, { + TRY_TO(TraverseType(T->getPattern())); + }) + DEF_TRAVERSE_TYPE(ObjCInterfaceType, { }) DEF_TRAVERSE_TYPE(ObjCObjectType, { @@ -752,14 +778,15 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, { // ----------------- TypeLoc traversal ----------------- // This macro makes available a variable TL, the passed-in TypeLoc. -// It calls WalkUpFrom* for the Type in the given TypeLoc, in addition -// to WalkUpFrom* for the TypeLoc itself, such that existing clients -// that override the WalkUpFrom*Type() and/or Visit*Type() methods +// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc, +// in addition to WalkUpFrom* for the TypeLoc itself, such that existing +// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods // continue to work. #define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ template<typename Derived> \ bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \ - TRY_TO(WalkUpFrom##TYPE(TL.getTypePtr())); \ + if (getDerived().shouldWalkTypesOfTypeLocs()) \ + TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE*>(TL.getTypePtr()))); \ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ { CODE; } \ return true; \ @@ -867,22 +894,16 @@ DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, { TRY_TO(TraverseTypeLoc(TL.getResultLoc())); }) -// FIXME: location of arguments, exception specifications (attributes?) -// Note that we have the ParmVarDecl's here. Do we want to use them? +// FIXME: location of exception specifications (attributes?) DEF_TRAVERSE_TYPELOC(FunctionProtoType, { TRY_TO(TraverseTypeLoc(TL.getResultLoc())); - FunctionProtoType *T = TL.getTypePtr(); -/* + const FunctionProtoType *T = TL.getTypePtr(); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { TRY_TO(TraverseDecl(TL.getArg(I))); } -*/ - for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), - AEnd = T->arg_type_end(); - A != AEnd; ++A) { - TRY_TO(TraverseType(*A)); - } + for (FunctionProtoType::exception_iterator E = T->exception_begin(), EEnd = T->exception_end(); E != EEnd; ++E) { @@ -906,10 +927,15 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, { TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); }) +DEF_TRAVERSE_TYPELOC(AutoType, { + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); + }) + DEF_TRAVERSE_TYPELOC(RecordType, { }) DEF_TRAVERSE_TYPELOC(EnumType, { }) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { }) DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { }) // FIXME: use the loc for the template name? DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { @@ -921,6 +947,14 @@ DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { DEF_TRAVERSE_TYPELOC(InjectedClassNameType, { }) +DEF_TRAVERSE_TYPELOC(ParenType, { + TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); + }) + +DEF_TRAVERSE_TYPELOC(AttributedType, { + TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); + }) + // FIXME: use the sourceloc on qualifier? DEF_TRAVERSE_TYPELOC(ElaboratedType, { if (TL.getTypePtr()->getQualifier()) { @@ -941,6 +975,10 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { } }) +DEF_TRAVERSE_TYPELOC(PackExpansionType, { + TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); + }) + DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { }) DEF_TRAVERSE_TYPELOC(ObjCObjectType, { @@ -1001,11 +1039,18 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, { }) DEF_TRAVERSE_DECL(FriendDecl, { - TRY_TO(TraverseDecl(D->getFriendDecl())); + // Friend is either decl or a type. + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); }) DEF_TRAVERSE_DECL(FriendTemplateDecl, { - TRY_TO(TraverseDecl(D->getFriendDecl())); + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) { TemplateParameterList *TPL = D->getTemplateParameterList(I); for (TemplateParameterList::iterator ITPL = TPL->begin(), @@ -1051,6 +1096,11 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, { return true; }) +DEF_TRAVERSE_DECL(LabelDecl, { + // There is no code in a LabelDecl. +}) + + DEF_TRAVERSE_DECL(NamespaceDecl, { // Code in an unnamed namespace shows up automatically in // decls_begin()/decls_end(). Thus we don't need to recurse on @@ -1082,7 +1132,9 @@ DEF_TRAVERSE_DECL(ObjCProtocolDecl, { }) DEF_TRAVERSE_DECL(ObjCMethodDecl, { - // FIXME: implement + // We don't traverse nodes in param_begin()/param_end(), as they + // appear in decls_begin()/decls_end() and thus are handled. + TRY_TO(TraverseStmt(D->getBody())); }) DEF_TRAVERSE_DECL(ObjCPropertyDecl, { @@ -1175,7 +1227,7 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, { if (D->isThisDeclarationADefinition()) TRY_TO(TraverseClassInstantiations(D, D)); } - + // Note that getInstantiatedFromMemberTemplate() is just a link // from a template instantiation back to the template from which // it was instantiated, and thus should not be traversed. @@ -1208,10 +1260,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations( assert(false && "Unknown specialization kind."); } } - + return true; } - + DEF_TRAVERSE_DECL(FunctionTemplateDecl, { TRY_TO(TraverseDecl(D->getTemplatedDecl())); TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); @@ -1251,7 +1303,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { }) DEF_TRAVERSE_DECL(TypedefDecl, { - TRY_TO(TraverseType(D->getUnderlyingType())); + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); // We shouldn't traverse D->getTypeForDecl(); it's a result of // declaring the typedef, not something that was written in the // source. @@ -1282,11 +1334,7 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper( RecordDecl *D) { // We shouldn't traverse D->getTypeForDecl(); it's a result of // declaring the type, not something that was written in the source. - // - // The anonymous struct or union object is the variable or field - // whose type is the anonymous struct or union. We shouldn't - // traverse D->getAnonymousStructOrUnionObject(), as it's not - // something that is explicitly written in the source. + TRY_TO(TraverseNestedNameSpecifier(D->getQualifier())); return true; } @@ -1380,6 +1428,8 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, { TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameSpecifier())); }) +DEF_TRAVERSE_DECL(IndirectFieldDecl, {}) + template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) { TRY_TO(TraverseNestedNameSpecifier(D->getQualifier())); @@ -1412,47 +1462,11 @@ template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { TRY_TO(TraverseNestedNameSpecifier(D->getQualifier())); - // Visit the function type itself, which can be either - // FunctionNoProtoType or FunctionProtoType, or a typedef. If it's - // not a Function*ProtoType, then it can't have a body or arguments, - // so we have to do less work. - Type *FuncType = D->getType().getTypePtr(); - if (FunctionProtoType *FuncProto = dyn_cast<FunctionProtoType>(FuncType)) { - if (D->isThisDeclarationADefinition()) { - // Don't call Traverse*, or the result type and parameter types - // will be double counted. - TRY_TO(WalkUpFromFunctionProtoType(FuncProto)); - } else { - // This works around a bug in Clang that does not add the parameters - // to decls_begin/end for function declarations (as opposed to - // definitions): - // http://llvm.org/PR7442 - // We work around this here by traversing the function type. - // This isn't perfect because we don't traverse the default - // values, if any. It also may not interact great with - // templates. But it's the best we can do until the bug is - // fixed. - // FIXME: replace the entire 'if' statement with - // TRY_TO(WalkUpFromFunctionProtoType(FuncProto)); - // when the bug is fixed. - TRY_TO(TraverseFunctionProtoType(FuncProto)); - return true; - } - } else if (FunctionNoProtoType *FuncNoProto = - dyn_cast<FunctionNoProtoType>(FuncType)) { - // Don't call Traverse*, or the result type will be double - // counted. - TRY_TO(WalkUpFromFunctionNoProtoType(FuncNoProto)); - } else { // a typedef type, or who knows what - assert(!D->isThisDeclarationADefinition() && "Unexpected function type"); - TRY_TO(TraverseType(D->getType())); - return true; - } - - TRY_TO(TraverseType(D->getResultType())); - // If we're an explicit template specialization, iterate over the - // template args that were explicitly specified. + // template args that were explicitly specified. If we were doing + // this in typing order, we'd do it between the return type and + // the function args, but both are handled by the FunctionTypeLoc + // above, so we have to choose one side. I've decided to do before. if (const FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo()) { if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared && @@ -1467,28 +1481,11 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { } } - for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) { - TRY_TO(TraverseDecl(*I)); - } - - if (FunctionProtoType *FuncProto = dyn_cast<FunctionProtoType>(FuncType)) { - if (D->isThisDeclarationADefinition()) { - // This would be visited if we called TraverseType(D->getType()) - // above, but we don't (at least, not in the - // declaration-is-a-definition case), in order to avoid duplicate - // visiting for parameters. (We need to check parameters here, - // rather than letting D->getType() do it, so we visit default - // parameter values). So we need to re-do some of the work the - // type would do. - for (FunctionProtoType::exception_iterator - E = FuncProto->exception_begin(), - EEnd = FuncProto->exception_end(); - E != EEnd; ++E) { - TRY_TO(TraverseType(*E)); - } - } - } + // Visit the function type itself, which can be either + // FunctionNoProtoType or FunctionProtoType, or a typedef. This + // also covers the return type and the function parameters, + // including exception specifications. + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { // Constructor initializers. @@ -1554,7 +1551,7 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, { DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { // A non-type template parameter, e.g. "S" in template<int S> class Foo ... - TRY_TO(TraverseVarHelper(D)); + TRY_TO(TraverseDeclaratorHelper(D)); TRY_TO(TraverseStmt(D->getDefaultArgument())); }) @@ -1577,12 +1574,11 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { // ----------------- Stmt traversal ----------------- // // For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating -// over the children defined in child_begin/child_end (every stmt -// defines these, though sometimes the range is empty). Each -// individual Traverse* method only needs to worry about children -// other than those. To see what child_begin()/end() does for a given -// class, see, e.g., -// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html +// over the children defined in children() (every stmt defines these, +// though sometimes the range is empty). Each individual Traverse* +// method only needs to worry about children other than those. To see +// what children() does for a given class, see, e.g., +// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html // This macro makes available a variable S, the passed-in stmt. #define DEF_TRAVERSE_STMT(STMT, CODE) \ @@ -1590,9 +1586,8 @@ template<typename Derived> \ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \ TRY_TO(WalkUpFrom##STMT(S)); \ { CODE; } \ - for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); \ - C != CEnd; ++C) { \ - TRY_TO(TraverseStmt(*C)); \ + for (Stmt::child_range range = S->children(); range; ++range) { \ + TRY_TO(TraverseStmt(*range)); \ } \ return true; \ } @@ -1608,12 +1603,12 @@ DEF_TRAVERSE_STMT(AsmStmt, { for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) { TRY_TO(TraverseStmt(S->getClobber(I))); } - // child_begin()/end() iterates over inputExpr and outputExpr. + // children() iterates over inputExpr and outputExpr. }) DEF_TRAVERSE_STMT(CXXCatchStmt, { TRY_TO(TraverseDecl(S->getExceptionDecl())); - // child_begin()/end() iterates over the handler block. + // children() iterates over the handler block. }) DEF_TRAVERSE_STMT(DeclStmt, { @@ -1621,11 +1616,11 @@ DEF_TRAVERSE_STMT(DeclStmt, { I != E; ++I) { TRY_TO(TraverseDecl(*I)); } - // Suppress the default iteration over child_begin/end by + // Suppress the default iteration over children() by // returning. Here's why: A DeclStmt looks like 'type var [= // initializer]'. The decls above already traverse over the // initializers, so we don't have to do it again (which - // child_begin/end would do). + // children() would do). return true; }) @@ -1652,17 +1647,16 @@ DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { }) DEF_TRAVERSE_STMT(ObjCAtTryStmt, { }) DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { }) DEF_TRAVERSE_STMT(ReturnStmt, { }) -DEF_TRAVERSE_STMT(SwitchCase, { }) DEF_TRAVERSE_STMT(SwitchStmt, { }) DEF_TRAVERSE_STMT(WhileStmt, { }) DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { + TRY_TO(TraverseNestedNameSpecifier(S->getQualifier())); if (S->hasExplicitTemplateArgs()) { TRY_TO(TraverseTemplateArgumentLocsHelper( S->getTemplateArgs(), S->getNumTemplateArgs())); } - TRY_TO(TraverseNestedNameSpecifier(S->getQualifier())); }) DEF_TRAVERSE_STMT(DeclRefExpr, { @@ -1695,27 +1689,27 @@ DEF_TRAVERSE_STMT(ImplicitCastExpr, { }) DEF_TRAVERSE_STMT(CStyleCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXConstCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXDynamicCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXStaticCastExpr, { - TRY_TO(TraverseType(S->getTypeAsWritten())); + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) // InitListExpr is a tricky one, because we want to do all our work on @@ -1729,9 +1723,8 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) { S = Syn; TRY_TO(WalkUpFromInitListExpr(S)); // All we need are the default actions. FIXME: use a helper function. - for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); - C != CEnd; ++C) { - TRY_TO(TraverseStmt(*C)); + for (Stmt::child_range range = S->children(); range; ++range) { + TRY_TO(TraverseStmt(*range)); } return true; } @@ -1739,12 +1732,12 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) { DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, { // This is called for code like 'return T()' where T is a built-in // (i.e. non-class) type. - if (!S->isImplicit()) - TRY_TO(TraverseType(S->getType())); + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); }) DEF_TRAVERSE_STMT(CXXNewExpr, { - TRY_TO(TraverseType(S->getAllocatedType())); + // The child-iterator will pick up the other arguments. + TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc())); }) DEF_TRAVERSE_STMT(OffsetOfExpr, { @@ -1769,15 +1762,43 @@ DEF_TRAVERSE_STMT(CXXTypeidExpr, { TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); }) -DEF_TRAVERSE_STMT(TypesCompatibleExpr, { - TRY_TO(TraverseTypeLoc(S->getArgTInfo1()->getTypeLoc())); - TRY_TO(TraverseTypeLoc(S->getArgTInfo2()->getTypeLoc())); +DEF_TRAVERSE_STMT(CXXUuidofExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); }) DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, { - TRY_TO(TraverseType(S->getQueriedType())); + TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, { + TRY_TO(TraverseTypeLoc(S->getLhsTypeSourceInfo()->getTypeLoc())); + TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(VAArgExpr, { + // The child-iterator will pick up the expression argument. + TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc())); }) +DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { + // This is called for code like 'return T()' where T is a class type. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { + // This is called for code like 'T()', where T is a template argument. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +// These expressions all might take explicit template arguments. +// We traverse those if so. FIXME: implement these. +DEF_TRAVERSE_STMT(CXXConstructExpr, { }) +DEF_TRAVERSE_STMT(CallExpr, { }) +DEF_TRAVERSE_STMT(CXXMemberCallExpr, { }) + // These exprs (most of them), do not need any action except iterating // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, { }) @@ -1790,53 +1811,64 @@ DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { }) DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { }) DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { }) DEF_TRAVERSE_STMT(CXXDeleteExpr, { }) -DEF_TRAVERSE_STMT(CXXExprWithTemporaries, { }) +DEF_TRAVERSE_STMT(ExprWithCleanups, { }) DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { }) -DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { }) +DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { + TRY_TO(TraverseNestedNameSpecifier(S->getQualifier())); + if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo()) + TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc())); + if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo()) + TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc())); +}) DEF_TRAVERSE_STMT(CXXThisExpr, { }) DEF_TRAVERSE_STMT(CXXThrowExpr, { }) -DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { }) DEF_TRAVERSE_STMT(DesignatedInitExpr, { }) DEF_TRAVERSE_STMT(ExtVectorElementExpr, { }) DEF_TRAVERSE_STMT(GNUNullExpr, { }) DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { }) DEF_TRAVERSE_STMT(ObjCEncodeExpr, { }) -DEF_TRAVERSE_STMT(ObjCImplicitSetterGetterRefExpr, { }) DEF_TRAVERSE_STMT(ObjCIsaExpr, { }) DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { }) DEF_TRAVERSE_STMT(ObjCMessageExpr, { }) DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { }) DEF_TRAVERSE_STMT(ObjCProtocolExpr, { }) DEF_TRAVERSE_STMT(ObjCSelectorExpr, { }) -DEF_TRAVERSE_STMT(ObjCSuperExpr, { }) DEF_TRAVERSE_STMT(ParenExpr, { }) DEF_TRAVERSE_STMT(ParenListExpr, { }) DEF_TRAVERSE_STMT(PredefinedExpr, { }) DEF_TRAVERSE_STMT(ShuffleVectorExpr, { }) DEF_TRAVERSE_STMT(StmtExpr, { }) -DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { }) -DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { }) -DEF_TRAVERSE_STMT(VAArgExpr, { - // The child-iterator will pick up the expression argument. - TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc())); - }) -DEF_TRAVERSE_STMT(CXXConstructExpr, { }) - -DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { - // This is called for code like 'return T()' where T is a class type. - TRY_TO(TraverseType(S->getType())); - }) +DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { + TRY_TO(TraverseNestedNameSpecifier(S->getQualifier())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { + TRY_TO(TraverseNestedNameSpecifier(S->getQualifier())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) -DEF_TRAVERSE_STMT(CallExpr, { }) -DEF_TRAVERSE_STMT(CXXMemberCallExpr, { }) DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { }) +DEF_TRAVERSE_STMT(OpaqueValueExpr, { }) +DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { }) // These operators (all of them) do not need any action except // iterating over the children. +DEF_TRAVERSE_STMT(BinaryConditionalOperator, { }) DEF_TRAVERSE_STMT(ConditionalOperator, { }) DEF_TRAVERSE_STMT(UnaryOperator, { }) DEF_TRAVERSE_STMT(BinaryOperator, { }) DEF_TRAVERSE_STMT(CompoundAssignOperator, { }) +DEF_TRAVERSE_STMT(CXXNoexceptExpr, { }) +DEF_TRAVERSE_STMT(PackExpansionExpr, { }) +DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, { }) @@ -1861,7 +1893,6 @@ DEF_TRAVERSE_STMT(ObjCStringLiteral, { }) // http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html // http://clang.llvm.org/doxygen/classclang_1_1SizeOfAlignOfExpr.html // http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html -// http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html // Every class that has getQualifier. #undef DEF_TRAVERSE_STMT diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index ba778293ba2d..e87ca78d635a 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -109,25 +109,7 @@ public: /// \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. Make sure that this is actually the most recent - // redeclaration, or we can build invalid chains. If the most recent - // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. - RedeclLink = PreviousDeclLink(llvm::cast<decl_type>( - PrevDecl->getMostRecentDeclaration())); - 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)); - } + void setPreviousDeclaration(decl_type *PrevDecl); /// \brief Iterates through all the redeclarations of the same decl. class redecl_iterator { diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 62a6b6463df5..7ede9ce323f4 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -20,7 +20,6 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtIterator.h" #include "clang/AST/DeclGroup.h" -#include "clang/AST/FullExpr.h" #include "llvm/ADT/SmallVector.h" #include "clang/AST/ASTContext.h" #include <string> @@ -104,13 +103,7 @@ public: first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class #define ABSTRACT_STMT(STMT) #include "clang/AST/StmtNodes.inc" -}; -private: - /// \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: @@ -122,6 +115,77 @@ protected: assert(0 && "Stmts cannot be released with regular 'delete'."); } + class StmtBitfields { + friend class Stmt; + + /// \brief The statement class. + unsigned sClass : 8; + }; + enum { NumStmtBits = 8 }; + + class CompoundStmtBitfields { + friend class CompoundStmt; + unsigned : NumStmtBits; + + unsigned NumStmts : 32 - NumStmtBits; + }; + + class ExprBitfields { + friend class Expr; + friend class DeclRefExpr; // computeDependence + friend class InitListExpr; // ctor + friend class DesignatedInitExpr; // ctor + friend class BlockDeclRefExpr; // ctor + friend class ASTStmtReader; // deserialization + friend class CXXNewExpr; // ctor + friend class DependentScopeDeclRefExpr; // ctor + friend class CXXConstructExpr; // ctor + friend class CallExpr; // ctor + friend class OffsetOfExpr; // ctor + friend class ObjCMessageExpr; // ctor + friend class ShuffleVectorExpr; // ctor + friend class ParenListExpr; // ctor + friend class CXXUnresolvedConstructExpr; // ctor + friend class CXXDependentScopeMemberExpr; // ctor + friend class OverloadExpr; // ctor + unsigned : NumStmtBits; + + unsigned ValueKind : 2; + unsigned ObjectKind : 2; + unsigned TypeDependent : 1; + unsigned ValueDependent : 1; + unsigned ContainsUnexpandedParameterPack : 1; + }; + enum { NumExprBits = 15 }; + + class CastExprBitfields { + friend class CastExpr; + unsigned : NumExprBits; + + unsigned Kind : 6; + unsigned BasePathSize : 32 - 6 - NumExprBits; + }; + + class CallExprBitfields { + friend class CallExpr; + unsigned : NumExprBits; + + unsigned NumPreArgs : 1; + }; + + union { + // FIXME: this is wasteful on 64-bit platforms. + void *Aligner; + + StmtBitfields StmtBits; + CompoundStmtBitfields CompoundStmtBits; + ExprBitfields ExprBits; + CastExprBitfields CastExprBits; + CallExprBitfields CallExprBits; + }; + + friend class ASTStmtReader; + public: // Only allow allocation of Stmts using the allocator in ASTContext // or by doing a placement new. @@ -152,44 +216,27 @@ public: protected: /// \brief Construct an empty statement. - explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC), RefCount(1) { + explicit Stmt(StmtClass SC, EmptyShell) { + StmtBits.sClass = SC; if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); } public: - Stmt(StmtClass SC) : sClass(SC), RefCount(1) { + Stmt(StmtClass SC) { + StmtBits.sClass = SC; if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); } - virtual ~Stmt() {} - -#ifndef NDEBUG - /// \brief True if this statement's refcount is in a valid state. - /// Should be used only in assertions. - bool isRetained() const { - return (RefCount >= 1); - } -#endif - - /// \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; + return static_cast<StmtClass>(StmtBits.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. - virtual SourceRange getSourceRange() const = 0; + SourceRange getSourceRange() const; + SourceLocation getLocStart() const { return getSourceRange().getBegin(); } SourceLocation getLocEnd() const { return getSourceRange().getEnd(); } @@ -236,22 +283,25 @@ public: /// within CFGs. bool hasImplicitControlFlow() const; - /// Child Iterators: All subclasses must implement child_begin and child_end - /// to permit easy iteration over the substatements/subexpessions of an - /// AST node. This permits easy iteration over all nodes in the AST. + /// Child Iterators: All subclasses must implement 'children' + /// to permit easy iteration over the substatements/subexpessions of an + /// 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; + typedef StmtRange child_range; + typedef ConstStmtRange const_child_range; - const_child_iterator child_begin() const { - return const_child_iterator(const_cast<Stmt*>(this)->child_begin()); + child_range children(); + const_child_range children() const { + return const_cast<Stmt*>(this)->children(); } - const_child_iterator child_end() const { - return const_child_iterator(const_cast<Stmt*>(this)->child_end()); - } + child_iterator child_begin() { return children().first; } + child_iterator child_end() { return children().second; } + + const_child_iterator child_begin() const { return children().first; } + const_child_iterator child_end() const { return children().second; } /// \brief Produce a unique representation of the given statement. /// @@ -265,7 +315,7 @@ public: /// 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, + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical); }; @@ -314,8 +364,10 @@ public: static bool classof(const DeclStmt *) { return true; } // Iterators over subexpressions. - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(child_iterator(DG.begin(), DG.end()), + child_iterator(DG.end(), DG.end())); + } typedef DeclGroupRef::iterator decl_iterator; typedef DeclGroupRef::const_iterator const_decl_iterator; @@ -330,8 +382,16 @@ public: /// class NullStmt : public Stmt { SourceLocation SemiLoc; + + /// \brief Whether the null statement was preceded by an empty macro, e.g: + /// @code + /// #define CALL(x) + /// CALL(0); + /// @endcode + bool LeadingEmptyMacro; public: - NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {} + NullStmt(SourceLocation L, bool LeadingEmptyMacro = false) + : Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {} /// \brief Build an empty null statement. explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { } @@ -339,55 +399,66 @@ public: SourceLocation getSemiLoc() const { return SemiLoc; } void setSemiLoc(SourceLocation L) { SemiLoc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); } + bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro; } + + SourceRange getSourceRange() const { return SourceRange(SemiLoc); } 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(); + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// CompoundStmt - This represents a group of statements like { stmt stmt }. /// class CompoundStmt : public Stmt { Stmt** Body; - unsigned NumStmts; SourceLocation LBracLoc, RBracLoc; public: - CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts, - SourceLocation LB, SourceLocation RB) - : Stmt(CompoundStmtClass), NumStmts(numStmts), LBracLoc(LB), RBracLoc(RB) { + CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned NumStmts, + SourceLocation LB, SourceLocation RB) + : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { + CompoundStmtBits.NumStmts = NumStmts; + if (NumStmts == 0) { Body = 0; return; } Body = new (C) Stmt*[NumStmts]; - memcpy(Body, StmtStart, numStmts * sizeof(*Body)); + memcpy(Body, StmtStart, NumStmts * sizeof(*Body)); } // \brief Build an empty compound statement. explicit CompoundStmt(EmptyShell Empty) - : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { } + : Stmt(CompoundStmtClass, Empty), Body(0) { + CompoundStmtBits.NumStmts = 0; + } void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); - bool body_empty() const { return NumStmts == 0; } - unsigned size() const { return NumStmts; } + bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } + unsigned size() const { return CompoundStmtBits.NumStmts; } typedef Stmt** body_iterator; body_iterator body_begin() { return Body; } - body_iterator body_end() { return Body + NumStmts; } - Stmt *body_back() { return NumStmts ? Body[NumStmts-1] : 0; } + body_iterator body_end() { return Body + size(); } + Stmt *body_back() { return !body_empty() ? Body[size()-1] : 0; } + + void setLastStmt(Stmt *S) { + assert(!body_empty() && "setLastStmt"); + Body[size()-1] = S; + } typedef Stmt* const * const_body_iterator; const_body_iterator body_begin() const { return Body; } - const_body_iterator body_end() const { return Body + NumStmts; } - const Stmt *body_back() const { return NumStmts ? Body[NumStmts-1] : 0; } + const_body_iterator body_end() const { return Body + size(); } + const Stmt *body_back() const { return !body_empty() ? Body[size()-1] : 0; } typedef std::reverse_iterator<body_iterator> reverse_body_iterator; reverse_body_iterator body_rbegin() { @@ -408,7 +479,7 @@ public: return const_reverse_body_iterator(body_begin()); } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(LBracLoc, RBracLoc); } @@ -423,8 +494,9 @@ public: static bool classof(const CompoundStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts); + } }; // SwitchCase is the base class for CaseStmt and DefaultStmt, @@ -443,17 +515,15 @@ public: void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } - Stmt *getSubStmt() { return v_getSubStmt(); } + Stmt *getSubStmt(); - virtual SourceRange getSourceRange() const { return SourceRange(); } + SourceRange getSourceRange() const { return SourceRange(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CaseStmtClass || - T->getStmtClass() == DefaultStmtClass; + T->getStmtClass() == DefaultStmtClass; } static bool classof(const SwitchCase *) { return true; } -protected: - virtual Stmt* v_getSubStmt() = 0; }; class CaseStmt : public SwitchCase { @@ -463,8 +533,6 @@ class CaseStmt : public SwitchCase { SourceLocation CaseLoc; SourceLocation EllipsisLoc; SourceLocation ColonLoc; - - virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, SourceLocation ellipsisLoc, SourceLocation colonLoc) @@ -504,7 +572,7 @@ public: void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } - virtual SourceRange getSourceRange() const { + 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())) @@ -518,15 +586,15 @@ public: static bool classof(const CaseStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } }; class DefaultStmt : public SwitchCase { Stmt* SubStmt; SourceLocation DefaultLoc; SourceLocation ColonLoc; - virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL), @@ -544,7 +612,7 @@ public: SourceLocation getColonLoc() const { return ColonLoc; } void setColonLoc(SourceLocation L) { ColonLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(DefaultLoc, SubStmt->getLocEnd()); } static bool classof(const Stmt *T) { @@ -553,42 +621,43 @@ public: static bool classof(const DefaultStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&SubStmt, &SubStmt+1); } }; + +/// LabelStmt - Represents a label, which has a substatement. For example: +/// foo: return; +/// class LabelStmt : public Stmt { - IdentifierInfo *Label; + LabelDecl *TheDecl; Stmt *SubStmt; SourceLocation IdentLoc; public: - LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) - : Stmt(LabelStmtClass), Label(label), - SubStmt(substmt), IdentLoc(IL) {} + LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt) + : Stmt(LabelStmtClass), TheDecl(D), 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; } + LabelDecl *getDecl() const { return TheDecl; } + void setDecl(LabelDecl *D) { TheDecl = D; } const char *getName() const; Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } void setIdentLoc(SourceLocation L) { IdentLoc = L; } void setSubStmt(Stmt *SS) { SubStmt = SS; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(IdentLoc, SubStmt->getLocEnd()); } + child_range children() { return child_range(&SubStmt, &SubStmt+1); } + 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(); }; @@ -635,22 +704,23 @@ public: SourceLocation getElseLoc() const { return ElseLoc; } void setElseLoc(SourceLocation L) { ElseLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { if (SubExprs[ELSE]) return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); else return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd()); } + // Iterators over subexpressions. The iterators will include iterating + // over the initialization expression referenced by the condition variable. + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == IfStmtClass; } static bool classof(const IfStmt *) { return true; } - - // Iterators over subexpressions. The iterators will include iterating - // over the initialization expression referenced by the condition variable. - virtual child_iterator child_begin(); - virtual child_iterator child_end(); }; /// SwitchStmt - This represents a 'switch' stmt. @@ -662,6 +732,11 @@ class SwitchStmt : public Stmt { SwitchCase *FirstCase; SourceLocation SwitchLoc; + /// If the SwitchStmt is a switch on an enum value, this records whether + /// all the enum values were covered by CaseStmts. This value is meant to + /// be a hint for possible clients. + unsigned AllEnumCasesCovered : 1; + public: SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond); @@ -705,21 +780,34 @@ public: } 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 { + + /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a + /// switch over an enum value then all cases have been explicitly covered. + void setAllEnumCasesCovered() { + AllEnumCasesCovered = 1; + } + + /// Returns true if the SwitchStmt is a switch of an enum value and all cases + /// have been explicitly covered. + bool isAllEnumCasesCovered() const { + return (bool) AllEnumCasesCovered; + } + + SourceRange getSourceRange() const { return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); } + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + 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(); }; @@ -757,7 +845,7 @@ public: SourceLocation getWhileLoc() const { return WhileLoc; } void setWhileLoc(SourceLocation L) { WhileLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); } static bool classof(const Stmt *T) { @@ -766,14 +854,15 @@ public: static bool classof(const WhileStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } }; /// DoStmt - This represents a 'do/while' stmt. /// class DoStmt : public Stmt { - enum { COND, BODY, END_EXPR }; + enum { BODY, COND, END_EXPR }; Stmt* SubExprs[END_EXPR]; SourceLocation DoLoc; SourceLocation WhileLoc; @@ -805,7 +894,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(DoLoc, RParenLoc); } static bool classof(const Stmt *T) { @@ -814,8 +903,9 @@ public: static bool classof(const DoStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } }; @@ -870,7 +960,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); } static bool classof(const Stmt *T) { @@ -879,32 +969,33 @@ public: static bool classof(const ForStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } }; /// GotoStmt - This represents a direct goto. /// class GotoStmt : public Stmt { - LabelStmt *Label; + LabelDecl *Label; SourceLocation GotoLoc; SourceLocation LabelLoc; public: - GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) + GotoStmt(LabelDecl *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) { } - LabelStmt *getLabel() const { return Label; } - void setLabel(LabelStmt *S) { Label = S; } + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *D) { Label = D; } SourceLocation getGotoLoc() const { return GotoLoc; } void setGotoLoc(SourceLocation L) { GotoLoc = L; } SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(GotoLoc, LabelLoc); } static bool classof(const Stmt *T) { @@ -913,8 +1004,7 @@ public: static bool classof(const GotoStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// IndirectGotoStmt - This represents an indirect goto. @@ -938,11 +1028,18 @@ public: void setStarLoc(SourceLocation L) { StarLoc = L; } SourceLocation getStarLoc() const { return StarLoc; } - Expr *getTarget(); - const Expr *getTarget() const; + Expr *getTarget() { return reinterpret_cast<Expr*>(Target); } + const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);} void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } - virtual SourceRange getSourceRange() const { + /// getConstantTarget - Returns the fixed target of this indirect + /// goto, if one exists. + LabelDecl *getConstantTarget(); + const LabelDecl *getConstantTarget() const { + return const_cast<IndirectGotoStmt*>(this)->getConstantTarget(); + } + + SourceRange getSourceRange() const { return SourceRange(GotoLoc, Target->getLocEnd()); } @@ -952,8 +1049,7 @@ public: static bool classof(const IndirectGotoStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Target, &Target+1); } }; @@ -970,7 +1066,7 @@ public: SourceLocation getContinueLoc() const { return ContinueLoc; } void setContinueLoc(SourceLocation L) { ContinueLoc = L; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(ContinueLoc); } @@ -980,8 +1076,7 @@ public: static bool classof(const ContinueStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; /// BreakStmt - This represents a break. @@ -997,7 +1092,7 @@ public: SourceLocation getBreakLoc() const { return BreakLoc; } void setBreakLoc(SourceLocation L) { BreakLoc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); } + SourceRange getSourceRange() const { return SourceRange(BreakLoc); } static bool classof(const Stmt *T) { return T->getStmtClass() == BreakStmtClass; @@ -1005,8 +1100,7 @@ public: static bool classof(const BreakStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(); } }; @@ -1050,7 +1144,7 @@ public: const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == ReturnStmtClass; @@ -1058,8 +1152,10 @@ public: static bool classof(const ReturnStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + if (RetExpr) return child_range(&RetExpr, &RetExpr+1); + return child_range(); + } }; /// AsmStmt - This represents a GNU inline-assembly statement extension. @@ -1257,7 +1353,7 @@ public: StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AsmLoc, RParenLoc); } @@ -1304,10 +1400,9 @@ public: return &Exprs[0] + NumOutputs; } - // Child iterators - - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs); + } }; } // end namespace clang diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 0508f35e48e8..f08815fd562d 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -37,7 +37,7 @@ public: CXXCatchStmt(EmptyShell Empty) : Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {} - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(CatchLoc, HandlerBlock->getLocEnd()); } @@ -51,8 +51,7 @@ public: } static bool classof(const CXXCatchStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); } friend class ASTStmtReader; }; @@ -84,7 +83,7 @@ public: static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty, unsigned numHandlers); - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(getTryLoc(), getEndLoc()); } @@ -113,8 +112,9 @@ public: } static bool classof(const CXXTryStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(getStmts(), getStmts() + getNumHandlers() + 1); + } friend class ASTStmtReader; }; diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index 4da2e3474b1c..851c001adc54 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -1,4 +1,4 @@ -//===--- StmtIterator.h - Iterators for Statements ------------------------===// +//===--- StmtIterator.h - Iterators for Statements --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_AST_STMT_ITR_H #define LLVM_CLANG_AST_STMT_ITR_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cassert> #include <cstddef> #include <iterator> @@ -51,11 +51,11 @@ protected: return (RawVAPtr & Flags) == 0; } - VariableArrayType* getVAPtr() const { - return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags); + const VariableArrayType *getVAPtr() const { + return reinterpret_cast<const VariableArrayType*>(RawVAPtr & ~Flags); } - void setVAPtr(VariableArrayType* P) { + void setVAPtr(const VariableArrayType *P) { assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); } @@ -68,7 +68,7 @@ protected: StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {} StmtIteratorBase(Decl *d, Stmt **s); - StmtIteratorBase(VariableArrayType *t); + StmtIteratorBase(const VariableArrayType *t); StmtIteratorBase(Decl **dgi, Decl **dge); StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {} }; @@ -86,7 +86,7 @@ public: StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {} StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {} StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {} - StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {} + StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {} DERIVED& operator++() { if (inDecl() || inDeclGroup()) { @@ -130,7 +130,7 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { StmtIterator(Decl** dgi, Decl** dge) : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} - StmtIterator(VariableArrayType* t) + StmtIterator(const VariableArrayType *t) : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} StmtIterator(Decl* D, Stmt **s = 0) @@ -146,6 +146,86 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} }; +/// A range of statement iterators. +/// +/// This class provides some extra functionality beyond std::pair +/// in order to allow the following idiom: +/// for (StmtRange range = stmt->children(); range; ++range) +struct StmtRange : std::pair<StmtIterator,StmtIterator> { + StmtRange() {} + StmtRange(const StmtIterator &begin, const StmtIterator &end) + : std::pair<StmtIterator,StmtIterator>(begin, end) {} + + bool empty() const { return first == second; } + operator bool() const { return !empty(); } + + Stmt *operator->() const { return first.operator->(); } + Stmt *&operator*() const { return first.operator*(); } + + StmtRange &operator++() { + assert(!empty() && "incrementing on empty range"); + ++first; + return *this; + } + + StmtRange operator++(int) { + assert(!empty() && "incrementing on empty range"); + StmtRange copy = *this; + ++first; + return copy; + } + + friend const StmtIterator &begin(const StmtRange &range) { + return range.first; + } + friend const StmtIterator &end(const StmtRange &range) { + return range.second; + } +}; + +/// A range of const statement iterators. +/// +/// This class provides some extra functionality beyond std::pair +/// in order to allow the following idiom: +/// for (ConstStmtRange range = stmt->children(); range; ++range) +struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> { + ConstStmtRange() {} + ConstStmtRange(const ConstStmtIterator &begin, + const ConstStmtIterator &end) + : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} + ConstStmtRange(const StmtRange &range) + : std::pair<ConstStmtIterator,ConstStmtIterator>(range.first, range.second) + {} + ConstStmtRange(const StmtIterator &begin, const StmtIterator &end) + : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} + + bool empty() const { return first == second; } + operator bool() const { return !empty(); } + + const Stmt *operator->() const { return first.operator->(); } + const Stmt *operator*() const { return first.operator*(); } + + ConstStmtRange &operator++() { + assert(!empty() && "incrementing on empty range"); + ++first; + return *this; + } + + ConstStmtRange operator++(int) { + assert(!empty() && "incrementing on empty range"); + ConstStmtRange copy = *this; + ++first; + return copy; + } + + friend const ConstStmtIterator &begin(const ConstStmtRange &range) { + return range.first; + } + friend const ConstStmtIterator &end(const ConstStmtRange &range) { + return range.second; + } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h index 269aa4c6dab2..1800a71f9154 100644 --- a/include/clang/AST/StmtObjC.h +++ b/include/clang/AST/StmtObjC.h @@ -55,7 +55,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); } static bool classof(const Stmt *T) { @@ -64,8 +64,9 @@ public: static bool classof(const ObjCForCollectionStmt *) { return true; } // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } }; /// ObjCAtCatchStmt - This represents objective-c's @catch statement. @@ -102,7 +103,7 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtCatchLoc, Body->getLocEnd()); } @@ -113,8 +114,7 @@ public: } static bool classof(const ObjCAtCatchStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Body, &Body + 1); } }; /// ObjCAtFinallyStmt - This represent objective-c's @finally Statement @@ -133,7 +133,7 @@ public: Stmt *getFinallyBody() { return AtFinallyStmt; } void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); } @@ -145,8 +145,9 @@ public: } static bool classof(const ObjCAtFinallyStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&AtFinallyStmt, &AtFinallyStmt+1); + } }; /// ObjCAtTryStmt - This represent objective-c's over-all @@ -239,15 +240,17 @@ public: getStmts()[1 + NumCatchStmts] = S; } - virtual SourceRange getSourceRange() const; + SourceRange getSourceRange() const; 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(); + child_range children() { + return child_range(getStmts(), + getStmts() + 1 + NumCatchStmts + HasFinally); + } }; /// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement. @@ -291,7 +294,7 @@ public: } void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd()); } @@ -300,8 +303,9 @@ public: } static bool classof(const ObjCAtSynchronizedStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { + return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR); + } }; /// ObjCAtThrowStmt - This represents objective-c's @throw statement. @@ -323,7 +327,7 @@ public: SourceLocation getThrowLoc() { return AtThrowLoc; } void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } - virtual SourceRange getSourceRange() const { + SourceRange getSourceRange() const { if (Throw) return SourceRange(AtThrowLoc, Throw->getLocEnd()); else @@ -335,8 +339,7 @@ public: } static bool classof(const ObjCAtThrowStmt *) { return true; } - virtual child_iterator child_begin(); - virtual child_iterator child_end(); + child_range children() { return child_range(&Throw, &Throw+1); } }; } // end namespace clang diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 7d5123fb0449..a4e074e083f6 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -23,6 +23,7 @@ namespace llvm { class FoldingSetNodeID; + class raw_ostream; } namespace clang { @@ -30,26 +31,14 @@ namespace clang { class Decl; class DiagnosticBuilder; class Expr; +struct PrintingPolicy; class TypeSourceInfo; /// \brief Represents a template argument within a class template /// specialization. class TemplateArgument { - union { - uintptr_t TypeOrValue; - struct { - char Value[sizeof(llvm::APSInt)]; - void *Type; - } Integer; - struct { - TemplateArgument *Args; - unsigned NumArgs; - bool CopyArgs; - } Args; - }; - public: - /// \brief The type of template argument we're storing. + /// \brief The kind of template argument we're storing. enum ArgKind { /// \brief Represents an empty template argument, e.g., one that has not /// been deduced. @@ -66,16 +55,42 @@ public: /// The template argument is a template name that was provided for a /// template template parameter. Template, + /// The template argument is a pack expansion of a template name that was + /// provided for a template template parameter. + TemplateExpansion, /// The template argument is a value- or type-dependent expression /// stored in an Expr*. Expression, /// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. Pack - } Kind; + }; + +private: + /// \brief The kind of template argument we're storing. + unsigned Kind; + union { + uintptr_t TypeOrValue; + struct { + char Value[sizeof(llvm::APSInt)]; + void *Type; + } Integer; + struct { + const TemplateArgument *Args; + unsigned NumArgs; + } Args; + struct { + void *Name; + unsigned NumExpansions; + } TemplateArg; + }; + + TemplateArgument(TemplateName, bool); // DO NOT USE + +public: /// \brief Construct an empty, invalid template argument. - TemplateArgument() : TypeOrValue(0), Kind(Null) { } + TemplateArgument() : Kind(Null), TypeOrValue(0) { } /// \brief Construct a template type argument. TemplateArgument(QualType T) : Kind(Type) { @@ -92,6 +107,8 @@ public: /// \brief Construct an integral constant template argument. TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. new (Integer.Value) llvm::APSInt(Value); Integer.Type = Type.getAsOpaquePtr(); } @@ -102,10 +119,35 @@ public: /// parameters. However, the template name could be a dependent template /// name that ends up being instantiated to a function template whose address /// is taken. - TemplateArgument(TemplateName Name) : Kind(Template) { - TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer()); + /// + /// \param Name The template name. + TemplateArgument(TemplateName Name) : Kind(Template) + { + TemplateArg.Name = Name.getAsVoidPointer(); + TemplateArg.NumExpansions = 0; } - + + /// \brief Construct a template argument that is a template pack expansion. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + /// + /// \param Name The template name. + /// + /// \param NumExpansions The number of expansions that will be generated by + /// instantiating + TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions) + : Kind(TemplateExpansion) + { + TemplateArg.Name = Name.getAsVoidPointer(); + if (NumExpansions) + TemplateArg.NumExpansions = *NumExpansions + 1; + else + TemplateArg.NumExpansions = 0; + } + /// \brief Construct a template argument that is an expression. /// /// This form of template argument only occurs in template argument @@ -115,46 +157,59 @@ public: TypeOrValue = reinterpret_cast<uintptr_t>(E); } + /// \brief Construct a template argument that is a template argument pack. + /// + /// We assume that storage for the template arguments provided + /// outlives the TemplateArgument itself. + TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){ + this->Args.Args = Args; + this->Args.NumArgs = NumArgs; + } + /// \brief Copy constructor for a template argument. TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. if (Kind == Integral) { new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); Integer.Type = Other.Integer.Type; } else if (Kind == Pack) { Args.NumArgs = Other.Args.NumArgs; - Args.Args = new TemplateArgument[Args.NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = Other.Args.Args[I]; - } - else + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } else TypeOrValue = Other.TypeOrValue; } 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; - } else { - // Destroy the current integral value, if that's what we're holding. - if (Kind == Integral) - getAsIntegral()->~APSInt(); + return *this; + } + + // Destroy the current integral value, if that's what we're holding. + if (Kind == Integral) + getAsIntegral()->~APSInt(); - Kind = Other.Kind; + Kind = Other.Kind; - if (Other.Kind == Integral) { - new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); - Integer.Type = Other.Integer.Type; - } else - TypeOrValue = Other.TypeOrValue; + if (Other.Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else if (Other.Kind == Pack) { + Args.NumArgs = Other.Args.NumArgs; + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } else { + TypeOrValue = Other.TypeOrValue; } return *this; @@ -165,16 +220,31 @@ public: if (Kind == Integral) getAsIntegral()->~APSInt(); - else if (Kind == Pack && Args.CopyArgs) - delete[] Args.Args; } + /// \brief Create a new template argument pack by copying the given set of + /// template arguments. + static TemplateArgument CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + /// \brief Return the kind of stored template argument. - ArgKind getKind() const { return Kind; } + ArgKind getKind() const { return (ArgKind)Kind; } /// \brief Determine whether this template argument has no value. bool isNull() const { return Kind == Null; } + /// \brief Whether this template argument is dependent on a template + /// parameter. + bool isDependent() const; + + /// \brief Whether this template argument contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// \brief Determine whether this template argument is a pack expansion. + bool isPackExpansion() const; + /// \brief Retrieve the template argument as a type. QualType getAsType() const { if (Kind != Type) @@ -195,9 +265,21 @@ public: if (Kind != Template) return TemplateName(); - return TemplateName::getFromVoidPointer( - reinterpret_cast<void *> (TypeOrValue)); + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the template argument as a template name; if the argument + /// is a pack expansion, return the pattern as a template name. + TemplateName getAsTemplateOrTemplatePattern() const { + if (Kind != Template && Kind != TemplateExpansion) + return TemplateName(); + + return TemplateName::getFromVoidPointer(TemplateArg.Name); } + + /// \brief Retrieve the number of expansions that a template template argument + /// expansion will produce, if known. + llvm::Optional<unsigned> getNumTemplateExpansions() const; /// \brief Retrieve the template argument as an integral value. llvm::APSInt *getAsIntegral() { @@ -260,11 +342,17 @@ public: /// same. bool structurallyEquals(const TemplateArgument &Other) const; - /// \brief Construct a template argument pack. - void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs); + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + TemplateArgument getPackExpansionPattern() const; + /// \brief Print this template argument to the given output stream. + void print(const PrintingPolicy &Policy, llvm::raw_ostream &Out) const; + /// \brief Used to insert TemplateArguments into FoldingSets. - void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const; + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; }; /// Location information for a TemplateArgument. @@ -276,95 +364,48 @@ private: struct { unsigned QualifierRange[2]; unsigned TemplateNameLoc; + unsigned EllipsisLoc; } Template; }; -#ifndef NDEBUG - enum Kind { - K_None, - K_TypeSourceInfo, - K_Expression, - K_Template - } Kind; -#endif - public: - TemplateArgumentLocInfo() - : Expression(0) -#ifndef NDEBUG - , Kind(K_None) -#endif - {} + TemplateArgumentLocInfo(); - TemplateArgumentLocInfo(TypeSourceInfo *TInfo) - : Declarator(TInfo) -#ifndef NDEBUG - , Kind(K_TypeSourceInfo) -#endif - {} + TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {} - TemplateArgumentLocInfo(Expr *E) - : Expression(E) -#ifndef NDEBUG - , Kind(K_Expression) -#endif - {} + TemplateArgumentLocInfo(Expr *E) : Expression(E) {} TemplateArgumentLocInfo(SourceRange QualifierRange, - SourceLocation TemplateNameLoc) -#ifndef NDEBUG - : Kind(K_Template) -#endif + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) { Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding(); Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding(); Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); + Template.EllipsisLoc = EllipsisLoc.getRawEncoding(); } TypeSourceInfo *getAsTypeSourceInfo() const { - assert(Kind == K_TypeSourceInfo); return Declarator; } Expr *getAsExpr() const { - assert(Kind == K_Expression); return Expression; } SourceRange getTemplateQualifierRange() const { - assert(Kind == K_Template); return SourceRange( SourceLocation::getFromRawEncoding(Template.QualifierRange[0]), SourceLocation::getFromRawEncoding(Template.QualifierRange[1])); } SourceLocation getTemplateNameLoc() const { - assert(Kind == K_Template); return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc); } -#ifndef NDEBUG - void validateForArgument(const TemplateArgument &Arg) { - switch (Arg.getKind()) { - case TemplateArgument::Type: - assert(Kind == K_TypeSourceInfo); - break; - case TemplateArgument::Expression: - case TemplateArgument::Declaration: - assert(Kind == K_Expression); - break; - case TemplateArgument::Template: - assert(Kind == K_Template); - break; - case TemplateArgument::Integral: - case TemplateArgument::Pack: - assert(Kind == K_None); - break; - case TemplateArgument::Null: - llvm_unreachable("source info for null template argument?"); - } + SourceLocation getTemplateEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(Template.EllipsisLoc); } -#endif }; /// Location wrapper for a TemplateArgument. TemplateArgument is to @@ -393,14 +434,18 @@ public: TemplateArgumentLoc(const TemplateArgument &Argument, SourceRange QualifierRange, - SourceLocation TemplateNameLoc) - : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) { - assert(Argument.getKind() == TemplateArgument::Template); + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc = SourceLocation()) + : Argument(Argument), + LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); } /// \brief - Fetches the primary location of the argument. SourceLocation getLocation() const { - if (Argument.getKind() == TemplateArgument::Template) + if (Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion) return getTemplateNameLoc(); return getSourceRange().getBegin(); @@ -433,14 +478,32 @@ public: } SourceRange getTemplateQualifierRange() const { - assert(Argument.getKind() == TemplateArgument::Template); + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); return LocInfo.getTemplateQualifierRange(); } SourceLocation getTemplateNameLoc() const { - assert(Argument.getKind() == TemplateArgument::Template); + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); return LocInfo.getTemplateNameLoc(); } + + SourceLocation getTemplateEllipsisLoc() const { + assert(Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateEllipsisLoc(); + } + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + /// + /// \param NumExpansions Will be set to the number of expansions that will + /// be generated from this pack expansion, if known a priori. + TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const; }; /// A convenient class for passing around template argument diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index ddfac712734b..1721973e8229 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -23,43 +23,119 @@ namespace llvm { } namespace clang { - + +class ASTContext; class DependentTemplateName; class DiagnosticBuilder; class IdentifierInfo; class NestedNameSpecifier; +class OverloadedTemplateStorage; struct PrintingPolicy; class QualifiedTemplateName; class NamedDecl; +class SubstTemplateTemplateParmPackStorage; +class TemplateArgument; class TemplateDecl; - -/// \brief A structure for storing the information associated with an -/// overloaded template name. -class OverloadedTemplateStorage { +class TemplateTemplateParmDecl; + +/// \brief Implementation class used to describe either a set of overloaded +/// template names or an already-substituted template template parameter pack. +class UncommonTemplateNameStorage { +protected: union { - unsigned Size; - NamedDecl *Storage[1]; + struct { + /// \brief If true, this is an OverloadedTemplateStorage instance; + /// otherwise, it's a SubstTemplateTemplateParmPackStorage instance. + unsigned IsOverloadedStorage : 1; + + /// \brief The number of stored templates or template arguments, + /// depending on which subclass we have. + unsigned Size : 31; + } Bits; + + void *PointerAlignment; }; - + + UncommonTemplateNameStorage(unsigned Size, bool OverloadedStorage) { + Bits.IsOverloadedStorage = OverloadedStorage; + Bits.Size = Size; + } + +public: + unsigned size() const { return Bits.Size; } + + OverloadedTemplateStorage *getAsOverloadedStorage() { + return Bits.IsOverloadedStorage + ? reinterpret_cast<OverloadedTemplateStorage *>(this) + : 0; + } + + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { + return Bits.IsOverloadedStorage + ? 0 + : reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) ; + } +}; + +/// \brief A structure for storing the information associated with an +/// overloaded template name. +class OverloadedTemplateStorage : public UncommonTemplateNameStorage { friend class ASTContext; - OverloadedTemplateStorage(unsigned Size) : Size(Size) {} + OverloadedTemplateStorage(unsigned Size) + : UncommonTemplateNameStorage(Size, true) { } NamedDecl **getStorage() { - return &Storage[1]; + return reinterpret_cast<NamedDecl **>(this + 1); } NamedDecl * const *getStorage() const { - return &Storage[1]; + return reinterpret_cast<NamedDecl *const *>(this + 1); } public: typedef NamedDecl *const *iterator; - unsigned size() const { return Size; } - iterator begin() const { return getStorage(); } iterator end() const { return getStorage() + size(); } }; + + +/// \brief A structure for storing an already-substituted template template +/// parameter pack. +/// +/// This kind of template names occurs when the parameter pack has been +/// provided with a template template argument pack in a context where its +/// enclosing pack expansion could not be fully expanded. +class SubstTemplateTemplateParmPackStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode +{ + ASTContext &Context; + TemplateTemplateParmDecl *Parameter; + const TemplateArgument *Arguments; + +public: + SubstTemplateTemplateParmPackStorage(ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + unsigned Size, + const TemplateArgument *Arguments) + : UncommonTemplateNameStorage(Size, false), Context(Context), + Parameter(Parameter), Arguments(Arguments) { } + + /// \brief Retrieve the template template parameter pack being substituted. + TemplateTemplateParmDecl *getParameterPack() const { + return Parameter; + } + + /// \brief Retrieve the template template argument pack with which this + /// parameter was substituted. + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack); +}; /// \brief Represents a C++ template name within the type system. /// @@ -90,7 +166,7 @@ public: /// only be understood in the context of class TemplateName { typedef llvm::PointerUnion4<TemplateDecl *, - OverloadedTemplateStorage *, + UncommonTemplateNameStorage *, QualifiedTemplateName *, DependentTemplateName *> StorageType; @@ -103,16 +179,28 @@ class TemplateName { public: // \brief Kind of name that is actually stored. enum NameKind { + /// \brief A single template declaration. Template, + /// \brief A set of overloaded template declarations. OverloadedTemplate, + /// \brief A qualified template name, where the qualification is kept + /// to describe the source code as written. QualifiedTemplate, - DependentTemplate + /// \brief A dependent template name that has not been resolved to a + /// template (or set of templates). + DependentTemplate, + /// \brief A template template parameter pack that has been substituted for + /// a template template argument pack, but has not yet been expanded into + /// individual arguments. + SubstTemplateTemplateParmPack }; TemplateName() : Storage() { } explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } explicit TemplateName(OverloadedTemplateStorage *Storage) : Storage(Storage) { } + explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage) + : Storage(Storage) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } @@ -122,7 +210,7 @@ public: // \brief Get the kind of name that is actually stored. NameKind getKind() const; - /// \brief Retrieve the the underlying template declaration that + /// \brief Retrieve the underlying template declaration that /// this template name refers to, if known. /// /// \returns The template declaration that this template name refers @@ -131,7 +219,7 @@ public: /// set of function templates, returns NULL. TemplateDecl *getAsTemplateDecl() const; - /// \brief Retrieve the the underlying, overloaded function template + /// \brief Retrieve the underlying, overloaded function template // declarations that this template name refers to, if known. /// /// \returns The set of overloaded function templates that this template @@ -139,7 +227,25 @@ public: /// specific set of function templates because it is a dependent name or /// refers to a single template, returns NULL. OverloadedTemplateStorage *getAsOverloadedTemplate() const { - return Storage.dyn_cast<OverloadedTemplateStorage *>(); + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsOverloadedStorage(); + + return 0; + } + + /// \brief Retrieve the substituted template template parameter pack, if + /// known. + /// + /// \returns The storage for the substituted template template parameter pack, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmPackStorage * + getAsSubstTemplateTemplateParmPack() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsSubstTemplateTemplateParmPack(); + + return 0; } /// \brief Retrieve the underlying qualified template name @@ -157,6 +263,10 @@ public: /// \brief Determines whether this is a dependent template name. bool isDependent() const; + /// \brief Determines whether this template name contains an + /// unexpanded parameter pack (for C++0x variadic templates). + bool containsUnexpandedParameterPack() const; + /// \brief Print the template name. /// /// \param OS the output stream to which the template name will be diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 92e62a58d42c..9b177cceed96 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -18,12 +18,14 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Visibility.h" #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/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" @@ -34,7 +36,7 @@ using llvm::dyn_cast; using llvm::dyn_cast_or_null; namespace clang { enum { - TypeAlignmentInBits = 3, + TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits }; class Type; @@ -91,8 +93,9 @@ namespace clang { class TemplateArgument; class TemplateArgumentLoc; class TemplateArgumentListInfo; - class Type; class ElaboratedType; + class ExtQuals; + class ExtQualsTypeCommonBase; struct PrintingPolicy; template <typename> class CanQual; @@ -128,7 +131,7 @@ public: MaxAddressSpace = 0xffffffu, /// The width of the "fast" qualifier mask. - FastWidth = 2, + FastWidth = 3, /// The fast qualifier mask. FastMask = (1 << FastWidth) - 1 @@ -271,6 +274,25 @@ public: } } + /// \brief Add the qualifiers from the given set to this set, given that + /// they don't conflict. + void addConsistentQualifiers(Qualifiers qs) { + assert(getAddressSpace() == qs.getAddressSpace() || + !hasAddressSpace() || !qs.hasAddressSpace()); + assert(getObjCGCAttr() == qs.getObjCGCAttr() || + !hasObjCGCAttr() || !qs.hasObjCGCAttr()); + Mask |= qs.Mask; + } + + /// \brief Determines if these qualifiers compatibly include another set. + /// Generally this answers the question of whether an object with the other + /// qualifiers can be safely used as an object with these qualifiers. + bool compatiblyIncludes(Qualifiers other) const { + // Non-CVR qualifiers must match exactly. CVR qualifiers may subset. + return ((Mask & ~CVRMask) == (other.Mask & ~CVRMask)) && + (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); + } + bool isSupersetOf(Qualifiers Other) const; bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } @@ -325,85 +347,6 @@ private: 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); - } -}; - /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { CC_Default, @@ -414,6 +357,7 @@ enum CallingConv { CC_X86Pascal // __attribute__((pascal)) }; +typedef std::pair<const Type*, Qualifiers> SplitQualType; /// 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 @@ -440,8 +384,14 @@ class QualType { return Value.getPointer().get<const Type*>(); } - QualType getUnqualifiedTypeSlow() const; - + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + uintptr_t CommonPtrVal + = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); + } + friend class QualifierCollector; public: QualType() {} @@ -457,24 +407,29 @@ public: /// 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 (hasLocalNonFastQualifiers()) - return const_cast<Type*>(getExtQualsUnsafe()->getBaseType()); - return const_cast<Type*>(getTypePtrUnsafe()); - } + /// + /// This function requires that the type not be NULL. If the type might be + /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). + const Type *getTypePtr() const; + + const Type *getTypePtrOrNull() const; + + /// Divides a QualType into its unqualified type and a set of local + /// qualifiers. + SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } - static QualType getFromOpaquePtr(void *Ptr) { + static QualType getFromOpaquePtr(const void *Ptr) { QualType T; - T.Value.setFromOpaqueValue(Ptr); + T.Value.setFromOpaqueValue(const_cast<void*>(Ptr)); return T; } - Type &operator*() const { + const Type &operator*() const { return *getTypePtr(); } - Type *operator->() const { + const Type *operator->() const { return getTypePtr(); } @@ -510,7 +465,7 @@ public: /// "volatile" qualifier set, without looking through typedefs that may have /// added "volatile" at a different level. bool isLocalVolatileQualified() const { - return (hasLocalNonFastQualifiers() && getExtQualsUnsafe()->hasVolatile()); + return (getLocalFastQualifiers() & Qualifiers::Volatile); } /// \brief Determine whether this type is volatile-qualified. @@ -536,13 +491,7 @@ public: /// \brief Retrieve the set of qualifiers local to this particular QualType /// instance, not including any qualifiers acquired through typedefs or /// other sugar. - Qualifiers getLocalQualifiers() const { - Qualifiers Quals; - if (hasLocalNonFastQualifiers()) - Quals = getExtQualsUnsafe()->getQualifiers(); - Quals.addFastQualifiers(getLocalFastQualifiers()); - return Quals; - } + Qualifiers getLocalQualifiers() const; /// \brief Retrieve the set of qualifiers applied to this type. Qualifiers getQualifiers() const; @@ -551,21 +500,13 @@ public: /// local to this particular QualType instance, not including any qualifiers /// acquired through typedefs or other sugar. unsigned getLocalCVRQualifiers() const { - unsigned CVR = getLocalFastQualifiers(); - if (isLocalVolatileQualified()) - CVR |= Qualifiers::Volatile; - return CVR; + return getLocalFastQualifiers(); } /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers /// applied to this type. unsigned getCVRQualifiers() const; - /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers - /// applied to this type, looking through any number of unqualified array - /// types to their element types' qualifiers. - unsigned getCVRQualifiersThroughArrayTypes() const; - bool isConstant(ASTContext& Ctx) const { return QualType::isConstant(*this, Ctx); } @@ -587,16 +528,13 @@ public: Value.setInt(Value.getInt() | TQs); } - // FIXME: The remove* functions are semantically broken, because they might - // not remove a qualifier stored on a typedef. Most of the with* functions - // have the same problem. - void removeConst(); - void removeVolatile(); - void removeRestrict(); - void removeCVRQualifiers(unsigned Mask); + void removeLocalConst(); + void removeLocalVolatile(); + void removeLocalRestrict(); + void removeLocalCVRQualifiers(unsigned Mask); - void removeFastQualifiers() { Value.setInt(0); } - void removeFastQualifiers(unsigned Mask) { + void removeLocalFastQualifiers() { Value.setInt(0); } + void removeLocalFastQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); Value.setInt(Value.getInt() & ~Mask); } @@ -611,31 +549,54 @@ public: // Creates a type with exactly the given fast qualifiers, removing // any existing fast qualifiers. - QualType withExactFastQualifiers(unsigned TQs) const { - return withoutFastQualifiers().withFastQualifiers(TQs); + QualType withExactLocalFastQualifiers(unsigned TQs) const { + return withoutLocalFastQualifiers().withFastQualifiers(TQs); } // Removes fast qualifiers, but leaves any extended qualifiers in place. - QualType withoutFastQualifiers() const { + QualType withoutLocalFastQualifiers() const { QualType T = *this; - T.removeFastQualifiers(); + T.removeLocalFastQualifiers(); return T; } + QualType getCanonicalType() const; + /// \brief Return this type with all of the instance-specific qualifiers /// removed, but without removing any qualifiers that may have been applied /// through typedefs. QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } - /// \brief Return the unqualified form of the given type, which might be - /// desugared to eliminate qualifiers introduced via typedefs. - QualType getUnqualifiedType() const { - QualType T = getLocalUnqualifiedType(); - if (!T.hasQualifiers()) - return T; - - return getUnqualifiedTypeSlow(); - } + /// \brief Retrieve the unqualified variant of the given type, + /// removing as little sugar as possible. + /// + /// This routine looks through various kinds of sugar to find the + /// least-desugared type that is unqualified. For example, given: + /// + /// \code + /// typedef int Integer; + /// typedef const Integer CInteger; + /// typedef CInteger DifferenceType; + /// \endcode + /// + /// Executing \c getUnqualifiedType() on the type \c DifferenceType will + /// desugar until we hit the type \c Integer, which has no qualifiers on it. + /// + /// The resulting type might still be qualified if it's an array + /// type. To strip qualifiers even from within an array type, use + /// ASTContext::getUnqualifiedArrayType. + inline QualType getUnqualifiedType() const; + + /// getSplitUnqualifiedType - Retrieve the unqualified variant of the + /// given type, removing as little sugar as possible. + /// + /// Like getUnqualifiedType(), but also returns the set of + /// qualifiers that were built up. + /// + /// The resulting type might still be qualified if it's an array + /// type. To strip qualifiers even from within an array type, use + /// ASTContext::getUnqualifiedArrayType. + inline SplitQualType getSplitUnqualifiedType() const; bool isMoreQualifiedThan(QualType Other) const; bool isAtLeastAsQualifiedAs(QualType Other) const; @@ -659,8 +620,20 @@ public: /// concrete. /// /// Qualifiers are left in place. - QualType getDesugaredType() const { - return QualType::getDesugaredType(*this); + QualType getDesugaredType(const ASTContext &Context) const { + return getDesugaredType(*this, Context); + } + + SplitQualType getSplitDesugaredType() const { + return getSplitDesugaredType(*this); + } + + /// IgnoreParens - Returns the specified type after dropping any + /// outer-level parentheses. + QualType IgnoreParens() const { + if (isa<ParenType>(*this)) + return QualType::IgnoreParens(*this); + return *this; } /// operator==/!= - Indicate whether the specified types and qualifiers are @@ -671,7 +644,13 @@ public: friend bool operator!=(const QualType &LHS, const QualType &RHS) { return LHS.Value != RHS.Value; } - std::string getAsString() const; + std::string getAsString() const { + return getAsString(split()); + } + static std::string getAsString(SplitQualType split) { + return getAsString(split.first, split.second); + } + static std::string getAsString(const Type *ty, Qualifiers qs); std::string getAsString(const PrintingPolicy &Policy) const { std::string S; @@ -679,7 +658,16 @@ public: return S; } void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const; + const PrintingPolicy &Policy) const { + return getAsStringInternal(split(), Str, Policy); + } + static void getAsStringInternal(SplitQualType split, std::string &out, + const PrintingPolicy &policy) { + return getAsStringInternal(split.first, split.second, out, policy); + } + static void getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &out, + const PrintingPolicy &policy); void dump(const char *s) const; void dump() const; @@ -704,12 +692,29 @@ public: return getObjCGCAttr() == Qualifiers::Strong; } + enum DestructionKind { + DK_none, + DK_cxx_destructor + }; + + /// isDestructedType - nonzero if objects of this type require + /// non-trivial work to clean up after. Non-zero because it's + /// conceivable that qualifiers (objc_gc(weak)?) could make + /// something require destruction. + DestructionKind isDestructedType() const { + return isDestructedTypeImpl(*this); + } + 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); + static QualType getDesugaredType(QualType T, const ASTContext &Context); + static SplitQualType getSplitDesugaredType(QualType T); + static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); + static QualType IgnoreParens(QualType T); + static DestructionKind isDestructedTypeImpl(QualType type); }; } // end clang. @@ -718,7 +723,7 @@ namespace llvm { /// Implement simplify_type for QualType, so that we can dyn_cast from QualType /// to a specific Type class. template<> struct simplify_type<const ::clang::QualType> { - typedef ::clang::Type* SimpleType; + typedef const ::clang::Type *SimpleType; static SimpleType getSimplifiedValue(const ::clang::QualType &Val) { return Val.getTypePtr(); } @@ -744,6 +749,106 @@ public: namespace clang { +/// \brief Base class that is common to both the \c ExtQuals and \c Type +/// classes, which allows \c QualType to access the common fields between the +/// two. +/// +class ExtQualsTypeCommonBase { + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} + + /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or + /// a self-referential pointer (for \c Type). + /// + /// This pointer allows an efficient mapping from a QualType to its + /// underlying type pointer. + const Type *const BaseType; + + /// \brief The canonical type of this type. A QualType. + QualType CanonicalType; + + friend class QualType; + friend class Type; + friend class ExtQuals; +}; + +/// ExtQuals - We can encode up to four 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', 'restrict', and 'volatile' qualifiers +/// in three low bits on the QualType pointer; a fourth bit records whether +/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, +/// Objective-C GC attributes) are much more rare. +class ExtQuals : public ExtQualsTypeCommonBase, 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. + + /// Quals - the immutable set of qualifiers applied by this + /// node; always contains extended qualifiers. + Qualifiers Quals; + + ExtQuals *this_() { return this; } + +public: + ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + 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 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; } + +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); + } +}; + +/// \brief The kind of C++0x ref-qualifier associated with a function type, +/// which determines whether a member function's "this" object can be an +/// lvalue, rvalue, or neither. +enum RefQualifierKind { + /// \brief No ref-qualifier was provided. + RQ_None = 0, + /// \brief An lvalue ref-qualifier was provided (\c &). + RQ_LValue, + /// \brief An rvalue ref-qualifier was provided (\c &&). + RQ_RValue +}; + /// Type - This is the base class of the type hierarchy. A central concept /// with types is that each type always has a canonical type. A canonical type /// is the type with any typedef names stripped out of it or the types it @@ -769,7 +874,7 @@ namespace clang { /// /// Types, once created, are immutable. /// -class Type { +class Type : public ExtQualsTypeCommonBase { public: enum TypeClass { #define TYPE(Class, Base) Class, @@ -783,53 +888,249 @@ private: Type(const Type&); // DO NOT IMPLEMENT. void operator=(const Type&); // DO NOT IMPLEMENT. - QualType CanonicalType; + /// Bitfields required by the Type class. + class TypeBitfields { + friend class Type; + template <class T> friend class TypePropertyCache; - /// TypeClass bitfield - Enum that specifies what subclass this belongs to. - unsigned TC : 8; + /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + unsigned TC : 8; - /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). - /// Note that this should stay at the end of the ivars for Type so that - /// subclasses can pack their bitfields into the same word. - bool Dependent : 1; + /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). + /// 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 Dependent : 1; - /// \brief Whether the linkage of this type is already known. - mutable bool LinkageKnown : 1; + /// \brief Whether this type is a variably-modified type (C99 6.7.5). + unsigned VariablyModified : 1; + + /// \brief Whether this type contains an unexpanded parameter pack + /// (for C++0x variadic templates). + unsigned ContainsUnexpandedParameterPack : 1; + + /// \brief Nonzero if the cache (i.e. the bitfields here starting + /// with 'Cache') is valid. If so, then this is a + /// LangOptions::VisibilityMode+1. + mutable unsigned CacheValidAndVisibility : 2; + + /// \brief Linkage of this type. + mutable unsigned CachedLinkage : 2; + + /// \brief Whether this type involves and local or unnamed types. + mutable unsigned CachedLocalOrUnnamed : 1; - /// \brief Linkage of this type. - mutable unsigned CachedLinkage : 2; + /// \brief FromAST - Whether this type comes from an AST file. + mutable unsigned FromAST : 1; + + bool isCacheValid() const { + return (CacheValidAndVisibility != 0); + } + Visibility getVisibility() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast<Visibility>(CacheValidAndVisibility-1); + } + Linkage getLinkage() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast<Linkage>(CachedLinkage); + } + bool hasLocalOrUnnamedType() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedLocalOrUnnamed; + } + }; + enum { NumTypeBits = 17 }; + +protected: + // These classes allow subclasses to somewhat cleanly pack bitfields + // into Type. + + class ArrayTypeBitfields { + friend class ArrayType; + + unsigned : NumTypeBits; + + /// IndexTypeQuals - CVR qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + unsigned IndexTypeQuals : 3; + + /// SizeModifier - storage class qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + /// Actually an ArrayType::ArraySizeModifier. + unsigned SizeModifier : 3; + }; + + class BuiltinTypeBitfields { + friend class BuiltinType; + + unsigned : NumTypeBits; + + /// The kind (BuiltinType::Kind) of builtin type this is. + unsigned Kind : 8; + }; + + class FunctionTypeBitfields { + friend class FunctionType; + + unsigned : NumTypeBits; + + /// Extra information which affects how the function is called, like + /// regparm and the calling convention. + unsigned ExtInfo : 8; + + /// Whether the function is variadic. Only used by FunctionProtoType. + unsigned Variadic : 1; + + /// TypeQuals - Used only by FunctionProtoType, put here to pack with the + /// other bitfields. + /// The qualifiers are part of FunctionProtoType because... + /// + /// C++ 8.3.5p4: The return type, the parameter type list and the + /// cv-qualifier-seq, [...], are part of the function type. + unsigned TypeQuals : 3; + + /// \brief The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; + }; + + class ObjCObjectTypeBitfields { + friend class ObjCObjectType; + + unsigned : NumTypeBits; + + /// NumProtocols - The number of protocols stored directly on this + /// object type. + unsigned NumProtocols : 32 - NumTypeBits; + }; + + class ReferenceTypeBitfields { + friend class ReferenceType; + + unsigned : NumTypeBits; + + /// True if the type was originally spelled with an lvalue sigil. + /// This is never true of rvalue references but can also be false + /// on lvalue references because of C++0x [dcl.typedef]p9, + /// as follows: + /// + /// typedef int &ref; // lvalue, spelled lvalue + /// typedef int &&rvref; // rvalue + /// ref &a; // lvalue, inner ref, spelled lvalue + /// ref &&a; // lvalue, inner ref + /// rvref &a; // lvalue, inner ref, spelled lvalue + /// rvref &&a; // rvalue, inner ref + unsigned SpelledAsLValue : 1; + + /// True if the inner type is a reference type. This only happens + /// in non-canonical forms. + unsigned InnerRef : 1; + }; + + class TypeWithKeywordBitfields { + friend class TypeWithKeyword; + + unsigned : NumTypeBits; + + /// An ElaboratedTypeKeyword. 8 bits for efficient access. + unsigned Keyword : 8; + }; + + class VectorTypeBitfields { + friend class VectorType; + + unsigned : NumTypeBits; + + /// VecKind - The kind of vector, either a generic vector type or some + /// target-specific vector type such as for AltiVec or Neon. + unsigned VecKind : 3; + + /// NumElements - The number of elements in the vector. + unsigned NumElements : 29 - NumTypeBits; + }; + + class AttributedTypeBitfields { + friend class AttributedType; - /// \brief FromAST - Whether this type comes from an AST file. - mutable bool FromAST : 1; + unsigned : NumTypeBits; + /// AttrKind - an AttributedType::Kind + unsigned AttrKind : 32 - NumTypeBits; + }; + + union { + TypeBitfields TypeBits; + ArrayTypeBitfields ArrayTypeBits; + AttributedTypeBitfields AttributedTypeBits; + BuiltinTypeBitfields BuiltinTypeBits; + FunctionTypeBitfields FunctionTypeBits; + ObjCObjectTypeBitfields ObjCObjectTypeBits; + ReferenceTypeBitfields ReferenceTypeBits; + TypeWithKeywordBitfields TypeWithKeywordBits; + VectorTypeBitfields VectorTypeBits; + }; + +private: /// \brief Set whether this type comes from an AST file. void setFromAST(bool V = true) const { - FromAST = V; + TypeBits.FromAST = V; } -protected: - /// \brief Compute the linkage of this type. - virtual Linkage getLinkageImpl() const; - - enum { BitsRemainingInType = 19 }; + template <class T> friend class TypePropertyCache; +protected: // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } - Type(TypeClass tc, QualType Canonical, bool dependent) - : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical), - TC(tc), Dependent(dependent), LinkageKnown(false), - CachedLinkage(NoLinkage), FromAST(false) {} - virtual ~Type(); + Type(TypeClass tc, QualType canon, bool Dependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { + TypeBits.TC = tc; + TypeBits.Dependent = Dependent; + TypeBits.VariablyModified = VariablyModified; + TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + TypeBits.CacheValidAndVisibility = 0; + TypeBits.CachedLocalOrUnnamed = false; + TypeBits.CachedLinkage = NoLinkage; + TypeBits.FromAST = false; + } friend class ASTContext; + void setDependent(bool D = true) { TypeBits.Dependent = D; } + void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } + void setContainsUnexpandedParameterPack(bool PP = true) { + TypeBits.ContainsUnexpandedParameterPack = PP; + } + public: - TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); } + TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); } /// \brief Whether this type comes from an AST file. - bool isFromAST() const { return FromAST; } + bool isFromAST() const { return TypeBits.FromAST; } + + /// \brief Whether this type is or contains an unexpanded parameter + /// pack, used to support C++0x variadic templates. + /// + /// A type that contains a parameter pack shall be expanded by the + /// ellipsis operator at some point. For example, the typedef in the + /// following example contains an unexpanded parameter pack 'T': + /// + /// \code + /// template<typename ...T> + /// struct X { + /// typedef T* pointer_types; // ill-formed; T is a parameter pack. + /// }; + /// \endcode + /// + /// Note that this routine does not specify which + bool containsUnexpandedParameterPack() const { + return TypeBits.ContainsUnexpandedParameterPack; + } + /// Determines if this type would be canonical if it had no further + /// qualification. bool isCanonicalUnqualified() const { - return CanonicalType.getTypePtr() == this; + return CanonicalType == QualType(this, 0); } /// Types are partitioned into 3 broad categories (C99 6.2.5p1): @@ -846,6 +1147,14 @@ public: bool isIncompleteOrObjectType() const { return !isFunctionType(); } + + /// \brief Determine whether this type is an object type. + bool isObjectType() const { + // C++ [basic.types]p8: + // An object type is a (possibly cv-qualified) type that is not a + // function type, not a reference type, and not a void type. + return !isReferenceType() && !isFunctionType() && !isVoidType(); + } /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10). bool isPODType() const; @@ -854,10 +1163,6 @@ public: /// (C++0x [basic.types]p10) bool isLiteralType() const; - /// 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. @@ -867,6 +1172,12 @@ public: /// isSpecificBuiltinType - Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; + /// isPlaceholderType - Test for a type which does not represent an + /// actual type-system type but is instead used as a placeholder for + /// various convenient purposes within Clang. All such types are + /// BuiltinTypes. + bool isPlaceholderType() 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) @@ -879,6 +1190,9 @@ public: /// \brief Determine whether this type is an integral or enumeration type. bool isIntegralOrEnumerationType() const; + /// \brief Determine whether this type is an integral or unscoped enumeration + /// type. + bool isIntegralOrUnscopedEnumerationType() const; /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) @@ -938,10 +1252,33 @@ public: bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t + enum ScalarTypeKind { + STK_Pointer, + STK_MemberPointer, + STK_Bool, + STK_Integral, + STK_Floating, + STK_IntegralComplex, + STK_FloatingComplex + }; + /// getScalarTypeKind - Given that this is a scalar type, classify it. + ScalarTypeKind getScalarTypeKind() const; + /// isDependentType - Whether this type is a dependent type, meaning /// that its definition somehow depends on a template parameter /// (C++ [temp.dep.type]). - bool isDependentType() const { return Dependent; } + bool isDependentType() const { return TypeBits.Dependent; } + + /// \brief Whether this type is a variably-modified type (C99 6.7.5). + bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } + + /// \brief Whether this type involves a variable-length array type + /// with a definite size. + bool hasSizedVLAType() const; + + /// \brief Whether this type is or contains a local or unnamed type. + bool hasUnnamedOrLocalType() const; + bool isOverloadableType() const; /// \brief Determine wither this type is a C++ elaborated-type-specifier. @@ -991,15 +1328,41 @@ public: /// because the type is a RecordType or because it is the injected-class-name /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; + + /// \brief Get the AutoType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + AutoType *getContainedAutoType() const; - // Member-template getAs<specific type>'. Look through sugar for - // an instance of <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. + /// Member-template getAs<specific type>'. Look through sugar for + /// an instance of <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; + /// A variant of getAs<> for array types which silently discards + /// qualifiers from the outermost type. + const ArrayType *getAsArrayTypeUnsafe() const; + + /// Member-template castAs<specific type>. Look through sugar for + /// the underlying instance of <specific type>. + /// + /// This method has the same relationship to getAs<T> as cast<T> has + /// to dyn_cast<T>; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template <typename T> const T *castAs() const; + + /// A variant of castAs<> for array type which silently discards + /// qualifiers from the outermost type. + const ArrayType *castAsArrayTypeUnsafe() const; + + /// getBaseElementTypeUnsafe - Get the base element type of this + /// type, potentially discarding type qualifiers. This method + /// should never be used when type qualifiers are meaningful. + const Type *getBaseElementTypeUnsafe() const; + /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -1040,6 +1403,12 @@ public: /// \brief Determine the linkage of this type. Linkage getLinkage() const; + + /// \brief Determine the visibility of this type. + Visibility getVisibility() const; + + /// \brief Determine the linkage and visibility of this type. + std::pair<Linkage,Visibility> getLinkageAndVisibility() const; /// \brief Note that the linkage is no longer known. void ClearLinkageCache(); @@ -1067,6 +1436,9 @@ template <> inline const TypedefType *Type::getAs() const { #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ return dyn_cast<Class##Type>(CanonicalType); \ +} \ +template <> inline const Class##Type *Type::castAs() const { \ + return cast<Class##Type>(CanonicalType); \ } #include "clang/AST/TypeNodes.def" @@ -1081,6 +1453,7 @@ public: 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. + WChar_U, // This is 'wchar_t' for C++, when unsigned. Char16, // This is 'char16_t' for C++. Char32, // This is 'char32_t' for C++. UShort, @@ -1091,7 +1464,7 @@ public: 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++. + WChar_S, // This is 'wchar_t' for C++, when signed. Short, Int, Long, @@ -1102,11 +1475,13 @@ public: 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. + /// This represents the type of an expression whose type is + /// totally unknown, e.g. 'T::foo'. It is permitted for this to + /// appear in situations where the structure of the type is + /// theoretically deducible. + Dependent, - UndeducedAuto, // In C++0x, this represents the type of an auto variable - // that has not been deduced yet. + Overload, // This represents the type of an overloaded function declaration. /// The primitive Objective C 'id' type. The type pointed to by the /// user-visible 'id' type. Only ever shows up in an AST as the base @@ -1120,37 +1495,42 @@ public: ObjCSel // This represents the ObjC 'SEL' type. }; -private: - Kind TypeKind; - -protected: - virtual Linkage getLinkageImpl() const; - + public: BuiltinType(Kind K) - : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)), - TypeKind(K) {} + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), + /*VariablyModified=*/false, + /*Unexpanded paramter pack=*/false) { + BuiltinTypeBits.Kind = K; + } - Kind getKind() const { return TypeKind; } + Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); } const char *getName(const LangOptions &LO) const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } bool isInteger() const { - return TypeKind >= Bool && TypeKind <= Int128; + return getKind() >= Bool && getKind() <= Int128; } bool isSignedInteger() const { - return TypeKind >= Char_S && TypeKind <= Int128; + return getKind() >= Char_S && getKind() <= Int128; } bool isUnsignedInteger() const { - return TypeKind >= Bool && TypeKind <= UInt128; + return getKind() >= Bool && getKind() <= UInt128; } bool isFloatingPoint() const { - return TypeKind >= Float && TypeKind <= LongDouble; + return getKind() >= Float && getKind() <= LongDouble; + } + + /// Determines whether this type is a "forbidden" placeholder type, + /// i.e. a type which cannot appear in arbitrary positions in a + /// fully-formed expression. + bool isPlaceholderType() const { + return getKind() == Overload; } static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } @@ -1163,14 +1543,13 @@ 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(), + Element->isVariablyModifiedType(), + Element->containsUnexpandedParameterPack()), ElementType(Element) { } friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: QualType getElementType() const { return ElementType; } @@ -1188,19 +1567,50 @@ public: static bool classof(const ComplexType *) { return true; } }; +/// ParenType - Sugar for parentheses used when specifying types. +/// +class ParenType : public Type, public llvm::FoldingSetNode { + QualType Inner; + + ParenType(QualType InnerType, QualType CanonType) : + Type(Paren, CanonType, InnerType->isDependentType(), + InnerType->isVariablyModifiedType(), + InnerType->containsUnexpandedParameterPack()), + Inner(InnerType) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getInnerType() const { return Inner; } + + bool isSugared() const { return true; } + QualType desugar() const { return getInnerType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getInnerType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { + Inner.Profile(ID); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Paren; } + static bool classof(const ParenType *) { return true; } +}; + /// PointerType - C99 6.7.5.1 - Pointer Declarators. /// class PointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr) : - Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) { + Type(Pointer, CanonicalPtr, Pointee->isDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) { } friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: QualType getPointeeType() const { return PointeeType; } @@ -1226,14 +1636,13 @@ 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(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) { } friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: // Get the pointee type. Pointee is required to always be a function type. @@ -1260,48 +1669,33 @@ public: class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; - /// True if the type was originally spelled with an lvalue sigil. - /// This is never true of rvalue references but can also be false - /// on lvalue references because of C++0x [dcl.typedef]p9, - /// as follows: - /// - /// typedef int &ref; // lvalue, spelled lvalue - /// typedef int &&rvref; // rvalue - /// ref &a; // lvalue, inner ref, spelled lvalue - /// ref &&a; // lvalue, inner ref - /// rvref &a; // lvalue, inner ref, spelled lvalue - /// rvref &&a; // rvalue, inner ref - bool SpelledAsLValue; - - /// True if the inner type is a reference type. This only happens - /// in non-canonical forms. - bool InnerRef; - protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : - Type(tc, CanonicalRef, Referencee->isDependentType()), - PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue), - InnerRef(Referencee->isReferenceType()) { + Type(tc, CanonicalRef, Referencee->isDependentType(), + Referencee->isVariablyModifiedType(), + Referencee->containsUnexpandedParameterPack()), + PointeeType(Referencee) + { + ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; + ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } - virtual Linkage getLinkageImpl() const; - public: - bool isSpelledAsLValue() const { return SpelledAsLValue; } - bool isInnerRef() const { return InnerRef; } + bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } + bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } QualType getPointeeTypeAsWritten() const { return PointeeType; } QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; - while (T->InnerRef) - T = T->PointeeType->getAs<ReferenceType>(); + while (T->isInnerRef()) + T = T->PointeeType->castAs<ReferenceType>(); return T->PointeeType; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, PointeeType, SpelledAsLValue); + Profile(ID, PointeeType, isSpelledAsLValue()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, @@ -1362,14 +1756,14 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, - Cls->isDependentType() || Pointee->isDependentType()), + Cls->isDependentType() || Pointee->isDependentType(), + Pointee->isVariablyModifiedType(), + (Cls->containsUnexpandedParameterPack() || + Pointee->containsUnexpandedParameterPack())), PointeeType(Pointee), Class(Cls) { } friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: QualType getPointeeType() const { return PointeeType; } @@ -1420,14 +1814,6 @@ 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... @@ -1435,23 +1821,29 @@ protected: // size is specified by a constant expression that is // value-dependent, ArrayType(TypeClass tc, QualType et, QualType can, - ArraySizeModifier sm, unsigned tq) - : Type(tc, can, et->isDependentType() || tc == DependentSizedArray), - ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {} + ArraySizeModifier sm, unsigned tq, + bool ContainsUnexpandedParameterPack) + : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, + (tc == VariableArray || et->isVariablyModifiedType()), + ContainsUnexpandedParameterPack), + ElementType(et) { + ArrayTypeBits.IndexTypeQuals = tq; + ArrayTypeBits.SizeModifier = sm; + } friend class ASTContext; // ASTContext creates these. - virtual Linkage getLinkageImpl() const; - public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { - return ArraySizeModifier(SizeModifier); + return ArraySizeModifier(ArrayTypeBits.SizeModifier); } Qualifiers getIndexTypeQualifiers() const { - return Qualifiers::fromCVRMask(IndexTypeQuals); + return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); + } + unsigned getIndexTypeCVRQualifiers() const { + return ArrayTypeBits.IndexTypeQuals; } - unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || @@ -1471,12 +1863,14 @@ class ConstantArrayType : public ArrayType { ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) - : ArrayType(ConstantArray, et, can, sm, tq), + : ArrayType(ConstantArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), 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) {} + : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), + Size(size) {} friend class ASTContext; // ASTContext creates these. public: const llvm::APInt &getSize() const { return Size; } @@ -1519,7 +1913,8 @@ class IncompleteArrayType : public ArrayType { IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, unsigned tq) - : ArrayType(IncompleteArray, et, can, sm, tq) {} + : ArrayType(IncompleteArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()) {} friend class ASTContext; // ASTContext creates these. public: bool isSugared() const { return false; } @@ -1570,7 +1965,8 @@ class VariableArrayType : public ArrayType { VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) - : ArrayType(VariableArray, et, can, sm, tq), + : ArrayType(VariableArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), SizeExpr((Stmt*) e), Brackets(brackets) {} friend class ASTContext; // ASTContext creates these. @@ -1613,7 +2009,7 @@ public: /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { - ASTContext &Context; + const ASTContext &Context; /// \brief An assignment expression that will instantiate to the /// size of the array. @@ -1625,11 +2021,10 @@ class DependentSizedArrayType : public ArrayType { /// Brackets - The left and right array brackets. SourceRange Brackets; - DependentSizedArrayType(ASTContext &Context, QualType et, QualType can, + DependentSizedArrayType(const 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) {} + SourceRange brackets); + friend class ASTContext; // ASTContext creates these. public: @@ -1658,7 +2053,7 @@ public: getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E); }; @@ -1672,17 +2067,15 @@ public: /// } /// @endcode class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { - ASTContext &Context; + const ASTContext &Context; Expr *SizeExpr; /// ElementType - The element type of the array. QualType ElementType; SourceLocation loc; - DependentSizedExtVectorType(ASTContext &Context, QualType ElementType, - QualType can, Expr *SizeExpr, SourceLocation loc) - : Type (DependentSizedExtVector, can, true), - Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), - loc(loc) {} + DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, + QualType can, Expr *SizeExpr, SourceLocation loc); + friend class ASTContext; public: @@ -1702,7 +2095,7 @@ public: Profile(ID, Context, getElementType(), getSizeExpr()); } - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, Expr *SizeExpr); }; @@ -1714,53 +2107,49 @@ public: /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { public: - enum AltiVecSpecific { - NotAltiVec, // is not AltiVec vector - AltiVec, // is AltiVec vector - Pixel, // is AltiVec 'vector Pixel' - Bool // is AltiVec 'vector bool ...' + enum VectorKind { + GenericVector, // not a target-specific vector type + AltiVecVector, // is AltiVec vector + AltiVecPixel, // is AltiVec 'vector Pixel' + AltiVecBool, // is AltiVec 'vector bool ...' + NeonVector, // is ARM Neon vector + NeonPolyVector // is ARM Neon polynomial vector }; protected: /// ElementType - The element type of the vector. QualType ElementType; - /// NumElements - The number of elements in the vector. - unsigned NumElements; - - AltiVecSpecific AltiVecSpec; - VectorType(QualType vecType, unsigned nElements, QualType canonType, - AltiVecSpecific altiVecSpec) : - Type(Vector, canonType, vecType->isDependentType()), - ElementType(vecType), NumElements(nElements), AltiVecSpec(altiVecSpec) {} + VectorKind vecKind); + VectorType(TypeClass tc, QualType vecType, unsigned nElements, - QualType canonType, AltiVecSpecific altiVecSpec) - : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), - NumElements(nElements), AltiVecSpec(altiVecSpec) {} + QualType canonType, VectorKind vecKind); + friend class ASTContext; // ASTContext creates these. - virtual Linkage getLinkageImpl() const; - public: QualType getElementType() const { return ElementType; } - unsigned getNumElements() const { return NumElements; } + unsigned getNumElements() const { return VectorTypeBits.NumElements; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - AltiVecSpecific getAltiVecSpecific() const { return AltiVecSpec; } + VectorKind getVectorKind() const { + return VectorKind(VectorTypeBits.VecKind); + } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getNumElements(), getTypeClass(), AltiVecSpec); + Profile(ID, getElementType(), getNumElements(), + getTypeClass(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass, - unsigned AltiVecSpec) { + VectorKind VecKind) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); - ID.AddInteger(AltiVecSpec); + ID.AddInteger(VecKind); } static bool classof(const Type *T) { @@ -1776,7 +2165,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, NotAltiVec) {} + VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} friend class ASTContext; // ASTContext creates these. public: static int getPointAccessorIdx(char c) { @@ -1823,7 +2212,7 @@ public: bool isAccessorWithinNumElements(char c) const { if (int idx = getAccessorIdx(c)+1) - return unsigned(idx-1) < NumElements; + return unsigned(idx-1) < getNumElements(); return false; } bool isSugared() const { return false; } @@ -1839,40 +2228,20 @@ public: /// class of FunctionNoProtoType and FunctionProtoType. /// class FunctionType : public Type { - virtual void ANCHOR(); // Key function for FunctionType. - - /// SubClassData - This field is owned by the subclass, put here to pack - /// tightly with the ivars in Type. - bool SubClassData : 1; - - /// TypeQuals - Used only by FunctionProtoType, put here to pack with the - /// other bitfields. - /// The qualifiers are part of FunctionProtoType because... - /// - /// C++ 8.3.5p4: The return type, the parameter type list and the - /// cv-qualifier-seq, [...], are part of the function type. - /// - unsigned TypeQuals : 3; - - /// NoReturn - Indicates if the function type is attribute noreturn. - unsigned NoReturn : 1; - - /// RegParm - How many arguments to pass inreg. - unsigned RegParm : 3; - - /// CallConv - The calling convention used by the function. - unsigned CallConv : 3; - // The type returned by the function. QualType ResultType; public: - // This class is used for passing arround the information needed to - // construct a call. It is not actually used for storage, just for - // factoring together common arguments. - // If you add a field (say Foo), other than the obvious places (both, constructors, - // compile failures), what you need to update is - // * Operetor== + /// ExtInfo - A class which abstracts out some details necessary for + /// making a call. + /// + /// It is not actually used directly for storing this information in + /// a FunctionType, although FunctionType does currently use the + /// same bit-pattern. + /// + // If you add a field (say Foo), other than the obvious places (both, + // constructors, compile failures), what you need to update is + // * Operator== // * getFoo // * withFoo // * functionType. Add Foo, getFoo. @@ -1883,76 +2252,100 @@ class FunctionType : public Type { // * TypePrinter::PrintFunctionProto // * AST read and write // * Codegen - class ExtInfo { + // Feel free to rearrange or add bits, but if you go over 8, + // you'll need to adjust both the Bits field below and + // Type::FunctionTypeBitfields. + + // | CC |noreturn|regparm + // |0 .. 2| 3 |4 .. 6 + enum { CallConvMask = 0x7 }; + enum { NoReturnMask = 0x8 }; + enum { RegParmMask = ~(CallConvMask | NoReturnMask), + RegParmOffset = 4 }; + + unsigned char Bits; + + ExtInfo(unsigned Bits) : Bits(static_cast<unsigned char>(Bits)) {} + + friend class FunctionType; + public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) : - NoReturn(noReturn), RegParm(regParm), CC(cc) {} + ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) { + Bits = ((unsigned) cc) | + (noReturn ? NoReturnMask : 0) | + (regParm << RegParmOffset); + } // Constructor with all defaults. Use when for example creating a // function know to use defaults. - ExtInfo() : NoReturn(false), RegParm(0), CC(CC_Default) {} + ExtInfo() : Bits(0) {} - bool getNoReturn() const { return NoReturn; } - unsigned getRegParm() const { return RegParm; } - CallingConv getCC() const { return CC; } + bool getNoReturn() const { return Bits & NoReturnMask; } + unsigned getRegParm() const { return Bits >> RegParmOffset; } + CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } - bool operator==(const ExtInfo &Other) const { - return getNoReturn() == Other.getNoReturn() && - getRegParm() == Other.getRegParm() && - getCC() == Other.getCC(); + bool operator==(ExtInfo Other) const { + return Bits == Other.Bits; } - bool operator!=(const ExtInfo &Other) const { - return !(*this == Other); + bool operator!=(ExtInfo Other) const { + return Bits != Other.Bits; } // Note that we don't have setters. That is by design, use // the following with methods instead of mutating these objects. ExtInfo withNoReturn(bool noReturn) const { - return ExtInfo(noReturn, getRegParm(), getCC()); + if (noReturn) + return ExtInfo(Bits | NoReturnMask); + else + return ExtInfo(Bits & ~NoReturnMask); } ExtInfo withRegParm(unsigned RegParm) const { - return ExtInfo(getNoReturn(), RegParm, getCC()); + return ExtInfo((Bits & ~RegParmMask) | (RegParm << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { - return ExtInfo(getNoReturn(), getRegParm(), cc); + return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } - private: - // True if we have __attribute__((noreturn)) - bool NoReturn; - // The value passed to __attribute__((regparm(x))) - unsigned RegParm; - // The calling convention as specified via - // __attribute__((cdecl|stdcall|fastcall|thiscall|pascal)) - CallingConv CC; + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Bits); + } }; protected: - FunctionType(TypeClass tc, QualType res, bool SubclassInfo, - unsigned typeQuals, QualType Canonical, bool Dependent, - const ExtInfo &Info) - : Type(tc, Canonical, Dependent), - SubClassData(SubclassInfo), TypeQuals(typeQuals), - NoReturn(Info.getNoReturn()), - RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {} - bool getSubClassData() const { return SubClassData; } - unsigned getTypeQuals() const { return TypeQuals; } + FunctionType(TypeClass tc, QualType res, bool variadic, + unsigned typeQuals, RefQualifierKind RefQualifier, + QualType Canonical, bool Dependent, + bool VariablyModified, bool ContainsUnexpandedParameterPack, + ExtInfo Info) + : Type(tc, Canonical, Dependent, VariablyModified, + ContainsUnexpandedParameterPack), + ResultType(res) { + FunctionTypeBits.ExtInfo = Info.Bits; + FunctionTypeBits.Variadic = variadic; + FunctionTypeBits.TypeQuals = typeQuals; + FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier); + } + bool isVariadic() const { return FunctionTypeBits.Variadic; } + unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } + + RefQualifierKind getRefQualifier() const { + return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); + } + public: QualType getResultType() const { return ResultType; } - unsigned getRegParmType() const { return RegParm; } - bool getNoReturnAttr() const { return NoReturn; } - CallingConv getCallConv() const { return (CallingConv)CallConv; } - ExtInfo getExtInfo() const { - return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv); - } + unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } + CallingConv getCallConv() const { return getExtInfo().getCC(); } + ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } /// \brief Determine the type of an expression that calls a function of /// this type. @@ -1972,15 +2365,13 @@ 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, - const ExtInfo &Info) - : FunctionType(FunctionNoProto, Result, false, 0, Canonical, - /*Dependent=*/false, Info) {} + FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) + : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical, + /*Dependent=*/false, Result->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false, Info) {} + friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: // No additional state past what FunctionType provides. @@ -1991,10 +2382,8 @@ public: Profile(ID, getResultType(), getExtInfo()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, - const ExtInfo &Info) { - ID.AddInteger(Info.getCC()); - ID.AddInteger(Info.getRegParm()); - ID.AddInteger(Info.getNoReturn()); + ExtInfo Info) { + Info.Profile(ID); ID.AddPointer(ResultType.getAsOpaquePtr()); } @@ -2010,36 +2399,37 @@ public: /// exception specification, but this specification is not part of the canonical /// type. class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { - /// hasAnyDependentType - Determine whether there are any dependent - /// types within the arguments passed in. - static bool hasAnyDependentType(const QualType *ArgArray, unsigned numArgs) { +public: + /// ExtProtoInfo - Extra information about a function prototype. + struct ExtProtoInfo { + ExtProtoInfo() : + Variadic(false), HasExceptionSpec(false), HasAnyExceptionSpec(false), + TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0) {} + + FunctionType::ExtInfo ExtInfo; + bool Variadic; + bool HasExceptionSpec; + bool HasAnyExceptionSpec; + unsigned char TypeQuals; + RefQualifierKind RefQualifier; + unsigned NumExceptions; + const QualType *Exceptions; + }; + +private: + /// \brief Determine whether there are any argument types that + /// contain an unexpanded parameter pack. + static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, + unsigned numArgs) { for (unsigned Idx = 0; Idx < numArgs; ++Idx) - if (ArgArray[Idx]->isDependentType()) - return true; + if (ArgArray[Idx]->containsUnexpandedParameterPack()) + return true; return false; } - FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs, - bool isVariadic, unsigned typeQuals, bool hasExs, - bool hasAnyExs, const QualType *ExArray, - unsigned numExs, QualType Canonical, - const ExtInfo &Info) - : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, - (Result->isDependentType() || - hasAnyDependentType(ArgArray, numArgs)), - Info), - NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs), - AnyExceptionSpec(hasAnyExs) { - // Fill in the trailing argument array. - QualType *ArgInfo = reinterpret_cast<QualType*>(this+1); - for (unsigned i = 0; i != numArgs; ++i) - ArgInfo[i] = ArgArray[i]; - // Fill in the exception array. - QualType *Ex = ArgInfo + numArgs; - for (unsigned i = 0; i != numExs; ++i) - Ex[i] = ExArray[i]; - } + FunctionProtoType(QualType result, const QualType *args, unsigned numArgs, + QualType canonical, const ExtProtoInfo &epi); /// NumArgs - The number of arguments this function has, not counting '...'. unsigned NumArgs : 20; @@ -2048,10 +2438,10 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { unsigned NumExceptions : 10; /// HasExceptionSpec - Whether this function has an exception spec at all. - bool HasExceptionSpec : 1; + unsigned HasExceptionSpec : 1; - /// AnyExceptionSpec - Whether this function has a throw(...) spec. - bool AnyExceptionSpec : 1; + /// HasAnyExceptionSpec - Whether this function has a throw(...) spec. + unsigned HasAnyExceptionSpec : 1; /// ArgInfo - There is an variable size array after the class in memory that /// holds the argument types. @@ -2061,9 +2451,6 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: unsigned getNumArgs() const { return NumArgs; } QualType getArgType(unsigned i) const { @@ -2071,8 +2458,21 @@ public: return arg_type_begin()[i]; } + ExtProtoInfo getExtProtoInfo() const { + ExtProtoInfo EPI; + EPI.ExtInfo = getExtInfo(); + EPI.Variadic = isVariadic(); + EPI.HasExceptionSpec = hasExceptionSpec(); + EPI.HasAnyExceptionSpec = hasAnyExceptionSpec(); + EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals()); + EPI.RefQualifier = getRefQualifier(); + EPI.NumExceptions = NumExceptions; + EPI.Exceptions = exception_begin(); + return EPI; + } + bool hasExceptionSpec() const { return HasExceptionSpec; } - bool hasAnyExceptionSpec() const { return AnyExceptionSpec; } + bool hasAnyExceptionSpec() const { return HasAnyExceptionSpec; } unsigned getNumExceptions() const { return NumExceptions; } QualType getExceptionType(unsigned i) const { assert(i < NumExceptions && "Invalid exception number!"); @@ -2083,9 +2483,24 @@ public: getNumExceptions() == 0; } - bool isVariadic() const { return getSubClassData(); } + using FunctionType::isVariadic; + + /// \brief Determines whether this function prototype contains a + /// parameter pack at the end. + /// + /// A function template whose last parameter is a parameter pack can be + /// called with an arbitrary number of arguments, much like a variadic + /// function. However, + bool isTemplateVariadic() const; + unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + + /// \brief Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return FunctionType::getRefQualifier(); + } + typedef const QualType *arg_type_iterator; arg_type_iterator arg_type_begin() const { return reinterpret_cast<const QualType *>(this+1); @@ -2112,10 +2527,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, - bool isVariadic, unsigned TypeQuals, - bool hasExceptionSpec, bool anyExceptionSpec, - unsigned NumExceptions, exception_iterator Exs, - const ExtInfo &ExtInfo); + const ExtProtoInfo &EPI); }; @@ -2127,7 +2539,8 @@ class UnresolvedUsingType : public Type { UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), true), + : Type(UnresolvedUsing, QualType(), true, false, + /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {} friend class ASTContext; // ASTContext creates these. public: @@ -2156,7 +2569,8 @@ class TypedefType : public Type { TypedefDecl *Decl; protected: TypedefType(TypeClass tc, const TypedefDecl *D, QualType can) - : Type(tc, can, can->isDependentType()), + : Type(tc, can, can->isDependentType(), can->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast<TypedefDecl*>(D)) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } @@ -2165,14 +2579,6 @@ 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: - /// typedef const int A; - /// typedef volatile A B; - /// looking through the typedefs for B will give you "const volatile A". - QualType LookThroughTypedefs() const; - bool isSugared() const { return true; } QualType desugar() const; @@ -2208,10 +2614,10 @@ public: /// of this class via TypeOfExprType nodes. class DependentTypeOfExprType : public TypeOfExprType, public llvm::FoldingSetNode { - ASTContext &Context; + const ASTContext &Context; public: - DependentTypeOfExprType(ASTContext &Context, Expr *E) + DependentTypeOfExprType(const ASTContext &Context, Expr *E) : TypeOfExprType(E), Context(Context) { } bool isSugared() const { return false; } @@ -2221,7 +2627,7 @@ public: Profile(ID, Context, getUnderlyingExpr()); } - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; @@ -2229,7 +2635,9 @@ public: class TypeOfType : public Type { QualType TOType; TypeOfType(QualType T, QualType can) - : Type(TypeOf, can, T->isDependentType()), TOType(T) { + : Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType(), + T->containsUnexpandedParameterPack()), + TOType(T) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } friend class ASTContext; // ASTContext creates these. @@ -2279,10 +2687,10 @@ public: /// canonical, dependent types, only. Clients will only see instances /// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { - ASTContext &Context; + const ASTContext &Context; public: - DependentDecltypeType(ASTContext &Context, Expr *E); + DependentDecltypeType(const ASTContext &Context, Expr *E); bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2291,7 +2699,7 @@ public: Profile(ID, Context, getUnderlyingExpr()); } - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; @@ -2303,8 +2711,6 @@ class TagType : public Type { protected: TagType(TypeClass TC, const TagDecl *D, QualType can); - virtual Linkage getLinkageImpl() const; - public: TagDecl *getDecl() const; @@ -2340,10 +2746,6 @@ public: // 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); } @@ -2376,20 +2778,107 @@ public: static bool classof(const EnumType *) { return true; } }; +/// AttributedType - An attributed type is a type to which a type +/// attribute has been applied. The "modified type" is the +/// fully-sugared type to which the attributed type was applied; +/// generally it is not canonically equivalent to the attributed type. +/// The "equivalent type" is the minimally-desugared type which the +/// type is canonically equivalent to. +/// +/// For example, in the following attributed type: +/// int32_t __attribute__((vector_size(16))) +/// - the modified type is the TypedefType for int32_t +/// - the equivalent type is VectorType(16, int32_t) +/// - the canonical type is VectorType(16, int) +class AttributedType : public Type, public llvm::FoldingSetNode { +public: + // It is really silly to have yet another attribute-kind enum, but + // clang::attr::Kind doesn't currently cover the pure type attrs. + enum Kind { + // Expression operand. + attr_address_space, + attr_regparm, + attr_vector_size, + attr_neon_vector_type, + attr_neon_polyvector_type, + + FirstExprOperandKind = attr_address_space, + LastExprOperandKind = attr_neon_polyvector_type, + + // Enumerated operand (string or keyword). + attr_objc_gc, + + FirstEnumOperandKind = attr_objc_gc, + LastEnumOperandKind = attr_objc_gc, + + // No operand. + attr_noreturn, + attr_cdecl, + attr_fastcall, + attr_stdcall, + attr_thiscall, + attr_pascal + }; + +private: + QualType ModifiedType; + QualType EquivalentType; + + friend class ASTContext; // creates these + + AttributedType(QualType canon, Kind attrKind, + QualType modified, QualType equivalent) + : Type(Attributed, canon, canon->isDependentType(), + canon->isVariablyModifiedType(), + canon->containsUnexpandedParameterPack()), + ModifiedType(modified), EquivalentType(equivalent) { + AttributedTypeBits.AttrKind = attrKind; + } + +public: + Kind getAttrKind() const { + return static_cast<Kind>(AttributedTypeBits.AttrKind); + } + + QualType getModifiedType() const { return ModifiedType; } + QualType getEquivalentType() const { return EquivalentType; } + + bool isSugared() const { return true; } + QualType desugar() const { return getEquivalentType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), ModifiedType, EquivalentType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent) { + ID.AddInteger(attrKind); + ID.AddPointer(modified.getAsOpaquePtr()); + ID.AddPointer(equivalent.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Attributed; + } + static bool classof(const AttributedType *T) { return true; } +}; + class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { unsigned Depth : 15; - unsigned Index : 16; unsigned ParameterPack : 1; + unsigned Index : 16; IdentifierInfo *Name; TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N, QualType Canon) - : Type(TemplateTypeParm, Canon, /*Dependent=*/true), - Depth(D), Index(I), ParameterPack(PP), Name(N) { } + : Type(TemplateTypeParm, Canon, /*Dependent=*/true, + /*VariablyModified=*/false, PP), + Depth(D), ParameterPack(PP), Index(I), Name(N) { } TemplateTypeParmType(unsigned D, unsigned I, bool PP) - : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true), - Depth(D), Index(I), ParameterPack(PP), Name(0) { } + : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true, + /*VariablyModified=*/false, PP), + Depth(D), ParameterPack(PP), Index(I), Name(0) { } friend class ASTContext; // ASTContext creates these @@ -2433,7 +2922,9 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) - : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType()), + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), + Canon->isVariablyModifiedType(), + Canon->containsUnexpandedParameterPack()), Replaced(Param) { } friend class ASTContext; @@ -2471,6 +2962,101 @@ public: static bool classof(const SubstTemplateTypeParmType *T) { return true; } }; +/// \brief Represents the result of substituting a set of types for a template +/// type parameter pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this type node is used to represent a template type +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType +/// at the current pack substitution index. +class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { + /// \brief The original type parameter. + const TemplateTypeParmType *Replaced; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack); + + friend class ASTContext; + +public: + IdentifierInfo *getName() const { return Replaced->getName(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack; + } + static bool classof(const SubstTemplateTypeParmPackType *T) { return true; } +}; + +/// \brief Represents a C++0x auto type. +/// +/// These types are usually a placeholder for a deduced type. However, within +/// templates and before the initializer is attached, there is no deduced type +/// and an auto type is type-dependent and canonical. +class AutoType : public Type, public llvm::FoldingSetNode { + AutoType(QualType DeducedType) + : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, + /*Dependent=*/DeducedType.isNull(), + /*VariablyModified=*/false, /*ContainsParameterPack=*/false) { + assert((DeducedType.isNull() || !DeducedType->isDependentType()) && + "deduced a dependent type for auto"); + } + + friend class ASTContext; // ASTContext creates these + +public: + bool isSugared() const { return isDeduced(); } + QualType desugar() const { return getCanonicalTypeInternal(); } + + QualType getDeducedType() const { + return isDeduced() ? getCanonicalTypeInternal() : QualType(); + } + bool isDeduced() const { + return !isDependentType(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDeducedType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Deduced) { + ID.AddPointer(Deduced.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto; + } + static bool classof(const AutoType *T) { return true; } +}; + /// \brief Represents the type of a template specialization as written /// in the source code. /// @@ -2516,7 +3102,8 @@ public: /// enclosing the template arguments. static std::string PrintTemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs, - const PrintingPolicy &Policy); + const PrintingPolicy &Policy, + bool SkipBrackets = false); static std::string PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, @@ -2556,14 +3143,14 @@ public: } QualType desugar() const { return getCanonicalTypeInternal(); } - void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Ctx) { + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, getArgs(), NumArgs, Ctx); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, const TemplateArgument *Args, unsigned NumArgs, - ASTContext &Context); + const ASTContext &Context); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; @@ -2607,7 +3194,9 @@ class InjectedClassNameType : public Type { // currently suitable for AST reading, too much // interdependencies. InjectedClassNameType(CXXRecordDecl *D, QualType TST) - : Type(InjectedClassName, QualType(), true), + : Type(InjectedClassName, QualType(), /*Dependent=*/true, + /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), Decl(D), InjectedType(TST) { assert(isa<TemplateSpecializationType>(TST)); assert(!TST.hasQualifiers()); @@ -2666,19 +3255,18 @@ enum ElaboratedTypeKeyword { /// Also provides a few static helpers for converting and printing /// elaborated type keyword and tag type kind enumerations. class TypeWithKeyword : public Type { - /// Keyword - Encodes an ElaboratedTypeKeyword enumeration constant. - unsigned Keyword : 3; - protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, bool dependent) - : Type(tc, Canonical, dependent), Keyword(Keyword) {} + QualType Canonical, bool Dependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : Type(tc, Canonical, Dependent, VariablyModified, + ContainsUnexpandedParameterPack) { + TypeWithKeywordBits.Keyword = Keyword; + } public: - virtual ~TypeWithKeyword(); // pin vtable to Type.cpp - ElaboratedTypeKeyword getKeyword() const { - return static_cast<ElaboratedTypeKeyword>(Keyword); + return static_cast<ElaboratedTypeKeyword>(TypeWithKeywordBits.Keyword); } /// getKeywordForTypeSpec - Converts a type specifier (DeclSpec::TST) @@ -2730,7 +3318,9 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType) : TypeWithKeyword(Keyword, Elaborated, CanonType, - NamedType->isDependentType()), + NamedType->isDependentType(), + NamedType->isVariablyModifiedType(), + NamedType->containsUnexpandedParameterPack()), NNS(NNS), NamedType(NamedType) { assert(!(Keyword == ETK_None && NNS == 0) && "ElaboratedType cannot have elaborated type keyword " @@ -2790,7 +3380,9 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) - : TypeWithKeyword(Keyword, DependentName, CanonType, true), + : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, + /*VariablyModified=*/false, + NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name) { assert(NNS->isDependent() && "DependentNameType requires a dependent nested-name-specifier"); @@ -2799,8 +3391,6 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these public: - virtual ~DependentNameType(); - /// \brief Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } @@ -2867,8 +3457,6 @@ class DependentTemplateSpecializationType : friend class ASTContext; // ASTContext creates these public: - virtual ~DependentTemplateSpecializationType(); - NestedNameSpecifier *getQualifier() const { return NNS; } const IdentifierInfo *getIdentifier() const { return Name; } @@ -2889,12 +3477,12 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) { + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getKeyword(), NNS, Name, NumArgs, getArgs()); } static void Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, + const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, @@ -2909,6 +3497,88 @@ public: } }; +/// \brief Represents a pack expansion of types. +/// +/// Pack expansions are part of C++0x variadic templates. A pack +/// expansion contains a pattern, which itself contains one or more +/// "unexpanded" parameter packs. When instantiated, a pack expansion +/// produces a series of types, each instantiated from the pattern of +/// the expansion, where the Ith instantiation of the pattern uses the +/// Ith arguments bound to each of the unexpanded parameter packs. The +/// pack expansion is considered to "expand" these unexpanded +/// parameter packs. +/// +/// \code +/// template<typename ...Types> struct tuple; +/// +/// template<typename ...Types> +/// struct tuple_of_references { +/// typedef tuple<Types&...> type; +/// }; +/// \endcode +/// +/// Here, the pack expansion \c Types&... is represented via a +/// PackExpansionType whose pattern is Types&. +class PackExpansionType : public Type, public llvm::FoldingSetNode { + /// \brief The pattern of the pack expansion. + QualType Pattern; + + /// \brief The number of expansions that this pack expansion will + /// generate when substituted (+1), or indicates that + /// + /// This field will only have a non-zero value when some of the parameter + /// packs that occur within the pattern have been substituted but others have + /// not. + unsigned NumExpansions; + + PackExpansionType(QualType Pattern, QualType Canon, + llvm::Optional<unsigned> NumExpansions) + : Type(PackExpansion, Canon, /*Dependent=*/true, + /*VariableModified=*/Pattern->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Pattern(Pattern), + NumExpansions(NumExpansions? *NumExpansions + 1: 0) { } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the pattern of this pack expansion, which is the + /// type that will be repeatedly instantiated when instantiating the + /// pack expansion itself. + QualType getPattern() const { return Pattern; } + + /// \brief Retrieve the number of expansions that this pack expansion will + /// generate, if known. + llvm::Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return llvm::Optional<unsigned>(); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPattern(), getNumExpansions()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, + llvm::Optional<unsigned> NumExpansions) { + ID.AddPointer(Pattern.getAsOpaquePtr()); + ID.AddBoolean(NumExpansions); + if (NumExpansions) + ID.AddInteger(*NumExpansions); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackExpansion; + } + static bool classof(const PackExpansionType *T) { + return true; + } +}; + /// ObjCObjectType - Represents a class type in Objective C. /// Every Objective C type is a combination of a base type and a /// list of protocols. @@ -2930,19 +3600,15 @@ public: /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type { - // Pad the bit count up so that NumProtocols is 2-byte aligned - unsigned : BitsRemainingInType - 16; - - /// \brief The number of protocols stored after the - /// ObjCObjectPointerType node. - /// - /// These protocols are those written directly on the type. If - /// protocol qualifiers ever become additive, the iterators will - /// get kindof complicated. - /// - /// In the canonical object type, these are sorted alphabetically - /// and uniqued. - unsigned NumProtocols : 16; + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the ObjCObjectPointerType node. + // + // These protocols are those written directly on the type. If + // protocol qualifiers ever become additive, the iterators will need + // to get kindof complicated. + // + // In the canonical object type, these are sorted alphabetically + // and uniqued. /// Either a BuiltinType or an InterfaceType or sugar for either. QualType BaseType; @@ -2959,13 +3625,11 @@ protected: enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(enum Nonce_ObjCInterface) - : Type(ObjCInterface, QualType(), false), - NumProtocols(0), - BaseType(QualType(this_(), 0)) {} + : Type(ObjCInterface, QualType(), false, false, false), + BaseType(QualType(this_(), 0)) { + ObjCObjectTypeBits.NumProtocols = 0; + } -protected: - Linkage getLinkageImpl() const; // key function - public: /// getBaseType - Gets the base type of this object type. This is /// always (possibly sugar for) one of: @@ -3006,7 +3670,7 @@ public: /// getNumProtocols - Return the number of qualifying protocols in this /// interface type, or 0 if there are none. - unsigned getNumProtocols() const { return NumProtocols; } + unsigned getNumProtocols() const { return ObjCObjectTypeBits.NumProtocols; } /// \brief Fetch a protocol by index. ObjCProtocolDecl *getProtocol(unsigned I) const { @@ -3072,6 +3736,7 @@ class ObjCInterfaceType : public ObjCObjectType { : ObjCObjectType(Nonce_ObjCInterface), Decl(const_cast<ObjCInterfaceDecl*>(D)) {} friend class ASTContext; // ASTContext creates these. + public: /// getDecl - Get the declaration of this interface. ObjCInterfaceDecl *getDecl() const { return Decl; } @@ -3117,13 +3782,10 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, false), + : Type(ObjCObjectPointer, Canonical, false, false, false), PointeeType(Pointee) {} friend class ASTContext; // ASTContext creates these. -protected: - virtual Linkage getLinkageImpl() const; - public: /// getPointeeType - Gets the type pointed to by this ObjC pointer. /// The result will always be an ObjCObjectType or sugar thereof. @@ -3152,7 +3814,7 @@ public: /// would return 'A1P<Q>' (and we'd have to make iterating over /// qualifiers more complicated). const ObjCObjectType *getObjectType() const { - return PointeeType->getAs<ObjCObjectType>(); + return PointeeType->castAs<ObjCObjectType>(); } /// getInterfaceType - If this pointer points to an Objective C @@ -3238,177 +3900,154 @@ public: /// 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; } + QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} /// Collect any qualifiers on the given type and return an - /// unqualified type. - const Type *strip(QualType QT) { - addFastQualifiers(QT.getLocalFastQualifiers()); - if (QT.hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = QT.getExtQualsUnsafe(); - Context = &EQ->getContext(); - addQualifiers(EQ->getQualifiers()); - return EQ->getBaseType(); - } - return QT.getTypePtrUnsafe(); + /// unqualified type. The qualifiers are assumed to be consistent + /// with those already in the type. + const Type *strip(QualType type) { + addFastQualifiers(type.getLocalFastQualifiers()); + if (!type.hasLocalNonFastQualifiers()) + return type.getTypePtrUnsafe(); + + const ExtQuals *extQuals = type.getExtQualsUnsafe(); + addConsistentQualifiers(extQuals->getQualifiers()); + return extQuals->getBaseType(); } /// Apply the collected qualifiers to the given type. - QualType apply(QualType QT) const; + QualType apply(const ASTContext &Context, QualType QT) const; /// Apply the collected qualifiers to the given type. - QualType apply(const Type* T) const; - + QualType apply(const ASTContext &Context, const Type* T) const; }; // Inline function definitions. +inline const Type *QualType::getTypePtr() const { + return getCommonPtr()->BaseType; +} + +inline const Type *QualType::getTypePtrOrNull() const { + return (isNull() ? 0 : getCommonPtr()->BaseType); +} + +inline SplitQualType QualType::split() const { + if (!hasLocalNonFastQualifiers()) + return SplitQualType(getTypePtrUnsafe(), + Qualifiers::fromFastMask(getLocalFastQualifiers())); + + const ExtQuals *eq = getExtQualsUnsafe(); + Qualifiers qs = eq->getQualifiers(); + qs.addFastQualifiers(getLocalFastQualifiers()); + return SplitQualType(eq->getBaseType(), qs); +} + +inline Qualifiers QualType::getLocalQualifiers() const { + Qualifiers Quals; + if (hasLocalNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getLocalFastQualifiers()); + return Quals; +} + +inline Qualifiers QualType::getQualifiers() const { + Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); + quals.addFastQualifiers(getLocalFastQualifiers()); + return quals; +} + +inline unsigned QualType::getCVRQualifiers() const { + unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); + cvr |= getLocalCVRQualifiers(); + return cvr; +} + +inline QualType QualType::getCanonicalType() const { + QualType canon = getCommonPtr()->CanonicalType; + return canon.withFastQualifiers(getLocalFastQualifiers()); +} + inline bool QualType::isCanonical() const { - const Type *T = getTypePtr(); - if (hasLocalQualifiers()) - return T->isCanonicalUnqualified() && !isa<ArrayType>(T); - return T->isCanonicalUnqualified(); + return getTypePtr()->isCanonicalUnqualified(); } inline bool QualType::isCanonicalAsParam() const { + if (!isCanonical()) return false; if (hasLocalQualifiers()) return false; + const Type *T = getTypePtr(); - return T->isCanonicalUnqualified() && - !isa<FunctionType>(T) && !isa<ArrayType>(T); + if (T->isVariablyModifiedType() && T->hasSizedVLAType()) + return false; + + return !isa<FunctionType>(T) && !isa<ArrayType>(T); } inline bool QualType::isConstQualified() const { return isLocalConstQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalConstQualified(); + getCommonPtr()->CanonicalType.isLocalConstQualified(); } inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalRestrictQualified(); + getCommonPtr()->CanonicalType.isLocalRestrictQualified(); } inline bool QualType::isVolatileQualified() const { return isLocalVolatileQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalVolatileQualified(); + getCommonPtr()->CanonicalType.isLocalVolatileQualified(); } inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || - getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers(); -} - -inline Qualifiers QualType::getQualifiers() const { - Qualifiers Quals = getLocalQualifiers(); - Quals.addQualifiers( - getTypePtr()->getCanonicalTypeInternal().getLocalQualifiers()); - return Quals; -} - -inline unsigned QualType::getCVRQualifiers() const { - return getLocalCVRQualifiers() | - getTypePtr()->getCanonicalTypeInternal().getLocalCVRQualifiers(); + getCommonPtr()->CanonicalType.hasLocalQualifiers(); } -/// getCVRQualifiersThroughArrayTypes - If there are CVR qualifiers for this -/// type, returns them. Otherwise, if this is an array type, recurses -/// on the element type until some qualifiers have been found or a non-array -/// type reached. -inline unsigned QualType::getCVRQualifiersThroughArrayTypes() const { - if (unsigned Quals = getCVRQualifiers()) - return Quals; - QualType CT = getTypePtr()->getCanonicalTypeInternal(); - if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) - return AT->getElementType().getCVRQualifiersThroughArrayTypes(); - return 0; +inline QualType QualType::getUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return QualType(getTypePtr(), 0); + + return QualType(getSplitUnqualifiedTypeImpl(*this).first, 0); } -inline void QualType::removeConst() { - removeFastQualifiers(Qualifiers::Const); +inline SplitQualType QualType::getSplitUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return split(); + + return getSplitUnqualifiedTypeImpl(*this); +} + +inline void QualType::removeLocalConst() { + removeLocalFastQualifiers(Qualifiers::Const); } -inline void QualType::removeRestrict() { - removeFastQualifiers(Qualifiers::Restrict); +inline void QualType::removeLocalRestrict() { + removeLocalFastQualifiers(Qualifiers::Restrict); } -inline void QualType::removeVolatile() { - QualifierCollector Qc; - const Type *Ty = Qc.strip(*this); - if (Qc.hasVolatile()) { - Qc.removeVolatile(); - *this = Qc.apply(Ty); - } +inline void QualType::removeLocalVolatile() { + removeLocalFastQualifiers(Qualifiers::Volatile); } -inline void QualType::removeCVRQualifiers(unsigned Mask) { +inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); + assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask); // Fast path: we don't need to touch the slow qualifiers. - if (!(Mask & ~Qualifiers::FastMask)) { - removeFastQualifiers(Mask); - return; - } - - QualifierCollector Qc; - const Type *Ty = Qc.strip(*this); - Qc.removeCVRQualifiers(Mask); - *this = Qc.apply(Ty); + removeLocalFastQualifiers(Mask); } /// getAddressSpace - Return the address space of this type. inline unsigned QualType::getAddressSpace() const { - if (hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = getExtQualsUnsafe(); - if (EQ->hasAddressSpace()) - return EQ->getAddressSpace(); - } - - QualType CT = getTypePtr()->getCanonicalTypeInternal(); - if (CT.hasLocalNonFastQualifiers()) { - 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(); - return 0; + return getQualifiers().getAddressSpace(); } /// getObjCGCAttr - Return the gc attribute of this type. inline Qualifiers::GC QualType::getObjCGCAttr() const { - if (hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = getExtQualsUnsafe(); - if (EQ->hasObjCGCAttr()) - return EQ->getObjCGCAttr(); - } - - QualType CT = getTypePtr()->getCanonicalTypeInternal(); - if (CT.hasLocalNonFastQualifiers()) { - 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 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; + return getQualifiers().getObjCGCAttr(); } inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { @@ -3436,26 +4075,18 @@ inline bool Qualifiers::isSupersetOf(Qualifiers Other) const { /// 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->getCVRQualifiersThroughArrayTypes(); - unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes(); - if (getAddressSpace() != Other.getAddressSpace()) - return false; - return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals; +inline bool QualType::isMoreQualifiedThan(QualType other) const { + Qualifiers myQuals = getQualifiers(); + Qualifiers otherQuals = other.getQualifiers(); + return (myQuals != otherQuals && myQuals.compatiblyIncludes(otherQuals)); } /// isAtLeastAsQualifiedAs - Determine whether this type is at last /// as qualified as the Other type. For example, "const volatile /// 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->getCVRQualifiersThroughArrayTypes(); - unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes(); - if (getAddressSpace() != Other.getAddressSpace()) - return false; - return (MyQuals | OtherQuals) == MyQuals; +inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { + return getQualifiers().compatiblyIncludes(other.getQualifiers()); } /// getNonReferenceType - If Type is a reference type (e.g., const @@ -3496,7 +4127,7 @@ inline bool Type::isRValueReferenceType() const { return isa<RValueReferenceType>(CanonicalType); } inline bool Type::isFunctionPointerType() const { - if (const PointerType* T = getAs<PointerType>()) + if (const PointerType *T = getAs<PointerType>()) return T->getPointeeType()->isFunctionType(); else return false; @@ -3531,9 +4162,15 @@ inline bool Type::isVariableArrayType() const { inline bool Type::isDependentSizedArrayType() const { return isa<DependentSizedArrayType>(CanonicalType); } +inline bool Type::isBuiltinType() const { + return isa<BuiltinType>(CanonicalType); +} inline bool Type::isRecordType() const { return isa<RecordType>(CanonicalType); } +inline bool Type::isEnumeralType() const { + return isa<EnumType>(CanonicalType); +} inline bool Type::isAnyComplexType() const { return isa<ComplexType>(CanonicalType); } @@ -3586,10 +4223,6 @@ inline bool Type::isTemplateTypeParmType() const { return isa<TemplateTypeParmType>(CanonicalType); } -inline bool Type::isBuiltinType() const { - return getAs<BuiltinType>(); -} - inline bool Type::isSpecificBuiltinType(unsigned K) const { if (const BuiltinType *BT = getAs<BuiltinType>()) if (BT->getKind() == (BuiltinType::Kind) K) @@ -3597,6 +4230,12 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const { return false; } +inline bool Type::isPlaceholderType() const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + return BT->isPlaceholderType(); + return false; +} + /// \brief Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { @@ -3612,6 +4251,13 @@ inline bool Type::hasObjCPointerRepresentation() const { return isObjCObjectPointerType(); } +inline const Type *Type::getBaseElementTypeUnsafe() const { + const Type *type = this; + while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) + type = arrayType->getElementType().getTypePtr(); + return type; +} + /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, @@ -3658,6 +4304,35 @@ template <typename T> const T *Type::getAs() const { return cast<T>(getUnqualifiedDesugaredType()); } +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +template <typename T> const T *Type::castAs() const { + ArrayType_cannot_be_used_with_getAs<T> at; + (void) at; + + assert(isa<T>(CanonicalType)); + if (const T *ty = dyn_cast<T>(this)) return ty; + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa<ArrayType>(CanonicalType)); + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) return arr; + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + } // end namespace clang #endif diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index f1c64bd95977..c7f5ee76330c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -20,6 +20,7 @@ #include "clang/Basic/Specifiers.h" namespace clang { + class ASTContext; class ParmVarDecl; class TypeSourceInfo; class UnqualTypeLoc; @@ -38,7 +39,7 @@ class TypeLoc { protected: // The correctness of this relies on the property that, for Type *Ty, // QualType(Ty, 0).getAsOpaquePtr() == (void*) Ty - void *Ty; + const void *Ty; void *Data; public: @@ -56,7 +57,7 @@ public: TypeLoc() : Ty(0), Data(0) { } TypeLoc(QualType ty, void *opaqueData) : Ty(ty.getAsOpaquePtr()), Data(opaqueData) { } - TypeLoc(Type *ty, void *opaqueData) + TypeLoc(const Type *ty, void *opaqueData) : Ty(ty), Data(opaqueData) { } TypeLocClass getTypeLocClass() const { @@ -76,7 +77,7 @@ public: return QualType::getFromOpaquePtr(Ty); } - Type *getTypePtr() const { + const Type *getTypePtr() const { return QualType::getFromOpaquePtr(Ty).getTypePtr(); } @@ -115,13 +116,36 @@ public: /// \brief Skips past any qualifiers, if this is qualified. UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header + TypeLoc IgnoreParens() const { + if (isa<ParenTypeLoc>(this)) + return IgnoreParensImpl(*this); + return *this; + } + /// \brief Initializes this to state that every location in this /// type is the given location. /// /// This method exists to provide a simple transition for code that /// relies on location-less types. - void initialize(SourceLocation Loc) const { - initializeImpl(*this, Loc); + void initialize(ASTContext &Context, SourceLocation Loc) const { + initializeImpl(Context, *this, Loc); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. + void initializeFullCopy(TypeLoc Other) const { + assert(getType() == Other.getType()); + size_t Size = getFullDataSize(); + memcpy(getOpaqueData(), Other.getOpaqueData(), Size); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. The given size must be the full data + /// size. + void initializeFullCopy(TypeLoc Other, unsigned Size) const { + assert(getType() == Other.getType()); + assert(getFullDataSize() == Size); + memcpy(getOpaqueData(), Other.getOpaqueData(), Size); } friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { @@ -135,8 +159,9 @@ public: static bool classof(const TypeLoc *TL) { return true; } private: - static void initializeImpl(TypeLoc TL, SourceLocation Loc); + static void initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc); static TypeLoc getNextTypeLocImpl(TypeLoc TL); + static TypeLoc IgnoreParensImpl(TypeLoc TL); static SourceRange getLocalSourceRangeImpl(TypeLoc TL); }; @@ -146,14 +171,14 @@ inline TypeLoc TypeSourceInfo::getTypeLoc() const { } /// \brief Wrapper of type source information for a type with -/// no direct quqlaifiers. +/// no direct qualifiers. class UnqualTypeLoc : public TypeLoc { public: UnqualTypeLoc() {} - UnqualTypeLoc(Type *Ty, void *Data) : TypeLoc(Ty, Data) {} + UnqualTypeLoc(const Type *Ty, void *Data) : TypeLoc(Ty, Data) {} - Type *getTypePtr() const { - return reinterpret_cast<Type*>(Ty); + const Type *getTypePtr() const { + return reinterpret_cast<const Type*>(Ty); } TypeLocClass getTypeLocClass() const { @@ -183,7 +208,7 @@ public: /// Initializes the local data of this type source info block to /// provide no information. - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { // do nothing } @@ -282,7 +307,7 @@ public: return getNextTypeLoc(asDerived()->getInnerType()); } - TypeClass *getTypePtr() const { + const TypeClass *getTypePtr() const { return cast<TypeClass>(Base::getTypePtr()); } @@ -355,7 +380,7 @@ public: return true; } - TypeClass *getTypePtr() const { + const TypeClass *getTypePtr() const { return cast<TypeClass>(Base::getTypePtr()); } }; @@ -383,7 +408,7 @@ public: SourceRange getLocalSourceRange() const { return SourceRange(getNameLoc(), getNameLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); } @@ -484,7 +509,7 @@ public: getWrittenBuiltinSpecs().ModeAttr = written; } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setBuiltinLoc(Loc); if (needsExtraLocalData()) { WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs(); @@ -568,6 +593,137 @@ class SubstTemplateTypeParmTypeLoc : SubstTemplateTypeParmType> { }; + /// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmPackTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmPackTypeLoc, + SubstTemplateTypeParmPackType> { +}; + +struct AttributedLocInfo { + union { + Expr *ExprOperand; + + /// A raw SourceLocation. + unsigned EnumOperandLoc; + }; + + SourceRange OperandParens; + + SourceLocation AttrLoc; +}; + +/// \brief Type source information for an attributed type. +class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + AttributedTypeLoc, + AttributedType, + AttributedLocInfo> { +public: + AttributedType::Kind getAttrKind() const { + return getTypePtr()->getAttrKind(); + } + + bool hasAttrExprOperand() const { + return (getAttrKind() >= AttributedType::FirstExprOperandKind && + getAttrKind() <= AttributedType::LastExprOperandKind); + } + + bool hasAttrEnumOperand() const { + return (getAttrKind() >= AttributedType::FirstEnumOperandKind && + getAttrKind() <= AttributedType::LastEnumOperandKind); + } + + bool hasAttrOperand() const { + return hasAttrExprOperand() || hasAttrEnumOperand(); + } + + /// The modified type, which is generally canonically different from + /// the attribute type. + /// int main(int, char**) __attribute__((noreturn)) + /// ~~~ ~~~~~~~~~~~~~ + TypeLoc getModifiedLoc() const { + return getInnerTypeLoc(); + } + + /// The location of the attribute name, i.e. + /// __attribute__((regparm(1000))) + /// ^~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// void *cur_thread __attribute__((address_space(21))) + /// ^~ + Expr *getAttrExprOperand() const { + assert(hasAttrExprOperand()); + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + assert(hasAttrExprOperand()); + getLocalData()->ExprOperand = e; + } + + /// The location of the attribute's enumerated operand, if it has one. + /// void * __attribute__((objc_gc(weak))) + /// ^~~~ + SourceLocation getAttrEnumOperandLoc() const { + assert(hasAttrEnumOperand()); + return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc); + } + void setAttrEnumOperandLoc(SourceLocation loc) { + assert(hasAttrEnumOperand()); + getLocalData()->EnumOperandLoc = loc.getRawEncoding(); + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// void * __attribute__((objc_gc(weak))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + assert(hasAttrOperand()); + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + assert(hasAttrOperand()); + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + // Note that this does *not* include the range of the attribute + // enclosure, e.g.: + // __attribute__((foo(bar))) + // ^~~~~~~~~~~~~~~ ~~ + // or + // [[foo(bar)]] + // ^~ ~~ + // That enclosure doesn't necessarily belong to a single attribute + // anyway. + SourceRange range(getAttrNameLoc()); + if (hasAttrOperand()) + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + if (hasAttrExprOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(0); + } else if (hasAttrEnumOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrEnumOperandLoc(loc); + } + } + + QualType getInnerType() const { + return getTypePtr()->getModifiedType(); + } +}; + struct ObjCProtocolListLocInfo { SourceLocation LAngleLoc; @@ -638,7 +794,7 @@ public: return SourceRange(getLAngleLoc(), getRAngleLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setHasBaseTypeAsWritten(true); setLAngleLoc(Loc); setRAngleLoc(Loc); @@ -682,11 +838,51 @@ public: return SourceRange(getNameLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); } }; +struct ParenLocInfo { + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +class ParenTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, ParenTypeLoc, ParenType, + ParenLocInfo> { +public: + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + TypeLoc getInnerLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getInnerType(); + } +}; + struct PointerLikeLocInfo { SourceLocation StarLoc; @@ -712,7 +908,7 @@ public: return SourceRange(getSigilLoc(), getSigilLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setSigilLoc(Loc); } @@ -812,6 +1008,7 @@ public: struct FunctionLocInfo { SourceLocation LParenLoc, RParenLoc; + bool TrailingReturn; }; /// \brief Wrapper for source info for functions. @@ -819,11 +1016,6 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, FunctionTypeLoc, FunctionType, FunctionLocInfo> { - // ParmVarDecls* are stored after Info, one for each argument. - ParmVarDecl **getParmArray() const { - return (ParmVarDecl**) getExtraLocalData(); - } - public: SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; @@ -839,6 +1031,18 @@ public: getLocalData()->RParenLoc = Loc; } + bool getTrailingReturn() const { + return getLocalData()->TrailingReturn; + } + void setTrailingReturn(bool Trailing) { + getLocalData()->TrailingReturn = Trailing; + } + + // ParmVarDecls* are stored after Info, one for each argument. + ParmVarDecl **getParmArray() const { + return (ParmVarDecl**) getExtraLocalData(); + } + unsigned getNumArgs() const { if (isa<FunctionNoProtoType>(getTypePtr())) return 0; @@ -855,9 +1059,10 @@ public: return SourceRange(getLParenLoc(), getRParenLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLParenLoc(Loc); setRParenLoc(Loc); + setTrailingReturn(false); for (unsigned i = 0, e = getNumArgs(); i != e; ++i) setArg(i, NULL); } @@ -928,7 +1133,7 @@ public: return SourceRange(getLBracketLoc(), getRBracketLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLBracketLoc(Loc); setRBracketLoc(Loc); setSizeExpr(NULL); @@ -997,9 +1202,6 @@ public: return getTypePtr()->getNumArgs(); } void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { -#ifndef NDEBUG - AI.validateForArgument(getTypePtr()->getArg(i)); -#endif getArgInfos()[i] = AI; } TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { @@ -1033,47 +1235,18 @@ public: return SourceRange(getTemplateNameLoc(), getRAngleLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLAngleLoc(Loc); setRAngleLoc(Loc); setTemplateNameLoc(Loc); - initializeArgLocs(getNumArgs(), getTypePtr()->getArgs(), + initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); } - static void initializeArgLocs(unsigned NumArgs, + static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, const TemplateArgument *Args, TemplateArgumentLocInfo *ArgInfos, - SourceLocation Loc) { - for (unsigned i = 0, e = NumArgs; i != e; ++i) { - TemplateArgumentLocInfo Info; -#ifndef NDEBUG - // If asserts are enabled, be sure to initialize the argument - // loc with the right kind of pointer. - switch (Args[i].getKind()) { - case TemplateArgument::Expression: - case TemplateArgument::Declaration: - Info = TemplateArgumentLocInfo((Expr*) 0); - break; - - case TemplateArgument::Type: - Info = TemplateArgumentLocInfo((TypeSourceInfo*) 0); - break; - - case TemplateArgument::Template: - Info = TemplateArgumentLocInfo(SourceRange(Loc), Loc); - break; - - case TemplateArgument::Integral: - case TemplateArgument::Pack: - case TemplateArgument::Null: - // K_None is fine. - break; - } -#endif - ArgInfos[i] = Info; - } - } + SourceLocation Loc); unsigned getExtraLocalDataSize() const { return getNumArgs() * sizeof(TemplateArgumentLocInfo); @@ -1168,7 +1341,7 @@ public: return SourceRange(getTypeofLoc(), getRParenLoc()); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setTypeofLoc(Loc); setLParenLoc(Loc); setRParenLoc(Loc); @@ -1208,6 +1381,11 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DecltypeType> { }; +class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + AutoTypeLoc, + AutoType> { +}; + struct ElaboratedLocInfo { SourceLocation KeywordLoc; SourceRange QualifierRange; @@ -1242,7 +1420,7 @@ public: return getQualifierRange(); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); } @@ -1307,7 +1485,7 @@ public: memcpy(Data, Loc.Data, size); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); setNameLoc(Loc); @@ -1368,9 +1546,6 @@ public: } void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { -#ifndef NDEBUG - AI.validateForArgument(getTypePtr()->getArg(i)); -#endif getArgInfos()[i] = AI; } TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { @@ -1394,13 +1569,13 @@ public: memcpy(Data, Loc.Data, size); } - void initializeLocal(SourceLocation Loc) { + void initializeLocal(ASTContext &Context, SourceLocation Loc) { setKeywordLoc(Loc); setQualifierRange(SourceRange(Loc)); setNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(getNumArgs(), + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); } @@ -1415,6 +1590,40 @@ private: } }; + +struct PackExpansionTypeLocInfo { + SourceLocation EllipsisLoc; +}; + +class PackExpansionTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc, + PackExpansionType, PackExpansionTypeLocInfo> { +public: + SourceLocation getEllipsisLoc() const { + return this->getLocalData()->EllipsisLoc; + } + + void setEllipsisLoc(SourceLocation Loc) { + this->getLocalData()->EllipsisLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getEllipsisLoc(), getEllipsisLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setEllipsisLoc(Loc); + } + + TypeLoc getPatternLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPattern(); + } +}; + } #endif diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h deleted file mode 100644 index 880af267f324..000000000000 --- a/include/clang/AST/TypeLocBuilder.h +++ /dev/null @@ -1,155 +0,0 @@ -//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This files defines TypeLocBuilder, a class for building TypeLocs -// bottom-up. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_TYPELOCBUILDER_H -#define LLVM_CLANG_AST_TYPELOCBUILDER_H - -#include "clang/AST/TypeLoc.h" -#include "llvm/ADT/SmallVector.h" -#include "clang/AST/ASTContext.h" - -namespace clang { - -class TypeLocBuilder { - enum { InlineCapacity = 8 * sizeof(SourceLocation) }; - - /// The underlying location-data buffer. Data grows from the end - /// of the buffer backwards. - char *Buffer; - - /// The capacity of the current buffer. - size_t Capacity; - - /// The index of the first occupied byte in the buffer. - size_t Index; - -#ifndef NDEBUG - /// The last type pushed on this builder. - QualType LastTy; -#endif - - /// The inline buffer. - char InlineBuffer[InlineCapacity]; - - public: - TypeLocBuilder() - : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) - {} - - ~TypeLocBuilder() { - if (Buffer != InlineBuffer) - delete[] Buffer; - } - - /// Ensures that this buffer has at least as much capacity as described. - void reserve(size_t Requested) { - if (Requested > Capacity) - // For now, match the request exactly. - grow(Requested); - } - - /// Pushes a copy of the given TypeLoc onto this builder. The builder - /// must be empty for this to work. - void pushFullCopy(TypeLoc L) { -#ifndef NDEBUG - assert(LastTy.isNull() && "pushing copy on non-empty TypeLocBuilder"); - LastTy = L.getNextTypeLoc().getType(); -#endif - assert(Index == Capacity && "pushing copy on non-empty TypeLocBuilder"); - - unsigned Size = L.getFullDataSize(); - TypeLoc Copy = pushImpl(L.getType(), Size); - memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size); - } - - /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs - /// previously retrieved from this builder. - TypeSpecTypeLoc pushTypeSpec(QualType T) { - size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; - return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize)); - } - - /// Resets this builder to the newly-initialized state. - void clear() { -#ifndef NDEBUG - LastTy = QualType(); -#endif - Index = Capacity; - } - - /// Pushes space for a new TypeLoc of the given type. Invalidates - /// any TypeLocs previously retrieved from this builder. - template <class TyLocType> TyLocType push(QualType T) { - size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize(); - return cast<TyLocType>(pushImpl(T, LocalSize)); - } - - /// Creates a TypeSourceInfo for the given type. - TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { -#ifndef NDEBUG - assert(T == LastTy && "type doesn't match last type pushed!"); -#endif - - size_t FullDataSize = Capacity - Index; - TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); - memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); - return DI; - } - -private: - TypeLoc pushImpl(QualType T, size_t LocalSize) { -#ifndef NDEBUG - QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); - assert(TLast == LastTy && - "mismatch between last type and new type's inner type"); - LastTy = T; -#endif - - // If we need to grow, grow by a factor of 2. - if (LocalSize > Index) { - size_t RequiredCapacity = Capacity + (LocalSize - Index); - size_t NewCapacity = Capacity * 2; - while (RequiredCapacity > NewCapacity) - NewCapacity *= 2; - grow(NewCapacity); - } - - Index -= LocalSize; - - return TypeLoc(T, &Buffer[Index]); - } - - /// Grow to the given capacity. - void grow(size_t NewCapacity) { - assert(NewCapacity > Capacity); - - // Allocate the new buffer and copy the old data into it. - char *NewBuffer = new char[NewCapacity]; - unsigned NewIndex = Index + NewCapacity - Capacity; - memcpy(&NewBuffer[NewIndex], - &Buffer[Index], - Capacity - Index); - - if (Buffer != InlineBuffer) - delete[] Buffer; - - Buffer = NewBuffer; - Capacity = NewCapacity; - Index = NewIndex; - } -}; - -} - -#endif diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 9cb56861a9ef..b2591cc0fbac 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -79,6 +79,7 @@ ABSTRACT_TYPE(Function, Type) TYPE(FunctionProto, FunctionType) TYPE(FunctionNoProto, FunctionType) DEPENDENT_TYPE(UnresolvedUsing, Type) +NON_CANONICAL_TYPE(Paren, Type) NON_CANONICAL_TYPE(Typedef, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type) @@ -87,12 +88,16 @@ ABSTRACT_TYPE(Tag, Type) TYPE(Record, TagType) TYPE(Enum, TagType) NON_CANONICAL_TYPE(Elaborated, Type) +NON_CANONICAL_TYPE(Attributed, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) +DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Auto, Type) DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) DEPENDENT_TYPE(DependentTemplateSpecialization, Type) +DEPENDENT_TYPE(PackExpansion, Type) TYPE(ObjCObject, Type) TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h index 5c9c5285a248..c52926b1fc31 100644 --- a/include/clang/AST/TypeVisitor.h +++ b/include/clang/AST/TypeVisitor.h @@ -19,12 +19,13 @@ namespace clang { #define DISPATCH(CLASS) \ - return static_cast<ImplClass*>(this)->Visit ## CLASS(static_cast<CLASS*>(T)) + return static_cast<ImplClass*>(this)-> \ + Visit##CLASS(static_cast<const CLASS*>(T)) template<typename ImplClass, typename RetTy=void> class TypeVisitor { public: - RetTy Visit(Type *T) { + RetTy Visit(const Type *T) { // Top switch stmt: dispatch to VisitFooType for each FooType. switch (T->getTypeClass()) { default: assert(0 && "Unknown type class!"); @@ -36,13 +37,13 @@ public: // 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) { \ +#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(const CLASS##Type *T) { \ DISPATCH(PARENT); \ } #include "clang/AST/TypeNodes.def" // Base case, ignore it. :) - RetTy VisitType(Type*) { return RetTy(); } + RetTy VisitType(const Type*) { return RetTy(); } }; #undef DISPATCH diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 280b1260ac26..7cc76a8d471b 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -379,6 +379,7 @@ using analyze_format_string::OptionalAmount; using analyze_format_string::OptionalFlag; class PrintfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag HasThousandsGrouping; // ''', POSIX extension. OptionalFlag IsLeftJustified; // '-' OptionalFlag HasPlusPrefix; // '+' OptionalFlag HasSpacePrefix; // ' ' @@ -388,8 +389,8 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier { public: PrintfSpecifier() : FormatSpecifier(/* isPrintf = */ true), - IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), - HasAlternativeForm("#"), HasLeadingZeroes("0") {} + HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), + HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {} static PrintfSpecifier Parse(const char *beg, const char *end); @@ -397,6 +398,10 @@ public: void setConversionSpecifier(const PrintfConversionSpecifier &cs) { CS = cs; } + void setHasThousandsGrouping(const char *position) { + HasThousandsGrouping = true; + HasThousandsGrouping.setPosition(position); + } void setIsLeftJustified(const char *position) { IsLeftJustified = true; IsLeftJustified.setPosition(position); @@ -445,6 +450,9 @@ public: /// more than one type. ArgTypeResult getArgType(ASTContext &Ctx) const; + const OptionalFlag &hasThousandsGrouping() const { + return HasThousandsGrouping; + } const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } @@ -465,6 +473,7 @@ public: bool hasValidLeadingZeros() const; bool hasValidSpacePrefix() const; bool hasValidLeftJustified() const; + bool hasValidThousandsGroupingPrefix() const; bool hasValidPrecision() const; bool hasValidFieldWidth() const; diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 237fe14aed4f..fbbd2613e7c2 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -55,7 +55,8 @@ struct LiveVariables_ValueTypes { /// 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 CFGBlock *currentBlock, + const AnalysisDataTy& AD, const ValTy& V) {} virtual void ObserverKill(DeclRefExpr* DR) {} diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h new file mode 100644 index 000000000000..c1fe040793e1 --- /dev/null +++ b/include/clang/Analysis/Analyses/UninitializedValuesV2.h @@ -0,0 +1,40 @@ +//= UninitializedValuesV2.h - Finding uses of uninitialized values --*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs for invoking and reported uninitialized values +// warnings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_UNINIT_VALS_H +#define LLVM_CLANG_UNINIT_VALS_H + +namespace clang { + +class AnalysisContext; +class CFG; +class DeclContext; +class Expr; +class VarDecl; + +class UninitVariablesHandler { +public: + UninitVariablesHandler() {} + virtual ~UninitVariablesHandler(); + + virtual void handleUseOfUninitVariable(const Expr *ex, + const VarDecl *vd) {} +}; + +void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, + UninitVariablesHandler &handler); + +} +#endif diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 7d4d25f8b0d8..2ecbfdc6bf02 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" @@ -56,15 +57,20 @@ class AnalysisContext { llvm::BumpPtrAllocator A; bool UseUnoptimizedCFG; bool AddEHEdges; + bool AddImplicitDtors; + bool AddInitializers; public: AnalysisContext(const Decl *d, idx::TranslationUnit *tu, bool useUnoptimizedCFG = false, - bool addehedges = false) + bool addehedges = false, + bool addImplicitDtors = false, + bool addInitializers = false) : D(d), TU(tu), cfg(0), completeCFG(0), builtCFG(false), builtCompleteCFG(false), liveness(0), relaxedLiveness(0), PM(0), PCA(0), ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG), - AddEHEdges(addehedges) {} + AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors), + AddInitializers(addInitializers) {} ~AnalysisContext(); @@ -80,13 +86,17 @@ public: bool getAddEHEdges() const { return AddEHEdges; } bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; } + bool getAddImplicitDtors() const { return AddImplicitDtors; } + bool getAddInitializers() const { return AddInitializers; } Stmt *getBody(); CFG *getCFG(); - + /// Return a version of the CFG without any edges pruned. CFG *getUnoptimizedCFG(); + void dumpCFG(); + ParentMap &getParentMap(); PseudoConstantAnalysis *getPseudoConstantAnalysis(); LiveVariables *getLiveVariables(); @@ -106,15 +116,21 @@ class AnalysisContextManager { typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; ContextMap Contexts; bool UseUnoptimizedCFG; + bool AddImplicitDtors; + bool AddInitializers; public: - AnalysisContextManager(bool useUnoptimizedCFG = false) - : UseUnoptimizedCFG(useUnoptimizedCFG) {} + AnalysisContextManager(bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, bool addInitializers = false) + : UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors), + AddInitializers(addInitializers) {} ~AnalysisContextManager(); AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; } + bool getAddImplicitDtors() const { return AddImplicitDtors; } + bool getAddInitializers() const { return AddInitializers; } // Discard all previously created AnalysisContexts. void clear(); @@ -196,9 +212,10 @@ class StackFrameContext : public LocationContext { friend class LocationContextManager; StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, unsigned idx) - : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk), - Index(idx) {} + const Stmt *s, const CFGBlock *blk, + unsigned idx) + : LocationContext(StackFrame, ctx, parent), CallSite(s), + Block(blk), Index(idx) {} public: ~StackFrameContext() {} @@ -282,8 +299,8 @@ public: const StackFrameContext *getStackFrame(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, - unsigned idx); + const Stmt *s, + const CFGBlock *blk, unsigned idx); const ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index e98a3df472a8..295d0a2133d3 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define ANALYSISSTART #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index b7a8e1159693..b337d74495c9 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -22,14 +22,21 @@ #include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/SourceLocation.h" #include <cassert> +#include <iterator> namespace llvm { class raw_ostream; } + namespace clang { class Decl; class Stmt; class Expr; + class FieldDecl; + class VarDecl; + class CXXCtorInitializer; + class CXXBaseSpecifier; + class CXXBindTemporaryExpr; class CFG; class PrinterHelper; class LangOptions; @@ -37,19 +44,203 @@ namespace clang { /// CFGElement - Represents a top-level expression in a basic block. class CFGElement { - llvm::PointerIntPair<Stmt *, 2> Data; public: - enum Type { StartScope, EndScope }; - explicit CFGElement() {} - CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {} - CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {} - Stmt *getStmt() const { return Data.getPointer(); } - bool asLValue() const { return Data.getInt() == 1; } - bool asStartScope() const { return Data.getInt() == 2; } - bool asEndScope() const { return Data.getInt() == 3; } - bool asDtor() const { return Data.getInt() == 4; } + enum Kind { + // main kind + Statement, + Initializer, + ImplicitDtor, + // dtor kind + AutomaticObjectDtor, + BaseDtor, + MemberDtor, + TemporaryDtor, + DTOR_BEGIN = AutomaticObjectDtor + }; + +protected: + // The int bits are used to mark the main kind. + llvm::PointerIntPair<void *, 2> Data1; + // The int bits are used to mark the dtor kind. + llvm::PointerIntPair<void *, 2> Data2; + + CFGElement(void *Ptr, unsigned Int) : Data1(Ptr, Int) {} + CFGElement(void *Ptr1, unsigned Int1, void *Ptr2, unsigned Int2) + : Data1(Ptr1, Int1), Data2(Ptr2, Int2) {} + +public: + CFGElement() {} + + Kind getKind() const { return static_cast<Kind>(Data1.getInt()); } + + Kind getDtorKind() const { + assert(getKind() == ImplicitDtor); + return static_cast<Kind>(Data2.getInt() + DTOR_BEGIN); + } + + bool isValid() const { return Data1.getPointer(); } + + operator bool() const { return isValid(); } + + template<class ElemTy> ElemTy getAs() const { + if (llvm::isa<ElemTy>(this)) + return *static_cast<const ElemTy*>(this); + return ElemTy(); + } + + static bool classof(const CFGElement *E) { return true; } +}; + +class CFGStmt : public CFGElement { +public: + CFGStmt() {} + CFGStmt(Stmt *S) : CFGElement(S, 0) {} + + Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); } + operator Stmt*() const { return getStmt(); } - operator bool() const { return getStmt() != 0; } + + static bool classof(const CFGElement *E) { + return E->getKind() == Statement; + } +}; + +/// CFGInitializer - Represents C++ base or member initializer from +/// constructor's initialization list. +class CFGInitializer : public CFGElement { +public: + CFGInitializer() {} + CFGInitializer(CXXCtorInitializer* I) + : CFGElement(I, Initializer) {} + + CXXCtorInitializer* getInitializer() const { + return static_cast<CXXCtorInitializer*>(Data1.getPointer()); + } + operator CXXCtorInitializer*() const { return getInitializer(); } + + static bool classof(const CFGElement *E) { + return E->getKind() == Initializer; + } +}; + +/// CFGImplicitDtor - Represents C++ object destructor implicitly generated +/// by compiler on various occasions. +class CFGImplicitDtor : public CFGElement { +protected: + CFGImplicitDtor(unsigned K, void* P, void* S) + : CFGElement(P, ImplicitDtor, S, K - DTOR_BEGIN) {} + +public: + CFGImplicitDtor() {} + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor; + } +}; + +/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated +/// for automatic object or temporary bound to const reference at the point +/// of leaving its local scope. +class CFGAutomaticObjDtor: public CFGImplicitDtor { +public: + CFGAutomaticObjDtor() {} + CFGAutomaticObjDtor(VarDecl* VD, Stmt* S) + : CFGImplicitDtor(AutomaticObjectDtor, VD, S) {} + + VarDecl* getVarDecl() const { + return static_cast<VarDecl*>(Data1.getPointer()); + } + + // Get statement end of which triggered the destructor call. + Stmt* getTriggerStmt() const { + return static_cast<Stmt*>(Data2.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && + E->getDtorKind() == AutomaticObjectDtor; + } +}; + +/// CFGBaseDtor - Represents C++ object destructor implicitly generated for +/// base object in destructor. +class CFGBaseDtor : public CFGImplicitDtor { +public: + CFGBaseDtor() {} + CFGBaseDtor(const CXXBaseSpecifier *BS) + : CFGImplicitDtor(BaseDtor, const_cast<CXXBaseSpecifier*>(BS), NULL) {} + + const CXXBaseSpecifier *getBaseSpecifier() const { + return static_cast<const CXXBaseSpecifier*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == BaseDtor; + } +}; + +/// CFGMemberDtor - Represents C++ object destructor implicitly generated for +/// member object in destructor. +class CFGMemberDtor : public CFGImplicitDtor { +public: + CFGMemberDtor() {} + CFGMemberDtor(FieldDecl *FD) + : CFGImplicitDtor(MemberDtor, FD, NULL) {} + + FieldDecl *getFieldDecl() const { + return static_cast<FieldDecl*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == MemberDtor; + } +}; + +/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated +/// at the end of full expression for temporary object. +class CFGTemporaryDtor : public CFGImplicitDtor { +public: + CFGTemporaryDtor() {} + CFGTemporaryDtor(CXXBindTemporaryExpr *E) + : CFGImplicitDtor(TemporaryDtor, E, NULL) {} + + CXXBindTemporaryExpr *getBindTemporaryExpr() const { + return static_cast<CXXBindTemporaryExpr *>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == TemporaryDtor; + } +}; + +/// CFGTerminator - Represents CFGBlock terminator statement. +/// +/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch +/// in control flow of destructors of temporaries. In this case terminator +/// statement is the same statement that branches control flow in evaluation +/// of matching full expression. +class CFGTerminator { + llvm::PointerIntPair<Stmt *, 1> Data; +public: + CFGTerminator() {} + CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false) + : Data(S, TemporaryDtorsBranch) {} + + Stmt *getStmt() { return Data.getPointer(); } + const Stmt *getStmt() const { return Data.getPointer(); } + + bool isTemporaryDtorsBranch() const { return Data.getInt(); } + + operator Stmt *() { return getStmt(); } + operator const Stmt *() const { return getStmt(); } + + Stmt *operator->() { return getStmt(); } + const Stmt *operator->() const { return getStmt(); } + + Stmt &operator*() { return *getStmt(); } + const Stmt &operator*() const { return *getStmt(); } + + operator bool() const { return getStmt(); } }; /// CFGBlock - Represents a single basic block in a source-level CFG. @@ -77,11 +268,11 @@ public: /// &&, || expression that uses result of && or ||, RHS /// class CFGBlock { - class StatementList { + class ElementList { typedef BumpVector<CFGElement> ImplTy; ImplTy Impl; public: - StatementList(BumpVectorContext &C) : Impl(C, 4) {} + ElementList(BumpVectorContext &C) : Impl(C, 4) {} typedef std::reverse_iterator<ImplTy::iterator> iterator; typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; @@ -89,6 +280,11 @@ class CFGBlock { typedef ImplTy::const_iterator const_reverse_iterator; void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } + reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, + BumpVectorContext& C) { + return Impl.insert(I, Cnt, E, C); + } + CFGElement front() const { return Impl.back(); } CFGElement back() const { return Impl.front(); } @@ -111,7 +307,7 @@ class CFGBlock { }; /// Stmts - The set of statements in the basic block. - StatementList Stmts; + ElementList Elements; /// Label - An (optional) label that prefixes the executable /// statements in the block. When this variable is non-NULL, it is @@ -121,7 +317,7 @@ class CFGBlock { /// Terminator - The terminator for a basic block that /// indicates the type of control-flow that occurs between a block /// and its successors. - Stmt *Terminator; + CFGTerminator Terminator; /// LoopTarget - Some blocks are used to represent the "loop edge" to /// the start of a loop from within the loop body. This Stmt* will be @@ -140,33 +336,33 @@ class CFGBlock { public: explicit CFGBlock(unsigned blockid, BumpVectorContext &C) - : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + : Elements(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; + typedef ElementList::iterator iterator; + typedef ElementList::const_iterator const_iterator; + typedef ElementList::reverse_iterator reverse_iterator; + typedef ElementList::const_reverse_iterator const_reverse_iterator; - CFGElement front() const { return Stmts.front(); } - CFGElement back() const { return Stmts.back(); } + CFGElement front() const { return Elements.front(); } + CFGElement back() const { return Elements.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(); } + iterator begin() { return Elements.begin(); } + iterator end() { return Elements.end(); } + const_iterator begin() const { return Elements.begin(); } + const_iterator end() const { return Elements.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(); } + reverse_iterator rbegin() { return Elements.rbegin(); } + reverse_iterator rend() { return Elements.rend(); } + const_reverse_iterator rbegin() const { return Elements.rbegin(); } + const_reverse_iterator rend() const { return Elements.rend(); } - unsigned size() const { return Stmts.size(); } - bool empty() const { return Stmts.empty(); } + unsigned size() const { return Elements.size(); } + bool empty() const { return Elements.empty(); } - CFGElement operator[](size_t i) const { return Stmts[i]; } + CFGElement operator[](size_t i) const { return Elements[i]; } // CFG iterators typedef AdjacentBlocks::iterator pred_iterator; @@ -205,14 +401,67 @@ public: unsigned pred_size() const { return Preds.size(); } bool pred_empty() const { return Preds.empty(); } + + class FilterOptions { + public: + FilterOptions() { + IgnoreDefaultsWithCoveredEnums = 0; + } + + unsigned IgnoreDefaultsWithCoveredEnums : 1; + }; + + static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, + const CFGBlock *Dst); + + template <typename IMPL, bool IsPred> + class FilteredCFGBlockIterator { + private: + IMPL I, E; + const FilterOptions F; + const CFGBlock *From; + public: + explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e, + const CFGBlock *from, + const FilterOptions &f) + : I(i), E(e), F(f), From(from) {} + + bool hasMore() const { return I != E; } + + FilteredCFGBlockIterator &operator++() { + do { ++I; } while (hasMore() && Filter(*I)); + return *this; + } + + const CFGBlock *operator*() const { return *I; } + private: + bool Filter(const CFGBlock *To) { + return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To); + } + }; + + typedef FilteredCFGBlockIterator<const_pred_iterator, true> + filtered_pred_iterator; + + typedef FilteredCFGBlockIterator<const_succ_iterator, false> + filtered_succ_iterator; + + filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const { + return filtered_pred_iterator(pred_begin(), pred_end(), this, f); + } + + filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const { + return filtered_succ_iterator(succ_begin(), succ_end(), this, f); + } + // 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; } + CFGTerminator getTerminator() { return Terminator; } + const CFGTerminator getTerminator() const { return Terminator; } Stmt* getTerminatorCondition(); @@ -239,17 +488,39 @@ public: Succs.push_back(Block, C); } - void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) { - Stmts.push_back(CFGElement(Statement, asLValue), C); - } - void StartScope(Stmt* S, BumpVectorContext &C) { - Stmts.push_back(CFGElement(S, CFGElement::StartScope), C); + void appendStmt(Stmt* statement, BumpVectorContext &C) { + Elements.push_back(CFGStmt(statement), C); + } + + void appendInitializer(CXXCtorInitializer *initializer, + BumpVectorContext& C) { + Elements.push_back(CFGInitializer(initializer), C); } - void EndScope(Stmt* S, BumpVectorContext &C) { - Stmts.push_back(CFGElement(S, CFGElement::EndScope), C); + + void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { + Elements.push_back(CFGBaseDtor(BS), C); } -}; + void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { + Elements.push_back(CFGMemberDtor(FD), C); + } + + void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { + Elements.push_back(CFGTemporaryDtor(E), C); + } + + // Destructors must be inserted in reversed order. So insertion is in two + // steps. First we prepare space for some number of elements, then we insert + // the elements beginning at the last position in prepared space. + iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, + BumpVectorContext& C) { + return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C)); + } + iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) { + *I = CFGAutomaticObjDtor(VD, S); + return ++I; + } +}; /// CFG - Represents a source-level, intra-procedural CFG that represents the /// control-flow of a Stmt. The Stmt can represent an entire function body, @@ -264,13 +535,24 @@ public: // CFG Construction & Manipulation. //===--------------------------------------------------------------------===// + class BuildOptions { + public: + bool PruneTriviallyFalseEdges:1; + bool AddEHEdges:1; + bool AddInitializers:1; + bool AddImplicitDtors:1; + + BuildOptions() + : PruneTriviallyFalseEdges(true) + , AddEHEdges(false) + , AddInitializers(false) + , AddImplicitDtors(false) {} + }; + /// buildCFG - Builds a CFG from an AST. The responsibility to free the /// constructed CFG belongs to the caller. static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C, - bool pruneTriviallyFalseEdges = true, - bool AddEHEdges = false, - bool AddScopes = false /* NOT FULLY IMPLEMENTED. - NOT READY FOR GENERAL USE. */); + BuildOptions BO = BuildOptions()); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. @@ -324,8 +606,10 @@ public: 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); + BI != BE; ++BI) { + if (CFGStmt S = BI->getAs<CFGStmt>()) + O(S); + } } //===--------------------------------------------------------------------===// @@ -340,7 +624,10 @@ public: operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } }; - bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + bool isBlkExpr(const Stmt *S) const { + return const_cast<CFG*>(this)->isBlkExpr(S); + } BlkExprNumTy getBlkExprNum(const Stmt* S); unsigned getNumBlkExprs(); @@ -398,18 +685,22 @@ private: namespace llvm { -/// Implement simplify_type for CFGElement, so that we can dyn_cast from -/// CFGElement to a specific Stmt class. -template <> struct simplify_type<const ::clang::CFGElement> { - typedef ::clang::Stmt* SimpleType; - static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) { +/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from +/// CFGTerminator to a specific Stmt class. +template <> struct simplify_type<const ::clang::CFGTerminator> { + typedef const ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { return Val.getStmt(); } }; - -template <> struct simplify_type< ::clang::CFGElement> - : public simplify_type<const ::clang::CFGElement> {}; - + +template <> struct simplify_type< ::clang::CFGTerminator> { + typedef ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { + return const_cast<SimpleType>(Val.getStmt()); + } +}; + // Traits for: CFGBlock template <> struct GraphTraits< ::clang::CFGBlock* > { diff --git a/include/clang/Checker/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index 4bbdab0e7fe1..7e6e3815400c 100644 --- a/include/clang/Checker/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -11,17 +11,18 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CHECKER_DS_COCOA -#define LLVM_CLANG_CHECKER_DS_COCOA +#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA +#define LLVM_CLANG_ANALYSIS_DS_COCOA #include "clang/AST/Type.h" namespace clang { +namespace ento { namespace cocoa { enum NamingConvention { NoConvention, CreateRule, InitRule }; - NamingConvention deriveNamingConvention(Selector S); + NamingConvention deriveNamingConvention(Selector S, bool ignorePrefix = true); static inline bool followsFundamentalRule(Selector S) { return deriveNamingConvention(S) == CreateRule; @@ -34,6 +35,6 @@ namespace cocoa { bool isCocoaObjectRef(QualType T); -}} +}}} #endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 9375db06be72..d75d333db6b6 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -273,8 +273,13 @@ private: 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.setCurrentBlock(B); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (CFGStmt S = El.getAs<CFGStmt>()) + ProcessStmt(S, recordStmtValues, AnalysisDirTag()); + } TF.VisitTerminator(const_cast<CFGBlock*>(B)); } @@ -282,10 +287,15 @@ private: void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::backward_analysis_tag) { + TF.setCurrentBlock(B); + TF.VisitTerminator(const_cast<CFGBlock*>(B)); - for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) - ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (CFGStmt S = El.getAs<CFGStmt>()) + ProcessStmt(S, recordStmtValues, AnalysisDirTag()); + } } void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index ba303de7a8da..54cfc3dc0db6 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -17,7 +17,7 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" @@ -44,6 +44,7 @@ public: PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, + PostInitializerKind, CallEnterKind, CallExitKind, MinPostStmtKind = PostStmtKind, @@ -70,11 +71,12 @@ protected: 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 { return K; } + const void *getTag() const { return Tag; } + const LocationContext *getLocationContext() const { return L; } // For use with DenseMap. This hash is probably slow. @@ -118,10 +120,12 @@ public: return B->empty() ? CFGElement() : B->front(); } - const Stmt *getFirstStmt() const { - return getFirstElement().getStmt(); + /// Create a new BlockEntrance object that is the same as the original + /// except for using the specified tag value. + BlockEntrance withTag(const void *tag) { + return BlockEntrance(getBlock(), getLocationContext(), tag); } - + static bool classof(const ProgramPoint* Location) { return Location->getKind() == BlockEntranceKind; } @@ -136,11 +140,6 @@ public: return reinterpret_cast<const CFGBlock*>(getData1()); } - const Stmt* getLastStmt() const { - const CFGBlock* B = getBlock(); - return B->empty() ? CFGElement() : B->back(); - } - const Stmt* getTerminator() const { return getBlock()->getTerminator(); } @@ -183,14 +182,15 @@ public: 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, Kind k, + const LocationContext *L, const void *tag = 0) + : StmtPoint(S, NULL, k, L, tag) {} + explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) : StmtPoint(S, NULL, PostStmtKind, L, tag) {} @@ -313,19 +313,29 @@ public: } }; +class PostInitializer : public ProgramPoint { +public: + PostInitializer(const CXXCtorInitializer *I, + const LocationContext *L) + : ProgramPoint(I, PostInitializerKind, L) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PostInitializerKind; + } +}; + class CallEnter : public StmtPoint { public: - // L is caller's location context. AC is callee's AnalysisContext. - CallEnter(const Stmt *S, const AnalysisContext *AC, const LocationContext *L) - : StmtPoint(S, AC, CallEnterKind, L, 0) {} + CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, + const LocationContext *callerCtx) + : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} const Stmt *getCallExpr() const { return static_cast<const Stmt *>(getData1()); } - AnalysisContext *getCalleeContext() const { - return const_cast<AnalysisContext *>( - static_cast<const AnalysisContext *>(getData2())); + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData2()); } static bool classof(const ProgramPoint *Location) { diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index 7cd481238f81..83532e62babe 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -24,6 +24,7 @@ #include "llvm/ADT/PointerIntPair.h" #include <algorithm> #include <cstring> +#include <iterator> #include <memory> namespace clang { @@ -155,7 +156,25 @@ public: grow(C); goto Retry; } - + + /// insert - Insert some number of copies of element into a position. Return + /// iterator to position after last inserted copy. + iterator insert(iterator I, size_t Cnt, const_reference E, + BumpVectorContext &C) { + assert (I >= Begin && I <= End && "Iterator out of bounds."); + if (End + Cnt <= Capacity) { + Retry: + move_range_right(I, End, Cnt); + construct_range(I, I + Cnt, E); + End += Cnt; + return I + Cnt; + } + ptrdiff_t D = I - Begin; + grow(C, size() + Cnt); + I = Begin + D; + goto Retry; + } + void reserve(BumpVectorContext &C, unsigned N) { if (unsigned(Capacity-Begin) < N) grow(C, N); @@ -181,6 +200,14 @@ private: E->~T(); } } + + void move_range_right(T *S, T *E, size_t D) { + for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) { + --E; + new (I) T(*E); + E->~T(); + } + } }; // Define this out-of-line to dissuade the C++ compiler from inlining it. diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index f20a49a6fcd8..95f4ace76e8c 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -66,6 +66,8 @@ public: DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? DISPATCH_CASE(CXXRecord) DISPATCH_CASE(Enum) + DISPATCH_CASE(UsingDirective) + DISPATCH_CASE(Using) default: assert(false && "Subtype of ScopedDecl not handled."); } @@ -85,6 +87,8 @@ public: DEFAULT_DISPATCH(ObjCMethod) DEFAULT_DISPATCH(ObjCProtocol) DEFAULT_DISPATCH(ObjCCategory) + DEFAULT_DISPATCH(UsingDirective) + DEFAULT_DISPATCH(Using) void VisitCXXRecordDecl(CXXRecordDecl *D) { static_cast<ImplClass*>(this)->VisitRecordDecl(D); diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index 75a4ac66012e..bb7cf0b97e53 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -26,6 +26,11 @@ public: static_cast< ImplClass* >(this)->VisitChildren(S); } + void VisitCompoundStmt(CompoundStmt *S) { + // Do nothing. Everything in a CompoundStmt is inlined + // into the CFG. + } + void VisitConditionVariableInit(Stmt *S) { assert(S == this->getCurrentBlkStmt()); VarDecl *CondVar = 0; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index 6421f185ff7f..d197e69babde 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -80,6 +80,7 @@ public: DISPATCH_CASE(StmtExpr) DISPATCH_CASE(ConditionalOperator) + DISPATCH_CASE(BinaryConditionalOperator) DISPATCH_CASE(ObjCForCollectionStmt) case Stmt::BinaryOperatorClass: { @@ -102,6 +103,7 @@ public: DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) + DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator) RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); @@ -155,7 +157,7 @@ public: } } - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + for (Stmt::child_range I = S->children(); I; ++I) if (*I) static_cast<ImplClass*>(this)->Visit(*I); } }; diff --git a/include/clang/Basic/ABI.h b/include/clang/Basic/ABI.h new file mode 100644 index 000000000000..018f50026541 --- /dev/null +++ b/include/clang/Basic/ABI.h @@ -0,0 +1,126 @@ +//===----- ABI.h - ABI related declarations ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These enums/classes describe ABI related information about constructors, +// destructors and thunks. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_ABI_H +#define CLANG_BASIC_ABI_H + +#include "llvm/Support/DataTypes.h" + +namespace clang { + +/// CXXCtorType - C++ constructor types +enum CXXCtorType { + Ctor_Complete, // Complete object ctor + Ctor_Base, // Base object ctor + Ctor_CompleteAllocating // Complete object allocating ctor +}; + +/// CXXDtorType - C++ destructor types +enum CXXDtorType { + Dtor_Deleting, // Deleting dtor + Dtor_Complete, // Complete object dtor + Dtor_Base // Base object dtor +}; + +/// ReturnAdjustment - A return adjustment. +struct ReturnAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VBaseOffsetOffset - The offset (in bytes), relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; + + ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; + } + + friend bool operator<(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset; + } +}; + +/// ThisAdjustment - A 'this' pointer adjustment. +struct ThisAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; + + ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; + } + + friend bool operator<(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset < RHS.VCallOffsetOffset; + } +}; + +/// ThunkInfo - The 'this' pointer adjustment as well as an optional return +/// adjustment for a thunk. +struct ThunkInfo { + /// This - The 'this' pointer adjustment. + ThisAdjustment This; + + /// Return - The return adjustment. + ReturnAdjustment Return; + + ThunkInfo() { } + + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) + : This(This), Return(Return) { } + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return; + } + + friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This < RHS.This) + return true; + + return LHS.This == RHS.This && LHS.Return < RHS.Return; + } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } +}; + +} // end namespace clang + +#endif // CLANG_BASIC_ABI_H diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 2f2267f7f79f..3e62d411d51a 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -89,171 +89,224 @@ class Attr { code AdditionalMembers = [{}]; } +class InheritableAttr : Attr; + // // Attributes begin here // -def Alias : Attr { +def Alias : InheritableAttr { let Spellings = ["alias"]; let Args = [StringArgument<"Aliasee">]; } -def Aligned : Attr { +def Aligned : InheritableAttr { let Spellings = ["align", "aligned"]; let Subjects = [NonBitField, NormalVar, Tag]; let Args = [AlignedArgument<"Alignment">]; let Namespaces = ["", "std"]; } -def AlignMac68k : Attr { +def AlignMac68k : InheritableAttr { let Spellings = []; } -def AlwaysInline : Attr { +def AlwaysInline : InheritableAttr { let Spellings = ["always_inline"]; } -def AnalyzerNoReturn : Attr { +def AnalyzerNoReturn : InheritableAttr { let Spellings = ["analyzer_noreturn"]; } -def Annotate : Attr { +def Annotate : InheritableAttr { let Spellings = ["annotate"]; let Args = [StringArgument<"Annotation">]; } -def AsmLabel : Attr { +def AsmLabel : InheritableAttr { let Spellings = []; let Args = [StringArgument<"Label">]; } -def BaseCheck : Attr { - let Spellings = ["base_check"]; - let Subjects = [CXXRecord]; - let Namespaces = ["", "std"]; -} - -def Blocks : Attr { +def Blocks : InheritableAttr { let Spellings = ["blocks"]; let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; } -def CarriesDependency : Attr { +def CarriesDependency : InheritableAttr { let Spellings = ["carries_dependency"]; let Subjects = [ParmVar, Function]; let Namespaces = ["", "std"]; } -def CDecl : Attr { +def CDecl : InheritableAttr { let Spellings = ["cdecl", "__cdecl"]; } -def CFReturnsRetained : Attr { +def CFReturnsRetained : InheritableAttr { let Spellings = ["cf_returns_retained"]; + let Subjects = [ObjCMethod, Function]; } -def CFReturnsNotRetained : Attr { +def CFReturnsNotRetained : InheritableAttr { let Spellings = ["cf_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def CFConsumed : InheritableAttr { + let Spellings = ["cf_consumed"]; + let Subjects = [ParmVar]; } -def Cleanup : Attr { +def Cleanup : InheritableAttr { let Spellings = ["cleanup"]; let Args = [FunctionArgument<"FunctionDecl">]; } -def Const : Attr { +def Common : InheritableAttr { + let Spellings = ["common"]; +} + +def Const : InheritableAttr { let Spellings = ["const"]; } -def Constructor : Attr { +def Constructor : InheritableAttr { let Spellings = ["constructor"]; let Args = [IntArgument<"Priority">]; } -def Deprecated : Attr { +def CUDAConstant : InheritableAttr { + let Spellings = ["constant"]; +} + +def CUDADevice : Attr { + let Spellings = ["device"]; +} + +def CUDAGlobal : InheritableAttr { + let Spellings = ["global"]; +} + +def CUDAHost : Attr { + let Spellings = ["host"]; +} + +def CUDALaunchBounds : InheritableAttr { + let Spellings = ["launch_bounds"]; + let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>]; +} + +def CUDAShared : InheritableAttr { + let Spellings = ["shared"]; +} + +def OpenCLKernel : Attr { + let Spellings = ["opencl_kernel_function"]; +} + +def Deprecated : InheritableAttr { let Spellings = ["deprecated"]; + let Args = [StringArgument<"Message">]; } -def Destructor : Attr { +def Destructor : InheritableAttr { let Spellings = ["destructor"]; let Args = [IntArgument<"Priority">]; } -def DLLExport : Attr { +def DLLExport : InheritableAttr { let Spellings = ["dllexport"]; } -def DLLImport : Attr { +def DLLImport : InheritableAttr { let Spellings = ["dllimport"]; } -def FastCall : Attr { +def Explicit : InheritableAttr { + let Spellings = []; +} + +def FastCall : InheritableAttr { let Spellings = ["fastcall", "__fastcall"]; } -def Final : Attr { - let Spellings = ["final"]; - let Subjects = [CXXRecord, CXXVirtualMethod]; - let Namespaces = ["", "std"]; +def Final : InheritableAttr { + let Spellings = []; } -def Format : Attr { +def Format : InheritableAttr { let Spellings = ["format"]; let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">, IntArgument<"FirstArg">]; } -def FormatArg : Attr { +def FormatArg : InheritableAttr { let Spellings = ["format_arg"]; let Args = [IntArgument<"FormatIdx">]; } -def GNUInline : Attr { +def GNUInline : InheritableAttr { let Spellings = ["gnu_inline"]; } -def Hiding : Attr { - let Spellings = ["hiding"]; - let Subjects = [Field, CXXMethod]; - let Namespaces = ["", "std"]; -} - -def IBAction : Attr { +def IBAction : InheritableAttr { let Spellings = ["ibaction"]; } -def IBOutlet : Attr { +def IBOutlet : InheritableAttr { let Spellings = ["iboutlet"]; } -def IBOutletCollection : Attr { +def IBOutletCollection : InheritableAttr { let Spellings = ["iboutletcollection"]; let Args = [TypeArgument<"Interface">]; } -def Malloc : Attr { +def Malloc : InheritableAttr { let Spellings = ["malloc"]; } -def MaxFieldAlignment : Attr { +def MaxFieldAlignment : InheritableAttr { let Spellings = []; let Args = [UnsignedArgument<"Alignment">]; } -def MSP430Interrupt : Attr { +def MayAlias : InheritableAttr { + let Spellings = ["may_alias"]; +} + +def MSP430Interrupt : InheritableAttr { let Spellings = []; let Args = [UnsignedArgument<"Number">]; } -def NoDebug : Attr { +def MBlazeInterruptHandler : InheritableAttr { + let Spellings = []; +} + +def MBlazeSaveVolatiles : InheritableAttr { + let Spellings = []; +} + +def Naked : InheritableAttr { + let Spellings = ["naked"]; +} + +def NoCommon : InheritableAttr { + let Spellings = ["nocommon"]; +} + +def NoDebug : InheritableAttr { let Spellings = ["nodebug"]; } -def NoInline : Attr { +def NoInline : InheritableAttr { let Spellings = ["noinline"]; } -def NonNull : Attr { +def NonNull : InheritableAttr { let Spellings = ["nonnull"]; let Args = [VariadicUnsignedArgument<"Args">]; let AdditionalMembers = @@ -266,49 +319,64 @@ def NonNull : Attr { } }]; } -def NoReturn : Attr { +def NoReturn : InheritableAttr { let Spellings = ["noreturn"]; // FIXME: Does GCC allow this on the function instead? let Subjects = [Function]; let Namespaces = ["", "std"]; } -def NoInstrumentFunction : Attr { +def NoInstrumentFunction : InheritableAttr { let Spellings = ["no_instrument_function"]; let Subjects = [Function]; } -def NoThrow : Attr { +def NoThrow : InheritableAttr { let Spellings = ["nothrow"]; } -def NSReturnsRetained : Attr { +def NSReturnsRetained : InheritableAttr { let Spellings = ["ns_returns_retained"]; + let Subjects = [ObjCMethod, Function]; } -def NSReturnsNotRetained : Attr { +def NSReturnsNotRetained : InheritableAttr { let Spellings = ["ns_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; } -def ObjCException : Attr { - let Spellings = ["objc_exception"]; +def NSReturnsAutoreleased : InheritableAttr { + let Spellings = ["ns_returns_autoreleased"]; + let Subjects = [ObjCMethod, Function]; } -def ObjCNSObject : Attr { - let Spellings = ["NSOjbect"]; +def NSConsumesSelf : InheritableAttr { + let Spellings = ["ns_consumes_self"]; + let Subjects = [ObjCMethod]; } -def Override : Attr { - let Spellings = ["override"]; - let Subjects = [CXXVirtualMethod]; - let Namespaces = ["", "std"]; +def NSConsumed : InheritableAttr { + let Spellings = ["ns_consumed"]; + let Subjects = [ParmVar]; +} + +def ObjCException : InheritableAttr { + let Spellings = ["objc_exception"]; +} + +def ObjCNSObject : InheritableAttr { + let Spellings = ["NSObject"]; } def Overloadable : Attr { let Spellings = ["overloadable"]; } -def Ownership : Attr { +def Override : InheritableAttr { + let Spellings = []; +} + +def Ownership : InheritableAttr { let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"]; let Args = [EnumArgument<"OwnKind", "OwnershipKind", ["ownership_holds", "ownership_returns", "ownership_takes"], @@ -316,97 +384,104 @@ def Ownership : Attr { StringArgument<"Module">, VariadicUnsignedArgument<"Args">]; } -def Packed : Attr { +def Packed : InheritableAttr { let Spellings = ["packed"]; } -def Pure : Attr { +def Pure : InheritableAttr { let Spellings = ["pure"]; } -def Regparm : Attr { +def Regparm : InheritableAttr { let Spellings = ["regparm"]; let Args = [UnsignedArgument<"NumParams">]; } -def ReqdWorkGroupSize : Attr { +def ReqdWorkGroupSize : InheritableAttr { let Spellings = ["reqd_work_group_size"]; let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, UnsignedArgument<"ZDim">]; } -def InitPriority : Attr { +def InitPriority : InheritableAttr { let Spellings = ["init_priority"]; let Args = [UnsignedArgument<"Priority">]; } -def Section : Attr { +def Section : InheritableAttr { let Spellings = ["section"]; let Args = [StringArgument<"Name">]; } -def Sentinel : Attr { +def Sentinel : InheritableAttr { let Spellings = ["sentinel"]; let Args = [DefaultIntArgument<"Sentinel", 0>, DefaultIntArgument<"NullPos", 0>]; } -def StdCall : Attr { +def StdCall : InheritableAttr { let Spellings = ["stdcall", "__stdcall"]; } -def ThisCall : Attr { +def ThisCall : InheritableAttr { let Spellings = ["thiscall", "__thiscall"]; } -def Pascal : Attr { +def Pascal : InheritableAttr { let Spellings = ["pascal", "__pascal"]; } -def TransparentUnion : Attr { +def TransparentUnion : InheritableAttr { let Spellings = ["transparent_union"]; } -def Unavailable : Attr { +def Unavailable : InheritableAttr { let Spellings = ["unavailable"]; + let Args = [StringArgument<"Message">]; } -def Unused : Attr { +def Unused : InheritableAttr { let Spellings = ["unused"]; } -def Used : Attr { +def Used : InheritableAttr { let Spellings = ["used"]; } -def Visibility : Attr { +def Uuid : InheritableAttr { + let Spellings = ["uuid"]; + let Args = [StringArgument<"Guid">]; + let Subjects = [CXXRecord]; +} + +def Visibility : InheritableAttr { let Spellings = ["visibility"]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; } -def VecReturn : Attr { +def VecReturn : InheritableAttr { let Spellings = ["vecreturn"]; let Subjects = [CXXRecord]; } -def WarnUnusedResult : Attr { +def WarnUnusedResult : InheritableAttr { let Spellings = ["warn_unused_result"]; } -def Weak : Attr { +def Weak : InheritableAttr { let Spellings = ["weak"]; } -def WeakImport : Attr { +def WeakImport : InheritableAttr { let Spellings = ["weak_import"]; } -def WeakRef : Attr { +def WeakRef : InheritableAttr { let Spellings = ["weakref"]; } -def X86ForceAlignArgPointer : Attr { +def X86ForceAlignArgPointer : InheritableAttr { let Spellings = []; } diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h index 822573b734a7..65c4f98c952c 100644 --- a/include/clang/Basic/AttrKinds.h +++ b/include/clang/Basic/AttrKinds.h @@ -21,6 +21,7 @@ namespace attr { // Kind - This is a list of all the recognized kinds of attributes. enum Kind { #define ATTR(X) X, +#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X, #include "clang/Basic/AttrList.inc" NUM_ATTRS }; diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 0da893899b0b..7d270ad7fb89 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -29,6 +29,8 @@ // d -> double // z -> size_t // F -> constant CFString +// G -> id +// H -> SEL // a -> __builtin_va_list // A -> "reference" to __builtin_va_list // V -> Vector, following num elements and a base type. @@ -38,12 +40,13 @@ // SJ -> sigjmp_buf // . -> "...". This may only occur at the end of the function list. // -// Types maybe prefixed with the following modifiers: +// Types may be prefixed with the following modifiers: // L -> long (e.g. Li for 'long int') // LL -> long long // LLL -> __int128_t (e.g. LLLi) // S -> signed // U -> unsigned +// I -> Required to constant fold to an integer constant expression. // // Types may be postfixed with the following modifiers: // * -> pointer (optionally followed by an address space number) @@ -75,7 +78,7 @@ // FIXME: gcc has nonnull #if defined(BUILTIN) && !defined(LIBBUILTIN) -# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) BUILTIN(ID, TYPE, ATTRS) +# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) #endif // Standard libc/libm functions: @@ -124,12 +127,24 @@ BUILTIN(__builtin_powl, "LdLdLd", "Fnc") BUILTIN(__builtin_acos , "dd" , "Fnc") BUILTIN(__builtin_acosf, "ff" , "Fnc") BUILTIN(__builtin_acosl, "LdLd", "Fnc") +BUILTIN(__builtin_acosh , "dd" , "Fnc") +BUILTIN(__builtin_acoshf, "ff" , "Fnc") +BUILTIN(__builtin_acoshl, "LdLd", "Fnc") BUILTIN(__builtin_asin , "dd" , "Fnc") BUILTIN(__builtin_asinf, "ff" , "Fnc") BUILTIN(__builtin_asinl, "LdLd", "Fnc") +BUILTIN(__builtin_asinh , "dd" , "Fnc") +BUILTIN(__builtin_asinhf, "ff" , "Fnc") +BUILTIN(__builtin_asinhl, "LdLd", "Fnc") BUILTIN(__builtin_atan , "dd" , "Fnc") BUILTIN(__builtin_atanf, "ff" , "Fnc") BUILTIN(__builtin_atanl, "LdLd", "Fnc") +BUILTIN(__builtin_atanh , "dd", "Fnc") +BUILTIN(__builtin_atanhf, "ff", "Fnc") +BUILTIN(__builtin_atanhl, "LdLd", "Fnc") +BUILTIN(__builtin_cbrt , "dd", "Fnc") +BUILTIN(__builtin_cbrtf, "ff", "Fnc") +BUILTIN(__builtin_cbrtl, "LdLd", "Fnc") BUILTIN(__builtin_ceil , "dd" , "Fnc") BUILTIN(__builtin_ceilf, "ff" , "Fnc") BUILTIN(__builtin_ceill, "LdLd", "Fnc") @@ -139,21 +154,99 @@ BUILTIN(__builtin_cosh , "dd" , "Fnc") BUILTIN(__builtin_coshf, "ff" , "Fnc") BUILTIN(__builtin_coshl, "LdLd", "Fnc") BUILTIN(__builtin_cosl, "LdLd", "Fnc") +BUILTIN(__builtin_erf , "dd", "Fnc") +BUILTIN(__builtin_erff, "ff", "Fnc") +BUILTIN(__builtin_erfl, "LdLd", "Fnc") +BUILTIN(__builtin_erfc , "dd", "Fnc") +BUILTIN(__builtin_erfcf, "ff", "Fnc") +BUILTIN(__builtin_erfcl, "LdLd", "Fnc") BUILTIN(__builtin_exp , "dd" , "Fnc") BUILTIN(__builtin_expf, "ff" , "Fnc") BUILTIN(__builtin_expl, "LdLd", "Fnc") +BUILTIN(__builtin_exp2 , "dd" , "Fnc") +BUILTIN(__builtin_exp2f, "ff" , "Fnc") +BUILTIN(__builtin_exp2l, "LdLd", "Fnc") +BUILTIN(__builtin_expm1 , "dd", "Fnc") +BUILTIN(__builtin_expm1f, "ff", "Fnc") +BUILTIN(__builtin_expm1l, "LdLd", "Fnc") +BUILTIN(__builtin_fdim, "ddd", "Fnc") +BUILTIN(__builtin_fdimf, "fff", "Fnc") +BUILTIN(__builtin_fdiml, "LdLdLd", "Fnc") BUILTIN(__builtin_floor , "dd" , "Fnc") BUILTIN(__builtin_floorf, "ff" , "Fnc") BUILTIN(__builtin_floorl, "LdLd", "Fnc") +BUILTIN(__builtin_fma, "dddd", "Fnc") +BUILTIN(__builtin_fmaf, "ffff", "Fnc") +BUILTIN(__builtin_fmal, "LdLdLdLd", "Fnc") +BUILTIN(__builtin_fmax, "ddd", "Fnc") +BUILTIN(__builtin_fmaxf, "fff", "Fnc") +BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc") +BUILTIN(__builtin_fmin, "ddd", "Fnc") +BUILTIN(__builtin_fminf, "fff", "Fnc") +BUILTIN(__builtin_fminl, "LdLdLd", "Fnc") BUILTIN(__builtin_hypot , "ddd" , "Fnc") BUILTIN(__builtin_hypotf, "fff" , "Fnc") BUILTIN(__builtin_hypotl, "LdLdLd", "Fnc") +BUILTIN(__builtin_ilogb , "id", "Fnc") +BUILTIN(__builtin_ilogbf, "if", "Fnc") +BUILTIN(__builtin_ilogbl, "iLd", "Fnc") +BUILTIN(__builtin_lgamma , "dd", "Fnc") +BUILTIN(__builtin_lgammaf, "ff", "Fnc") +BUILTIN(__builtin_lgammal, "LdLd", "Fnc") +BUILTIN(__builtin_llrint, "LLid", "Fnc") +BUILTIN(__builtin_llrintf, "LLif", "Fnc") +BUILTIN(__builtin_llrintl, "LLiLd", "Fnc") +BUILTIN(__builtin_llround , "LLid", "Fnc") +BUILTIN(__builtin_llroundf, "LLif", "Fnc") +BUILTIN(__builtin_llroundl, "LLiLd", "Fnc") BUILTIN(__builtin_log , "dd" , "Fnc") BUILTIN(__builtin_log10 , "dd" , "Fnc") BUILTIN(__builtin_log10f, "ff" , "Fnc") BUILTIN(__builtin_log10l, "LdLd", "Fnc") +BUILTIN(__builtin_log1p , "dd" , "Fnc") +BUILTIN(__builtin_log1pf, "ff" , "Fnc") +BUILTIN(__builtin_log1pl, "LdLd", "Fnc") +BUILTIN(__builtin_log2, "dd" , "Fnc") +BUILTIN(__builtin_log2f, "ff" , "Fnc") +BUILTIN(__builtin_log2l, "LdLd" , "Fnc") +BUILTIN(__builtin_logb , "dd", "Fnc") +BUILTIN(__builtin_logbf, "ff", "Fnc") +BUILTIN(__builtin_logbl, "LdLd", "Fnc") BUILTIN(__builtin_logf, "ff" , "Fnc") BUILTIN(__builtin_logl, "LdLd", "Fnc") +BUILTIN(__builtin_lrint , "Lid", "Fnc") +BUILTIN(__builtin_lrintf, "Lif", "Fnc") +BUILTIN(__builtin_lrintl, "LiLd", "Fnc") +BUILTIN(__builtin_lround , "Lid", "Fnc") +BUILTIN(__builtin_lroundf, "Lif", "Fnc") +BUILTIN(__builtin_lroundl, "LiLd", "Fnc") +BUILTIN(__builtin_nearbyint , "dd", "Fnc") +BUILTIN(__builtin_nearbyintf, "ff", "Fnc") +BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc") +BUILTIN(__builtin_nextafter , "ddd", "Fnc") +BUILTIN(__builtin_nextafterf, "fff", "Fnc") +BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc") +BUILTIN(__builtin_nexttoward , "ddd", "Fnc") +BUILTIN(__builtin_nexttowardf, "fff", "Fnc") +BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remainder , "ddd", "Fnc") +BUILTIN(__builtin_remainderf, "fff", "Fnc") +BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remquo , "dddi*", "Fnc") +BUILTIN(__builtin_remquof, "fffi*", "Fnc") +BUILTIN(__builtin_remquol, "LdLdLdi*", "Fnc") +BUILTIN(__builtin_rint , "dd", "Fnc") +BUILTIN(__builtin_rintf, "ff", "Fnc") +BUILTIN(__builtin_rintl, "LdLd", "Fnc") +BUILTIN(__builtin_round, "dd" , "Fnc") +BUILTIN(__builtin_roundf, "ff" , "Fnc") +BUILTIN(__builtin_roundl, "LdLd" , "Fnc") +BUILTIN(__builtin_scalbln , "ddLi", "Fnc") +BUILTIN(__builtin_scalblnf, "ffLi", "Fnc") +BUILTIN(__builtin_scalblnl, "LdLdLi", "Fnc") +BUILTIN(__builtin_scalbn , "ddi", "Fnc") +BUILTIN(__builtin_scalbnf, "ffi", "Fnc") +BUILTIN(__builtin_scalbnl, "LdLdi", "Fnc") BUILTIN(__builtin_sin , "dd" , "Fnc") BUILTIN(__builtin_sinf, "ff" , "Fnc") BUILTIN(__builtin_sinh , "dd" , "Fnc") @@ -169,6 +262,12 @@ BUILTIN(__builtin_tanh , "dd" , "Fnc") BUILTIN(__builtin_tanhf, "ff" , "Fnc") BUILTIN(__builtin_tanhl, "LdLd", "Fnc") BUILTIN(__builtin_tanl, "LdLd", "Fnc") +BUILTIN(__builtin_tgamma , "dd", "Fnc") +BUILTIN(__builtin_tgammaf, "ff", "Fnc") +BUILTIN(__builtin_tgammal, "LdLd", "Fnc") +BUILTIN(__builtin_trunc , "dd", "Fnc") +BUILTIN(__builtin_truncf, "ff", "Fnc") +BUILTIN(__builtin_truncl, "LdLd", "Fnc") // C99 complex builtins BUILTIN(__builtin_cabs, "dXd", "Fnc") @@ -176,15 +275,24 @@ BUILTIN(__builtin_cabsf, "fXf", "Fnc") BUILTIN(__builtin_cabsl, "LdXLd", "Fnc") BUILTIN(__builtin_cacos, "XdXd", "Fnc") BUILTIN(__builtin_cacosf, "XfXf", "Fnc") +BUILTIN(__builtin_cacosh, "XdXd", "Fnc") +BUILTIN(__builtin_cacoshf, "XfXf", "Fnc") +BUILTIN(__builtin_cacoshl, "XLdXLd", "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_casinh, "XdXd", "Fnc") +BUILTIN(__builtin_casinhf, "XfXf", "Fnc") +BUILTIN(__builtin_casinhl, "XLdXLd", "Fnc") BUILTIN(__builtin_casinl, "XLdXLd", "Fnc") BUILTIN(__builtin_catan, "XdXd", "Fnc") BUILTIN(__builtin_catanf, "XfXf", "Fnc") +BUILTIN(__builtin_catanh, "XdXd", "Fnc") +BUILTIN(__builtin_catanhf, "XfXf", "Fnc") +BUILTIN(__builtin_catanhl, "XLdXLd", "Fnc") BUILTIN(__builtin_catanl, "XLdXLd", "Fnc") BUILTIN(__builtin_ccos, "XdXd", "Fnc") BUILTIN(__builtin_ccosf, "XfXf", "Fnc") @@ -275,7 +383,7 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc") BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") // Random GCC builtins -BUILTIN(__builtin_constant_p, "Us.", "nc") +BUILTIN(__builtin_constant_p, "i.", "nc") BUILTIN(__builtin_classify_type, "i.", "nc") BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") @@ -313,14 +421,14 @@ BUILTIN(__builtin_strpbrk, "c*cC*cC*", "nF") BUILTIN(__builtin_strrchr, "c*cC*i", "nF") BUILTIN(__builtin_strspn, "zcC*cC*", "nF") BUILTIN(__builtin_strstr, "c*cC*cC*", "nF") -BUILTIN(__builtin_return_address, "v*Ui", "n") +BUILTIN(__builtin_return_address, "v*IUi", "n") BUILTIN(__builtin_extract_return_addr, "v*v*", "n") -BUILTIN(__builtin_frame_address, "v*Ui", "n") +BUILTIN(__builtin_frame_address, "v*IUi", "n") BUILTIN(__builtin_flt_rounds, "i", "nc") BUILTIN(__builtin_setjmp, "iv**", "") BUILTIN(__builtin_longjmp, "vv**i", "r") BUILTIN(__builtin_unwind_init, "v", "") -BUILTIN(__builtin_eh_return_data_regno, "ii", "nc") +BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc") BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:") BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:") BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") @@ -485,92 +593,135 @@ BUILTIN(__builtin_abort, "v", "Fnr") BUILTIN(__builtin_index, "c*cC*i", "Fn") BUILTIN(__builtin_rindex, "c*cC*i", "Fn") - +// Microsoft builtins. +BUILTIN(__assume, "vb", "n") +BUILTIN(__noop, "v.", "n") // C99 library functions // C99 stdlib.h -LIBBUILTIN(abort, "v", "fr", "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") +LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES) // C99 string.h -LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h") -LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h") -LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h") -LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h") -LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h") -LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h") -LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h") -LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h") -LIBBUILTIN(strchr, "c*cC*i", "f", "string.h") -LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h") -LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h") -LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h") -LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h") -LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h") -LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h") -LIBBUILTIN(memset, "v*v*iz", "f", "string.h") -LIBBUILTIN(strerror, "c*i", "f", "string.h") -LIBBUILTIN(strlen, "zcC*", "f", "string.h") +LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES) // C99 stdio.h -LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h") -LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h") -LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h") -LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h") -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") -LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h") +LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h", ALL_LANGUAGES) // C99 -LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h") +LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) // Non-C library functions // FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode! -LIBBUILTIN(alloca, "v*z", "f", "stdlib.h") +LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_LANGUAGES) // POSIX string.h -LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h") -LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h") -LIBBUILTIN(strdup, "c*cC*", "f", "string.h") -LIBBUILTIN(strndup, "c*cC*z", "f", "string.h") +LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES) // POSIX strings.h -LIBBUILTIN(index, "c*cC*i", "f", "strings.h") -LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h") -LIBBUILTIN(bzero, "vv*z", "f", "strings.h") +LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES) // POSIX unistd.h -LIBBUILTIN(_exit, "vi", "fr", "unistd.h") +LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES) // POSIX setjmp.h -LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h") -LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h") +LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES) +// id objc_msgSend(id, SEL, ...) +LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG) + +// long double objc_msgSend_fpret(id self, SEL op, ...) +LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG) +// id objc_msgSend_stret (id, SEL, ...) +LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG) +// id objc_msgSendSuper(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper, "Gv*H.", "f", "objc/message.h", OBJC_LANG) +// void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper_stret, "vv*H.", "f", "objc/message.h", OBJC_LANG) +// id objc_getClass(const char *name) +LIBBUILTIN(objc_getClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// id objc_getMetaClass(const char *name) +LIBBUILTIN(objc_getMetaClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// void objc_enumerationMutation(id) +LIBBUILTIN(objc_enumerationMutation, "vG", "f", "objc/runtime.h", OBJC_LANG) + +// id objc_read_weak(id *location) +LIBBUILTIN(objc_read_weak, "GG*", "f", "/objc/objc-auto.h", OBJC_LANG) +// id objc_assign_weak(id value, id *location) +LIBBUILTIN(objc_assign_weak, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG) +// id objc_assign_ivar(id value, id dest, ptrdiff_t offset) +// FIXME. Darwin has ptrdiff_t typedef'ed to int. +LIBBUILTIN(objc_assign_ivar, "GGGi", "f", "/objc/objc-auto.h", OBJC_LANG) +// id objc_assign_global(id val, id *dest) +LIBBUILTIN(objc_assign_global, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG) +// id objc_assign_strongCast(id val, id *dest +LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG) + +// id objc_exception_extract(void *localExceptionData) +LIBBUILTIN(objc_exception_extract, "Gv*", "f", "/objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_enter(void *localExceptionData) +LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_exit(void *localExceptionData) +LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG) +// int objc_exception_match(Class exceptionClass, id exception) +LIBBUILTIN(objc_exception_match, "iGG", "f", "/objc/objc-exception.h", OBJC_LANG) +// void objc_exception_throw(id exception) +LIBBUILTIN(objc_exception_throw, "vG", "f", "/objc/objc-exception.h", OBJC_LANG) + +// int objc_sync_enter(id obj) +LIBBUILTIN(objc_sync_enter, "iG", "f", "/objc/objc-sync.h", OBJC_LANG) +// int objc_sync_exit(id obj) +LIBBUILTIN(objc_sync_exit, "iG", "f", "/objc/objc-sync.h", OBJC_LANG) -// 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") BUILTIN(__builtin_objc_memmove_collectable, "v*v*vC*z", "nF") // Builtin math library functions -LIBBUILTIN(pow, "ddd", "fe", "math.h") -LIBBUILTIN(powl, "LdLdLd", "fe", "math.h") -LIBBUILTIN(powf, "fff", "fe", "math.h") +LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES) -LIBBUILTIN(sqrt, "dd", "fe", "math.h") -LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h") -LIBBUILTIN(sqrtf, "ff", "fe", "math.h") +LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES) -LIBBUILTIN(sin, "dd", "fe", "math.h") -LIBBUILTIN(sinl, "LdLd", "fe", "math.h") -LIBBUILTIN(sinf, "ff", "fe", "math.h") +LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES) -LIBBUILTIN(cos, "dd", "fe", "math.h") -LIBBUILTIN(cosl, "LdLd", "fe", "math.h") -LIBBUILTIN(cosf, "ff", "fe", "math.h") +LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES) // Blocks runtime Builtin math library functions -LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h") -LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h") +LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES) +LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES) // FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock. #undef BUILTIN diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 94d5e6955a24..4df4c8f95374 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -30,7 +30,15 @@ namespace clang { class IdentifierTable; class ASTContext; class QualType; - + class LangOptions; + + enum LanguageID { + C_LANG = 0x1, // builtin for c only. + CXX_LANG = 0x2, // builtin for cplusplus only. + OBJC_LANG = 0x4, // builtin for objective-c and objective-c++ + ALL_LANGUAGES = (C_LANG|CXX_LANG|OBJC_LANG) //builtin is for all languages. + }; + namespace Builtin { enum ID { NotBuiltin = 0, // This is not a builtin function. @@ -41,6 +49,7 @@ enum ID { struct Info { const char *Name, *Type, *Attributes, *HeaderName; + LanguageID builtin_lang; bool Suppressed; bool operator==(const Info &RHS) const { @@ -62,7 +71,7 @@ public: /// InitializeBuiltins - Mark the identifiers for all the builtins with their /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. - void InitializeBuiltins(IdentifierTable &Table, bool NoBuiltins = false); + void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts); /// \brief Popular the vector with the names of all of the builtins. void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, @@ -108,6 +117,10 @@ public: return strchr(GetRecord(ID).Attributes, 'f') != 0; } + /// \brief Completely forget that the given ID was ever considered a builtin, + /// e.g., because the user provided a conflicting signature. + void ForgetBuiltin(unsigned ID, IdentifierTable &Table); + /// \brief If this is a library function that comes from a specific /// header, retrieve that header name. const char *getHeaderName(unsigned ID) const { @@ -124,12 +137,6 @@ public: /// argument and whether this function as a va_list argument. bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg); - /// hasVAListUse - Return true of the specified builtin uses __builtin_va_list - /// as an operand or return type. - 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/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index e0518dcdb681..8a751e4ce846 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -50,25 +50,25 @@ BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "") BUILTIN(__builtin_altivec_dss, "vUi", "") BUILTIN(__builtin_altivec_dssall, "v", "") -BUILTIN(__builtin_altivec_dst, "vv*iUi", "") -BUILTIN(__builtin_altivec_dstt, "vv*iUi", "") -BUILTIN(__builtin_altivec_dstst, "vv*iUi", "") -BUILTIN(__builtin_altivec_dststt, "vv*iUi", "") +BUILTIN(__builtin_altivec_dst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstt, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dststt, "vvC*iUi", "") BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "") BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "") -BUILTIN(__builtin_altivec_lvx, "V4iiv*", "") -BUILTIN(__builtin_altivec_lvxl, "V4iiv*", "") -BUILTIN(__builtin_altivec_lvebx, "V16civ*", "") -BUILTIN(__builtin_altivec_lvehx, "V8siv*", "") -BUILTIN(__builtin_altivec_lvewx, "V4iiv*", "") +BUILTIN(__builtin_altivec_lvx, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvxl, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvebx, "V16civC*", "") +BUILTIN(__builtin_altivec_lvehx, "V8sivC*", "") +BUILTIN(__builtin_altivec_lvewx, "V4iivC*", "") BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "") -BUILTIN(__builtin_altivec_lvsl, "V16cUcv*", "") -BUILTIN(__builtin_altivec_lvsr, "V16cUcv*", "") +BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "") +BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "") BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "") BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "") diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 5ad64b9b49d1..da106daf26ec 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -25,11 +25,16 @@ // FIXME: Are these nothrow/const? // MMX +// +// FIXME: All MMX instructions will be generated via builtins. Any MMX vector +// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be +// expanded by the back-end. BUILTIN(__builtin_ia32_emms, "v", "") BUILTIN(__builtin_ia32_femms, "v", "") BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "") @@ -37,6 +42,7 @@ BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "") BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "") @@ -76,6 +82,7 @@ BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "") BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "") BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "") BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "") +BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "") BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "") @@ -91,7 +98,7 @@ BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "") BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "") BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "") -BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cc", "") // FIXME: Correct type? +BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "") BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "") BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "") BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "") @@ -249,8 +256,8 @@ BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "") BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "") -BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLii", "") -BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLii", "") +BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLiIi", "") +BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLiIi", "") BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "") BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "") @@ -267,7 +274,7 @@ BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") -BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cc", "") // FIXME: Correct type? +BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "") // FIXME: Correct type? BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index e2f93e02c525..2ec7427cf758 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -15,6 +15,7 @@ def Named : Decl<1>; def Namespace : DDecl<Named>, DeclContext; def UsingDirective : DDecl<Named>; def NamespaceAlias : DDecl<Named>; + def Label : DDecl<Named>; def Type : DDecl<Named, 1>; def Typedef : DDecl<Type>; def UnresolvedUsingTypename : DDecl<Type>; @@ -29,6 +30,7 @@ def Named : Decl<1>; def Value : DDecl<Named, 1>; def EnumConstant : DDecl<Value>; def UnresolvedUsingValue : DDecl<Value>; + def IndirectField : DDecl<Value>; def Declarator : DDecl<Value, 1>; def Function : DDecl<Declarator>, DeclContext; def CXXMethod : DDecl<Function>; @@ -41,7 +43,7 @@ def Named : Decl<1>; def Var : DDecl<Declarator>; def ImplicitParam : DDecl<Var>; def ParmVar : DDecl<Var>; - def NonTypeTemplateParm : DDecl<Var>; + def NonTypeTemplateParm : DDecl<Declarator>; def Template : DDecl<Named, 1>; def RedeclarableTemplate : DDecl<Template, 1>; def FunctionTemplate : DDecl<RedeclarableTemplate>; diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 37d26947c335..19e7c91f5324 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -14,76 +14,24 @@ #ifndef LLVM_CLANG_DIAGNOSTIC_H #define LLVM_CLANG_DIAGNOSTIC_H +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/type_traits.h" -#include <string> -#include <vector> -#include <cassert> -namespace llvm { - template <typename T> class SmallVectorImpl; -} +#include <vector> +#include <list> namespace clang { - class DeclContext; - class DiagnosticBuilder; class DiagnosticClient; - class FileManager; + class DiagnosticBuilder; class IdentifierInfo; + class DeclContext; class LangOptions; - class PartialDiagnostic; class Preprocessor; - - // Import the diagnostic enums themselves. - namespace diag { - // Start position for diagnostics. - enum { - DIAG_START_DRIVER = 300, - DIAG_START_FRONTEND = DIAG_START_DRIVER + 100, - DIAG_START_LEX = DIAG_START_FRONTEND + 100, - DIAG_START_PARSE = DIAG_START_LEX + 300, - DIAG_START_AST = DIAG_START_PARSE + 300, - DIAG_START_SEMA = DIAG_START_AST + 100, - DIAG_START_ANALYSIS = DIAG_START_SEMA + 1500, - DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 - }; - - class CustomDiagInfo; - - /// diag::kind - All of the diagnostics that can be emitted by the frontend. - typedef unsigned kind; - - // Get typedefs for common diagnostics. - enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, -#include "clang/Basic/DiagnosticCommonKinds.inc" - 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 - /// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this - /// one). - enum Mapping { - // NOTE: 0 means "uncomputed". - MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. - 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, - /// Map this diagnostic to "error", but make it immune to -Wfatal-errors. - /// This happens for -Wno-fatal-errors=foo. - MAP_ERROR_NO_WFATAL = 6 - }; - } + class DiagnosticErrorTrap; /// \brief Annotates a diagnostic with some code that should be /// inserted, removed, or replaced to fix the problem. @@ -153,12 +101,17 @@ public: /// Diagnostic - This concrete class is used by the front-end to report /// problems and issues. It massages the diagnostics (e.g. handling things like /// "report warnings as errors" and passes them off to the DiagnosticClient for -/// reporting to the user. +/// reporting to the user. Diagnostic is tied to one translation unit and +/// one SourceManager. class Diagnostic : public llvm::RefCountedBase<Diagnostic> { public: /// Level - The level of the diagnostic, after it has been through mapping. enum Level { - Ignored, Note, Warning, Error, Fatal + Ignored = DiagnosticIDs::Ignored, + Note = DiagnosticIDs::Note, + Warning = DiagnosticIDs::Warning, + Error = DiagnosticIDs::Error, + Fatal = DiagnosticIDs::Fatal }; /// ExtensionHandling - How do we handle otherwise-unmapped extension? This @@ -203,33 +156,94 @@ private: unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, // 0 -> no limit. ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? - llvm::OwningPtr<DiagnosticClient> Client; - - /// DiagMappings - Mapping information for diagnostics. Mapping info is + llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags; + DiagnosticClient *Client; + bool OwnsDiagClient; + SourceManager *SourceMgr; + + /// \brief Mapping information for diagnostics. Mapping info is /// packed into four bits per diagnostic. The low three bits are the mapping /// (an instance of diag::Mapping), or zero if unset. The high bit is set /// 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. - class DiagMappings { - unsigned char Values[diag::DIAG_UPPER_LIMIT/2]; + /// + /// A new DiagState is created and kept around when diagnostic pragmas modify + /// the state so that we know what is the diagnostic state at any given + /// source location. + class DiagState { + llvm::DenseMap<unsigned, unsigned> DiagMap; public: - DiagMappings() { - memset(Values, 0, diag::DIAG_UPPER_LIMIT/2); - } + typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator; - void setMapping(diag::kind Diag, unsigned Map) { - size_t Shift = (Diag & 1)*4; - Values[Diag/2] = (Values[Diag/2] & ~(15 << Shift)) | (Map << Shift); - } + void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; } diag::Mapping getMapping(diag::kind Diag) const { - return (diag::Mapping)((Values[Diag/2] >> (Diag & 1)*4) & 15); + iterator I = DiagMap.find(Diag); + if (I != DiagMap.end()) + return (diag::Mapping)I->second; + return diag::Mapping(); + } + + iterator begin() const { return DiagMap.begin(); } + iterator end() const { return DiagMap.end(); } + }; + + /// \brief Keeps and automatically disposes all DiagStates that we create. + std::list<DiagState> DiagStates; + + /// \brief Represents a point in source where the diagnostic state was + /// modified because of a pragma. 'Loc' can be null if the point represents + /// the diagnostic state modifications done through the command-line. + struct DiagStatePoint { + DiagState *State; + FullSourceLoc Loc; + DiagStatePoint(DiagState *State, FullSourceLoc Loc) + : State(State), Loc(Loc) { } + + bool operator<(const DiagStatePoint &RHS) const { + // If Loc is invalid it means it came from <command-line>, in which case + // we regard it as coming before any valid source location. + if (RHS.Loc.isInvalid()) + return false; + if (Loc.isInvalid()) + return true; + return Loc.isBeforeInTranslationUnitThan(RHS.Loc); } }; - mutable std::vector<DiagMappings> DiagMappingsStack; + /// \brief A vector of all DiagStatePoints representing changes in diagnostic + /// state due to diagnostic pragmas. The vector is always sorted according to + /// the SourceLocation of the DiagStatePoint. + typedef std::vector<DiagStatePoint> DiagStatePointsTy; + mutable DiagStatePointsTy DiagStatePoints; + + /// \brief Keeps the DiagState that was active during each diagnostic 'push' + /// so we can get back at it when we 'pop'. + std::vector<DiagState *> DiagStateOnPushStack; + + DiagState *GetCurDiagState() const { + assert(!DiagStatePoints.empty()); + return DiagStatePoints.back().State; + } + + void PushDiagStatePoint(DiagState *State, SourceLocation L) { + FullSourceLoc Loc(L, *SourceMgr); + // Make sure that DiagStatePoints is always sorted according to Loc. + assert((Loc.isValid() || DiagStatePoints.empty()) && + "Adding invalid loc point after another point"); + assert((Loc.isInvalid() || DiagStatePoints.empty() || + DiagStatePoints.back().Loc.isInvalid() || + DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) && + "Previous point loc comes after or is the same as new one"); + DiagStatePoints.push_back(DiagStatePoint(State, + FullSourceLoc(Loc, *SourceMgr))); + } + + /// \brief Finds the DiagStatePoint that contains the diagnostic state of + /// the given source location. + DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const; /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or /// fatal error is emitted, and is sticky. @@ -239,14 +253,11 @@ private: /// 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. - Diagnostic::Level LastDiagLevel; + DiagnosticIDs::Level LastDiagLevel; unsigned NumWarnings; // Number of warnings reported unsigned NumErrors; // Number of errors reported unsigned NumErrorsSuppressed; // Number of errors suppressed - - /// CustomDiagInfo - Information for uniquing and looking up custom diags. - diag::CustomDiagInfo *CustomDiagInfo; /// ArgToStringFn - A function pointer that converts an opaque diagnostic /// argument to a strings. This takes the modifiers and argument that was @@ -279,34 +290,52 @@ private: std::string DelayedDiagArg2; public: - explicit Diagnostic(DiagnosticClient *client = 0); + explicit Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags, + DiagnosticClient *client = 0, + bool ShouldOwnClient = true); ~Diagnostic(); - //===--------------------------------------------------------------------===// - // Diagnostic characterization methods, used by a client to customize how - // + const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { + return Diags; + } + + DiagnosticClient *getClient() { return Client; } + const DiagnosticClient *getClient() const { return Client; } - DiagnosticClient *getClient() { return Client.get(); } - const DiagnosticClient *getClient() const { return Client.get(); } - /// \brief Return the current diagnostic client along with ownership of that /// client. - DiagnosticClient *takeClient() { return Client.take(); } + DiagnosticClient *takeClient() { + OwnsDiagClient = false; + return Client; + } + + bool hasSourceManager() const { return SourceMgr != 0; } + SourceManager &getSourceManager() const { + assert(SourceMgr && "SourceManager not set!"); + return *SourceMgr; + } + void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; } + + //===--------------------------------------------------------------------===// + // Diagnostic characterization methods, used by a client to customize how + // diagnostics are emitted. + // /// pushMappings - Copies the current DiagMappings and pushes the new copy /// onto the top of the stack. - void pushMappings(); + void pushMappings(SourceLocation Loc); /// 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(); + bool popMappings(SourceLocation Loc); /// \brief Set the diagnostic client associated with this diagnostic object. /// - /// The diagnostic object takes ownership of \c client. - void setClient(DiagnosticClient* client) { Client.reset(client); } + /// \param ShouldOwnClient true if the diagnostic object should take + /// ownership of \c client. + void setClient(DiagnosticClient *client, bool ShouldOwnClient = true); /// setErrorLimit - Specify a limit for the number of errors we should /// emit before giving up. Zero disables the limit. @@ -362,7 +391,7 @@ public: /// \brief Pretend that the last diagnostic issued was ignored. This can /// be used by clients who suppress diagnostics themselves. void setLastDiagnosticIgnored() { - LastDiagLevel = Ignored; + LastDiagLevel = DiagnosticIDs::Ignored; } /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped @@ -379,28 +408,29 @@ public: void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } - /// setDiagnosticMapping - This allows the client to specify that certain + /// \brief 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. - void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { - assert(Diag < diag::DIAG_UPPER_LIMIT && - "Can only map builtin diagnostics"); - assert((isBuiltinWarningOrExtension(Diag) || - (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) && - "Cannot map errors into warnings!"); - setDiagnosticMappingInternal(Diag, Map, true); - } + /// + /// \param Loc The source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the latest state. + void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, + SourceLocation Loc); /// 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. - bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map); + /// + /// 'Loc' is the source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the state from command-line. + bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map, + SourceLocation Loc = SourceLocation()) { + return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this); + } bool hasErrorOccurred() const { return ErrorOccurred; } bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } - unsigned getNumErrors() const { return NumErrors; } - unsigned getNumErrorsSuppressed() const { return NumErrorsSuppressed; } unsigned getNumWarnings() const { return NumWarnings; } void setNumWarnings(unsigned NumWarnings) { @@ -410,8 +440,9 @@ public: /// 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, llvm::StringRef Message); - + unsigned getCustomDiagID(Level L, llvm::StringRef Message) { + return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message); + } /// ConvertArgToString - This method converts a diagnostic argument (as an /// intptr_t) into the string that represents it. @@ -437,92 +468,22 @@ public: // Diagnostic classification and reporting interfaces. // - /// 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 - /// call on NOTEs. - static bool isBuiltinWarningOrExtension(unsigned DiagID); - - /// \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) { - bool ignored; - return isBuiltinExtensionDiag(DiagID, ignored); - } - - /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic - /// ID is for an extension of some sort. This also returns EnabledByDefault, - /// which is set to indicate whether the diagnostic is ignored by default (in - /// which case -pedantic enables it) or treated as a warning/error by default. - /// - static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); - - - /// 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. - static const char *getWarningOptionForDiag(unsigned DiagID); - - /// getWarningOptionForDiag - Return the category number that a specified - /// DiagID belongs to, or 0 if no category. - static unsigned getCategoryNumberForDiag(unsigned DiagID); - - /// getCategoryNameFromID - Given a category ID, return the name of the - /// category. - static const char *getCategoryNameFromID(unsigned CategoryID); - - /// \brief Enumeration describing how the the emission of a diagnostic should - /// be treated when it occurs during C++ template argument deduction. - enum SFINAEResponse { - /// \brief The diagnostic should not be reported, but it should cause - /// template argument deduction to fail. - /// - /// The vast majority of errors that occur during template argument - /// deduction fall into this category. - SFINAE_SubstitutionFailure, - - /// \brief The diagnostic should be suppressed entirely. - /// - /// Warnings generally fall into this category. - SFINAE_Suppress, - - /// \brief The diagnostic should be reported. - /// - /// The diagnostic should be reported. Various fatal errors (e.g., - /// template instantiation depth exceeded) fall into this category. - SFINAE_Report - }; - - /// \brief Determines whether the given built-in diagnostic ID is - /// for an error that is suppressed if it occurs during C++ template - /// argument deduction. - /// - /// When an error is suppressed due to SFINAE, the template argument - /// deduction fails but no diagnostic is emitted. Certain classes of - /// errors, such as those errors that involve C++ access control, - /// are not SFINAE errors. - static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID); - - /// getDiagnosticLevel - Based on the way the client configured the Diagnostic + /// \brief 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; + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { + return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this); + } /// 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. /// @c Pos represents the source location associated with the diagnostic, /// which can be an invalid location if no position information is available. - inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID); + inline DiagnosticBuilder Report(SourceLocation Pos, unsigned DiagID); inline DiagnosticBuilder Report(unsigned DiagID); /// \brief Determine whethere there is already a diagnostic in flight. @@ -563,32 +524,34 @@ 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. - diag::Mapping getDiagnosticMappingInfo(diag::kind Diag) const { - return DiagMappingsStack.back().getMapping(Diag); + diag::Mapping getDiagnosticMappingInfo(diag::kind Diag, + DiagState *State) const { + return State->getMapping(Diag); } void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map, - bool isUser) const { + DiagState *State, + bool isUser, bool isPragma) const { if (isUser) Map |= 8; // Set the high bit for user mappings. - DiagMappingsStack.back().setMapping((diag::kind)DiagId, Map); + if (isPragma) Map |= 0x10; // Set the bit for diagnostic pragma mappings. + State->setMapping((diag::kind)DiagId, Map); } - /// getDiagnosticLevel - This is an internal implementation helper used when - /// DiagClass is already known. - Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const; - // This is private state used by DiagnosticBuilder. We put it here instead of // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight // object. This implementation choice means that we can only have one // diagnostic "in flight" at a time, but this seems to be a reasonable // tradeoff to keep these objects small. Assertions verify that only one // diagnostic is in flight at a time. + friend class DiagnosticIDs; friend class DiagnosticBuilder; friend class DiagnosticInfo; - + friend class PartialDiagnostic; + friend class DiagnosticErrorTrap; + /// CurDiagLoc - This is the location of the current diagnostic that is in /// flight. - FullSourceLoc CurDiagLoc; + SourceLocation 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. @@ -640,7 +603,33 @@ private: /// /// \returns true if the diagnostic was emitted, false if it was /// suppressed. - bool ProcessDiag(); + bool ProcessDiag() { + return Diags->ProcessDiag(*this); + } + + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief RAII class that determines when any errors have occurred +/// between the time the instance was created and the time it was +/// queried. +class DiagnosticErrorTrap { + Diagnostic &Diag; + unsigned PrevErrors; + +public: + explicit DiagnosticErrorTrap(Diagnostic &Diag) + : Diag(Diag), PrevErrors(Diag.NumErrors) {} + + /// \brief Determine whether any errors have occurred since this + /// object instance was created. + bool hasErrorOccurred() const { + return Diag.NumErrors > PrevErrors; + } + + // Set to initial state of "no errors occurred". + void reset() { PrevErrors = Diag.NumErrors; } }; //===----------------------------------------------------------------------===// @@ -667,6 +656,11 @@ class DiagnosticBuilder { explicit DiagnosticBuilder(Diagnostic *diagObj) : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {} + friend class PartialDiagnostic; + +protected: + void FlushCounts(); + public: /// Copy constructor. When copied, this "takes" the diagnostic info from the /// input and neuters it. @@ -703,6 +697,17 @@ public: /// isActive - Determine whether this diagnostic is still active. bool isActive() const { return DiagObj != 0; } + /// \brief Retrieve the active diagnostic ID. + /// + /// \pre \c isActive() + unsigned getDiagID() const { + assert(isActive() && "Diagnostic is inactive"); + return DiagObj->CurDiagID; + } + + /// \brief Clear out the current diagnostic. + void Clear() { DiagObj = 0; } + /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: /// return Diag(...); @@ -816,14 +821,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, /// Report - Issue the message to the client. DiagID is a member of the /// diag::kind enum. This actually returns a new instance of DiagnosticBuilder /// which emits the diagnostics (through ProcessDiag) when it is destroyed. -inline DiagnosticBuilder Diagnostic::Report(FullSourceLoc Loc, unsigned DiagID){ +inline DiagnosticBuilder Diagnostic::Report(SourceLocation Loc, + unsigned DiagID){ assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); CurDiagLoc = Loc; CurDiagID = DiagID; return DiagnosticBuilder(this); } inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) { - return Report(FullSourceLoc(), DiagID); + return Report(SourceLocation(), DiagID); } //===----------------------------------------------------------------------===// @@ -840,7 +846,9 @@ public: const Diagnostic *getDiags() const { return DiagObj; } unsigned getID() const { return DiagObj->CurDiagID; } - const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; } + const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; } + bool hasSourceManager() const { return DiagObj->hasSourceManager(); } + SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } @@ -930,10 +938,11 @@ public: }; /** - * \brief Represents a diagnostic in a form that can be serialized and - * deserialized. + * \brief Represents a diagnostic in a form that can be retained until its + * corresponding source manager is destroyed. */ class StoredDiagnostic { + unsigned ID; Diagnostic::Level Level; FullSourceLoc Loc; std::string Message; @@ -943,12 +952,14 @@ class StoredDiagnostic { public: StoredDiagnostic(); StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info); - StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message); + StoredDiagnostic(Diagnostic::Level Level, unsigned ID, + llvm::StringRef Message); ~StoredDiagnostic(); /// \brief Evaluates true when this object stores a diagnostic. operator bool() const { return Message.size() > 0; } + unsigned getID() const { return ID; } Diagnostic::Level getLevel() const { return Level; } const FullSourceLoc &getLocation() const { return Loc; } llvm::StringRef getMessage() const { return Message; } @@ -964,25 +975,21 @@ public: fixit_iterator fixit_begin() const { return FixIts.begin(); } fixit_iterator fixit_end() const { return FixIts.end(); } unsigned fixit_size() const { return FixIts.size(); } - - /// Serialize - Serialize the given diagnostic (with its diagnostic - /// level) to the given stream. Serialization is a lossy operation, - /// since the specific diagnostic ID and any macro-instantiation - /// information is lost. - void Serialize(llvm::raw_ostream &OS) const; - - /// Deserialize - Deserialize the first diagnostic within the memory - /// [Memory, MemoryEnd), producing a new diagnostic builder describing the - /// deserialized diagnostic. If the memory does not contain a - /// diagnostic, returns a diagnostic builder with no diagnostic ID. - static StoredDiagnostic Deserialize(FileManager &FM, SourceManager &SM, - const char *&Memory, const char *MemoryEnd); }; /// DiagnosticClient - This is an abstract interface implemented by clients of /// the front-end, which formats and prints fully processed diagnostics. class DiagnosticClient { +protected: + unsigned NumWarnings; // Number of warnings reported + unsigned NumErrors; // Number of errors reported + public: + DiagnosticClient() : NumWarnings(0), NumErrors(0) { } + + unsigned getNumErrors() const { return NumErrors; } + unsigned getNumWarnings() const { return NumWarnings; } + virtual ~DiagnosticClient(); /// BeginSourceFile - Callback to inform the diagnostic client that processing @@ -1012,8 +1019,11 @@ public: /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or /// capturing it to a log as needed. + /// + /// Default implementation just keeps track of the total number of warnings + /// and errors. virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) = 0; + const DiagnosticInfo &Info); }; } // end namespace clang diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td index fabf9ebb4498..be510ed844e1 100644 --- a/include/clang/Basic/Diagnostic.td +++ b/include/clang/Basic/Diagnostic.td @@ -56,6 +56,7 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> { string Text = text; DiagClass Class = DC; bit SFINAE = 1; + bit AccessControl = 0; DiagMapping DefaultMapping = defaultmapping; DiagGroup Group; string CategoryName = ""; @@ -74,6 +75,7 @@ class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; } class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; } class NoSFINAE { bit SFINAE = 0; } +class AccessControl { bit AccessControl = 1; } // Definitions for Diagnostics. include "DiagnosticASTKinds.td" diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index d755d99e6be5..7d45bc58463c 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -56,6 +56,8 @@ def note_odr_number_of_bases : Note< "class has %0 base %plural{1:class|:classes}0">; def note_odr_enumerator : Note<"enumerator %0 with value %1 here">; def note_odr_missing_enumerator : Note<"no corresponding enumerator here">; + +// Importing Objective-C ASTs def err_odr_ivar_type_inconsistent : Error< "instance variable %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; @@ -80,5 +82,32 @@ def note_odr_objc_method_here : Note< def err_odr_objc_property_type_inconsistent : Error< "property %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; +def err_odr_objc_property_impl_kind_inconsistent : Error< + "property %0 is implemented with %select{@synthesize|@dynamic}1 in one " + "translation but %select{@dynamic|@synthesize}1 in another translation unit">; +def note_odr_objc_property_impl_kind : Note< + "property %0 is implemented with %select{@synthesize|@dynamic}1 here">; +def err_odr_objc_synthesize_ivar_inconsistent : Error< + "property %0 is synthesized to different ivars in different translation " + "units (%1 vs. %2)">; +def note_odr_objc_synthesize_ivar_here : Note< + "property is synthesized to ivar %0 here">; + +// Importing C++ ASTs +def err_odr_different_num_template_parameters : Error< + "template parameter lists have a different number of parameters (%0 vs %1)">; +def note_odr_template_parameter_list : Note< + "template parameter list also declared here">; +def err_odr_different_template_parameter_kind : Error< + "template parameter has different kinds in different translation units">; +def note_odr_template_parameter_here : Note< + "template parameter declared here">; +def err_odr_parameter_pack_non_pack : Error< + "parameter kind mismatch; parameter is %select{not a|a}0 parameter pack">; +def note_odr_parameter_pack_non_pack : Note< + "%select{parameter|parameter pack}0 declared here">; +def err_odr_non_type_parameter_type_inconsistent : Error< + "non-type template parameter declared with incompatible types in different " + "translation units (%0 vs. %1)">; def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">; } diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 98ea9d4bd6d9..85c64c5cef65 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -44,9 +44,12 @@ def err_expected_colon_after_setter_name : Error< def ext_no_declarators : ExtWarn<"declaration does not declare anything">, InGroup<MissingDeclarations>; def err_param_redefinition : Error<"redefinition of parameter %0">; +def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">; def err_invalid_storage_class_in_func_decl : Error< "invalid storage class specifier in function declarator">; def err_expected_namespace_name : Error<"expected namespace name">; +def ext_variadic_templates : ExtWarn< + "variadic templates are a C++0x extension">, InGroup<CXX0x>; // Sema && Lex def ext_longlong : Extension< diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 34cd6004edee..ef1c9e7d8b9a 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -11,11 +11,15 @@ let Component = "Driver" in { def err_drv_no_such_file : Error<"no such file or directory: '%0'">; def err_drv_unsupported_opt : Error<"unsupported option '%0'">; +def err_drv_unsupported_option_argument : Error< + "unsupported argument '%1' to 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_stdlib_name : Error< + "invalid library name in argument '%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< @@ -49,6 +53,8 @@ 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_clang_unsupported_per_platform : Error< + "the clang compiler does not support '%0' on this platform">; def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error< "the clang compiler does not support '%0' for C++ on Darwin/i386">; def err_drv_command_failed : Error< @@ -71,6 +77,10 @@ def err_drv_cc_print_options_failure : Error< def err_drv_preamble_format : Error< "incorrect format for -preamble-bytes=N,END">; +def warn_c_kext : Warning< + "ignoring -fapple-kext which is valid for c++ and objective-c++ only">; +def warn_drv_unsupported_option_argument : Warning< + "ignoring unsupported argument '%1' to option '%0'">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; def warn_drv_preprocessed_input_file_unused : Warning< @@ -91,8 +101,6 @@ def warn_drv_assuming_mfloat_abi_is : Warning< "unknown platform, assuming -mfloat-abi=%0">; def warn_ignoring_ftabstop_value : Warning< "ignoring invalid -ftabstop value '%0', using default value %1">; -def warn_drv_missing_resource_library : Warning< - "missing resource library '%0', link may fail">; def warn_drv_conflicting_deployment_targets : Warning< "conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">; def warn_drv_treating_input_as_cxx : Warning< @@ -100,5 +108,7 @@ def warn_drv_treating_input_as_cxx : Warning< InGroup<Deprecated>; def warn_drv_objc_gc_unsupported : Warning< "Objective-C garbage collection is not supported on this platform, ignoring '%0'">; +def warn_drv_pch_not_first_include : Warning< + "precompiled header '%0' was ignored because '%1' is not first '-include'">; } diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 7c74bf458e58..5f9f4a7f3927 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -18,7 +18,7 @@ def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; // Error generated by the backend. def err_fe_inline_asm : Error<"%0">, CatInlineAsm; -def note_fe_inline_asm_here : Note<"instantated into assembly here">; +def note_fe_inline_asm_here : Note<"instantiated into assembly here">; @@ -69,12 +69,16 @@ def err_fe_pch_file_modified : Error< DefaultFatal; def err_fe_unable_to_open_output : Error< "unable to open output file '%0': '%1'">; +def err_fe_unable_to_rename_temp : Error< + "unable to rename temporary '%0' to output file '%1': '%2'">; def err_fe_unable_to_open_logfile : Error< "unable to open logfile file '%0': '%1'">; def err_fe_pth_file_has_no_source_header : Error< "PTH file '%0' does not designate an original source header file for -include-pth">; def warn_fe_macro_contains_embedded_newline : Warning< "macro '%0' contains embedded newline, text after the newline is ignored.">; +def warn_fe_cc_print_header_failure : Warning< + "unable to open CC_PRINT_HEADERS file: %0 (using stderr)">; def err_verify_missing_start : Error< "cannot find start ('{{') of expected %0">; @@ -83,7 +87,8 @@ def err_verify_missing_end : Error< def err_verify_invalid_content : Error< "invalid expected %0: %1">; def err_verify_inconsistent_diags : Error< - "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: %2">; + "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: " + "%2">; def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; def note_fixit_in_macro : Note< @@ -127,6 +132,12 @@ def warn_pch_nonfragile_abi2 : Error< "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 " "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 " "Objective-C ABI is selected">; +def warn_pch_apple_kext : Error< + "PCH file was compiled %select{with|without}0 support for Apple's kernel " + "extensions ABI but it is currently %select{disabled|enabled}1">; +def warn_pch_objc_auto_properties : Error< + "PCH file was compiled %select{with|without}0 support for auto-synthesized " + "@properties but it is currently %select{disabled|enabled}1">; def warn_pch_no_constant_cfstrings : Error< "Objctive-C NSstring generation support was %select{disabled|enabled}0 " "in PCH file but currently %select{disabled|enabled}1">; @@ -142,6 +153,9 @@ def warn_pch_gnu_keywords : Error< def warn_pch_microsoft_extensions : Error< "Microsoft extensions were %select{disabled|enabled}0 in PCH file but are " "currently %select{disabled|enabled}1">; +def warn_pch_ms_bitfields : Error< + "Microsoft-compatible structure layout was %select{disabled|enabled}0 in " + "PCH file but is currently %select{disabled|enabled}1">; def warn_pch_heinous_extensions : Error< "heinous extensions were %select{disabled|enabled}0 in PCH file but are " "currently %select{disabled|enabled}1">; @@ -154,6 +168,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_cuda : Error< + "CUDA 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">; @@ -163,6 +180,9 @@ def warn_pch_exceptions : Error< def warn_pch_sjlj_exceptions : Error< "sjlj-exceptions were %select{disabled|enabled}0 in PCH file but " "are currently %select{disabled|enabled}1">; +def warn_pch_objc_exceptions : Error< + "Objective-C exceptions were %select{disabled|enabled}0 in PCH file but " + "are currently %select{disabled|enabled}1">; def warn_pch_objc_runtime : Error< "PCH file was compiled with the %select{NeXT|GNU}0 runtime but the " "%select{NeXT|GNU}1 runtime is selected">; @@ -241,6 +261,9 @@ def warn_pch_char_signed : Error< def warn_pch_short_wchar : Error< "-fshort-wchar was %select{disabled|enabled}0 in the PCH file but " "is currently %select{disabled|enabled}1">; +def warn_pch_short_enums : Error< + "-fshort-enums was %select{disabled|enabled}0 in the PCH file but " + "is currently %select{disabled|enabled}1">; def err_not_a_pch_file : Error< "'%0' does not appear to be a precompiled header file">, DefaultFatal; @@ -250,4 +273,7 @@ def warn_unknown_warning_option : Warning< def warn_unknown_warning_specifier : Warning< "unknown %0 warning specifier: '%1'">, InGroup<DiagGroup<"unknown-warning-option"> >; + +def warn_unkwown_analyzer_checker : Warning< + "no analyzer checkers are associated with '%0'">; } diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index d4b7f1f55743..d4377c9a0b07 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -35,9 +35,12 @@ def : DiagGroup<"declaration-after-statement">; def GNUDesignator : DiagGroup<"gnu-designator">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; +def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">; def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >, DiagCategory<"Deprecations">; +def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; + def : DiagGroup<"disabled-optimization">; def : DiagGroup<"discard-qual">; def : DiagGroup<"div-by-zero">; @@ -54,6 +57,7 @@ def : DiagGroup<"effc++">; def FourByteMultiChar : DiagGroup<"four-char-constants">; def GlobalConstructors : DiagGroup<"global-constructors">; def : DiagGroup<"idiomatic-parentheses">; +def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; def : DiagGroup<"import">; def : DiagGroup<"init-self">; @@ -74,17 +78,19 @@ def : DiagGroup<"newline-eof">; def LongLong : DiagGroup<"long-long">; def MismatchedTags : DiagGroup<"mismatched-tags">; def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def NullDereference : DiagGroup<"null-dereference">; def InitializerOverrides : DiagGroup<"initializer-overrides">; def NonNull : DiagGroup<"nonnull">; def : DiagGroup<"nonportable-cfstrings">; -def : DiagGroup<"non-virtual-dtor">; +def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; def : DiagGroup<"overflow">; def OverlengthStrings : DiagGroup<"overlength-strings">; -def : DiagGroup<"overloaded-virtual">; -def : DiagGroup<"packed">; +def OverloadedVirtual : DiagGroup<"overloaded-virtual">; +def Packed : DiagGroup<"packed">; +def Padded : DiagGroup<"padded">; def PointerArith : DiagGroup<"pointer-arith">; def PoundWarning : DiagGroup<"#warnings">, DiagCategory<"#warning Directive">; @@ -92,6 +98,7 @@ def : DiagGroup<"pointer-to-int-cast">; def : DiagGroup<"redundant-decls">; def ReturnType : DiagGroup<"return-type">; def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">; +def SelfAssignment : DiagGroup<"self-assign">; def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; def : DiagGroup<"sequence-point">; def Shadow : DiagGroup<"shadow">; @@ -101,6 +108,7 @@ def SignCompare : DiagGroup<"sign-compare">; def : DiagGroup<"stack-protector">; def : DiagGroup<"switch-default">; def : DiagGroup<"synth">; +def TautologicalCompare : DiagGroup<"tautological-compare">; // Preprocessor warnings. def : DiagGroup<"builtin-macro-redefined">; @@ -140,9 +148,14 @@ def UnusedLabel : DiagGroup<"unused-label">; def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedValue : DiagGroup<"unused-value">; def UnusedVariable : DiagGroup<"unused-variable">; +def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">; def Reorder : DiagGroup<"reorder">; def UndeclaredSelector : DiagGroup<"undeclared-selector">; +def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; +def CustomAtomic : DiagGroup<"custom-atomic-properties">; +def AtomicProperties : DiagGroup<"atomic-properties", + [ImplicitAtomic, CustomAtomic]>; def Selector : DiagGroup<"selector">; def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">; def Protocol : DiagGroup<"protocol">; @@ -154,17 +167,27 @@ def VLA : DiagGroup<"vla">; def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def : DiagGroup<"write-strings">; def CharSubscript : DiagGroup<"char-subscripts">; +def LargeByValueCopy : DiagGroup<"large-by-value-copy">; // Aggregation warning settings. // -Widiomatic-parentheses contains warnings about 'idiomatic' // missing parentheses; it is off by default. -def Parentheses : DiagGroup<"parentheses", [DiagGroup<"idiomatic-parentheses">]>; +def Parentheses : DiagGroup<"parentheses", + [LogicalOpParentheses, + DiagGroup<"idiomatic-parentheses">]>; -// -Wconversion has its own warnings, but we split this one out for -// legacy reasons. +// -Wconversion has its own warnings, but we split a few out for +// legacy reasons: +// - some people want just 64-to-32 warnings +// - conversion warnings with constant sources are on by default +// - conversion warnings for literals are on by default +// - bool-to-pointer conversion warnings are on by default def Conversion : DiagGroup<"conversion", - [DiagGroup<"shorten-64-to-32">, BoolConversions]>, + [DiagGroup<"shorten-64-to-32">, + DiagGroup<"constant-conversion">, + DiagGroup<"literal-conversion">, + BoolConversions]>, DiagCategory<"Value Conversion Issue">; def Unused : DiagGroup<"unused", @@ -202,13 +225,15 @@ def Most : DiagGroup<"most", [ MultiChar, Reorder, ReturnType, + SelfAssignment, Switch, Trigraphs, Uninitialized, UnknownPragmas, Unused, VectorConversions, - VolatileRegisterVar + VolatileRegisterVar, + OverloadedVirtual ]>; // -Wall is -Wmost -Wparentheses @@ -224,5 +249,12 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment def NonGCC : DiagGroup<"non-gcc", [SignCompare, Conversion, LiteralRange]>; +// A warning group for warnings about using C++0x features as extensions in +// earlier C++ versions. +def CXX0x : DiagGroup<"c++0x-extensions">; + // A warning group for warnings about GCC extensions. def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>; + +// A warning group for warnings about Microsoft extensions. +def Microsoft : DiagGroup<"microsoft">; diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h new file mode 100644 index 000000000000..b46380569851 --- /dev/null +++ b/include/clang/Basic/DiagnosticIDs.h @@ -0,0 +1,212 @@ +//===--- DiagnosticIDs.h - Diagnostic IDs Handling --------------*- 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 Diagnostic IDs-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICIDS_H +#define LLVM_CLANG_DIAGNOSTICIDS_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + class Diagnostic; + class SourceLocation; + + // Import the diagnostic enums themselves. + namespace diag { + // Start position for diagnostics. + enum { + DIAG_START_DRIVER = 300, + DIAG_START_FRONTEND = DIAG_START_DRIVER + 100, + DIAG_START_LEX = DIAG_START_FRONTEND + 120, + DIAG_START_PARSE = DIAG_START_LEX + 300, + DIAG_START_AST = DIAG_START_PARSE + 300, + DIAG_START_SEMA = DIAG_START_AST + 100, + DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000, + DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 + }; + + class CustomDiagInfo; + + /// diag::kind - All of the diagnostics that can be emitted by the frontend. + typedef unsigned kind; + + // Get typedefs for common diagnostics. + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, +#include "clang/Basic/DiagnosticCommonKinds.inc" + 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 + /// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this + /// one). + enum Mapping { + // NOTE: 0 means "uncomputed". + MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. + 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, + /// Map this diagnostic to "error", but make it immune to -Wfatal-errors. + /// This happens for -Wno-fatal-errors=foo. + MAP_ERROR_NO_WFATAL = 6 + }; + } + +/// \brief Used for handling and querying diagnostic IDs. Can be used and shared +/// by multiple Diagnostics for multiple translation units. +class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> { +public: + /// Level - The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored, Note, Warning, Error, Fatal + }; + +private: + /// CustomDiagInfo - Information for uniquing and looking up custom diags. + diag::CustomDiagInfo *CustomDiagInfo; + +public: + DiagnosticIDs(); + ~DiagnosticIDs(); + + /// 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, llvm::StringRef Message); + + //===--------------------------------------------------------------------===// + // Diagnostic classification and reporting interfaces. + // + + /// 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 + /// call on NOTEs. + static bool isBuiltinWarningOrExtension(unsigned DiagID); + + /// \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) { + bool ignored; + return isBuiltinExtensionDiag(DiagID, ignored); + } + + /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic + /// ID is for an extension of some sort. This also returns EnabledByDefault, + /// which is set to indicate whether the diagnostic is ignored by default (in + /// which case -pedantic enables it) or treated as a warning/error by default. + /// + static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); + + + /// 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. + static const char *getWarningOptionForDiag(unsigned DiagID); + + /// getWarningOptionForDiag - Return the category number that a specified + /// DiagID belongs to, or 0 if no category. + static unsigned getCategoryNumberForDiag(unsigned DiagID); + + /// getCategoryNameFromID - Given a category ID, return the name of the + /// category. + static const char *getCategoryNameFromID(unsigned CategoryID); + + /// \brief Enumeration describing how the the emission of a diagnostic should + /// be treated when it occurs during C++ template argument deduction. + enum SFINAEResponse { + /// \brief The diagnostic should not be reported, but it should cause + /// template argument deduction to fail. + /// + /// The vast majority of errors that occur during template argument + /// deduction fall into this category. + SFINAE_SubstitutionFailure, + + /// \brief The diagnostic should be suppressed entirely. + /// + /// Warnings generally fall into this category. + SFINAE_Suppress, + + /// \brief The diagnostic should be reported. + /// + /// The diagnostic should be reported. Various fatal errors (e.g., + /// template instantiation depth exceeded) fall into this category. + SFINAE_Report, + + /// \brief The diagnostic is an access-control diagnostic, which will be + /// substitution failures in some contexts and reported in others. + SFINAE_AccessControl + }; + + /// \brief Determines whether the given built-in diagnostic ID is + /// for an error that is suppressed if it occurs during C++ template + /// argument deduction. + /// + /// When an error is suppressed due to SFINAE, the template argument + /// deduction fails but no diagnostic is emitted. Certain classes of + /// errors, such as those errors that involve C++ access control, + /// are not SFINAE errors. + static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID); + +private: + /// 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. + bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map, + SourceLocation Loc, Diagnostic &Diag) const; + + /// \brief Based on the way the client configured the Diagnostic + /// object, classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticClient. + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, + const Diagnostic &Diag) const; + + /// getDiagnosticLevel - This is an internal implementation helper used when + /// DiagClass is already known. + DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, + unsigned DiagClass, + SourceLocation Loc, + const Diagnostic &Diag) const; + + /// ProcessDiag - This is the method used to report a diagnostic that is + /// finally fully formed. + /// + /// \returns true if the diagnostic was emitted, false if it was + /// suppressed. + bool ProcessDiag(Diagnostic &Diag) const; + + friend class Diagnostic; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index dcb05c8fcd45..6d1d9b6ad869 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -45,8 +45,8 @@ def charize_microsoft_ext : Extension<"@# is a microsoft extension">; def ext_token_used : Extension<"extension used">; -def err_unterminated_string : Error<"missing terminating '\"' character">; -def err_unterminated_char : Error<"missing terminating ' character">; +def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">; +def warn_unterminated_char : ExtWarn<"missing terminating ' character">; def err_empty_character : Error<"empty character constant">; def err_unterminated_block_comment : Error<"unterminated /* comment">; def err_invalid_character_to_charify : Error< @@ -98,6 +98,10 @@ def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">; def ext_string_too_long : Extension<"string literal of length %0 exceeds " "maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to " "support">, InGroup<OverlengthStrings>; +def warn_ucn_escape_too_large : ExtWarn< + "character unicode escape sequence too long for its type">; +def warn_ucn_not_valid_in_c89 : ExtWarn< + "unicode escape sequences are only valid in C99 or C++">; //===----------------------------------------------------------------------===// // PTH Diagnostics @@ -240,11 +244,11 @@ def warn_pragma_ignored : Warning<"unknown pragma ignored">, InGroup<UnknownPragmas>, DefaultIgnore; def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, InGroup<UnknownPragmas>; -def ext_stdc_pragma_syntax : +def ext_on_off_switch_syntax : ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">, InGroup<UnknownPragmas>; -def ext_stdc_pragma_syntax_eom : - ExtWarn<"expected end of macro in STDC pragma">, +def ext_pragma_syntax_eom : + ExtWarn<"expected end of macro in pragma">, InGroup<UnknownPragmas>; def warn_stdc_fenv_access_not_supported : Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 646fd0d1bfb6..9d7ec9d45447 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -55,11 +55,15 @@ def ext_c99_compound_literal : Extension< def ext_enumerator_list_comma : Extension< "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific " "feature">; +def err_enumerator_list_missing_comma : Error< + "missing ',' between enumerators">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup<GNU>; def ext_gnu_address_of_label : Extension< "use of GNU address-of-label extension">, InGroup<GNU>; +def ext_gnu_local_label : Extension< + "use of GNU locally declared label extension">, InGroup<GNU>; def ext_gnu_statement_expr : Extension< "use of GNU statement expression extension">, InGroup<GNU>; def ext_gnu_conditional_expr : Extension< @@ -93,6 +97,7 @@ def err_expected_lsquare : Error<"expected '['">; def err_expected_rsquare : Error<"expected ']'">; def err_expected_rbrace : Error<"expected '}'">; def err_expected_greater : Error<"expected '>'">; +def err_expected_ggg : Error<"expected '>>>'">; def err_expected_semi_declaration : Error< "expected ';' at end of declaration">; def err_expected_semi_decl_list : Error< @@ -110,6 +115,8 @@ def err_expected_fn_body : Error< def err_expected_method_body : Error<"expected method body">; def err_invalid_token_after_toplevel_declarator : Error< "expected ';' after top level declarator">; +def err_invalid_equalequal_after_declarator : Error< + "invalid '==' at end of declaration; did you mean '='?">; def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; def err_expected_lparen_after_id : Error<"expected '(' after %0">; @@ -122,6 +129,8 @@ def err_expected_while : Error<"expected 'while' in do/while loop">; def err_expected_semi_after : Error<"expected ';' after %0">; def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; def err_expected_semi_after_expr : Error<"expected ';' after expression">; +def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; + def err_expected_semi_after_method_proto : Error< "expected ';' after method prototype">; def err_expected_semi_after_namespace_name : Error< @@ -139,6 +148,8 @@ def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; def err_expected_colon_after : Error<"expected ':' after %0">; def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; +def err_address_of_label_outside_fn : Error< + "use of address-of-label extension outside of a function body">; def err_expected_string_literal : Error<"expected string literal">; def err_expected_asm_operand : Error< "expected string literal or '[' for asm operand">, CatInlineAsm; @@ -152,10 +163,12 @@ def err_invalid_reference_qualifier_application : Error< "'%0' qualifier may not be applied to a reference">; def err_illegal_decl_reference_to_reference : Error< "%0 declared as a reference to a reference">; -def err_rvalue_reference : Error< - "rvalue references are only allowed in C++0x">; -def ext_inline_namespace : Extension< - "inline namespaces are a C++0x feature">; +def ext_rvalue_reference : ExtWarn< + "rvalue references are a C++0x extension">, InGroup<CXX0x>; +def ext_ref_qualifier : ExtWarn< + "reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>; +def ext_inline_namespace : ExtWarn< + "inline namespaces are a C++0x feature">, InGroup<CXX0x>; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; @@ -194,10 +207,16 @@ def err_unknown_typename : Error< "unknown type name %0">; def err_use_of_tag_name_without_tag : Error< "must use '%1' tag to refer to type %0%select{| in this scope}2">; +def err_templated_using_directive : Error< + "cannot template a using directive">; +def err_templated_using_declaration : Error< + "cannot template a using declaration">; def err_expected_ident_in_using : Error< "expected an identifier in using directive">; def err_unexected_colon_in_nested_name_spec : Error< "unexpected ':' in nested name specifier">; +def err_bool_redeclaration : Error< + "redeclaration of C++ built-in type 'bool'">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< @@ -214,13 +233,17 @@ def err_illegal_super_cast : Error< def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; -def err_objc_expected_equal : Error< - "setter/getter expects '=' followed by name">; +def err_objc_expected_equal_for_getter : Error< + "expected '=' for Objective-C getter">; +def err_objc_expected_equal_for_setter : Error< + "expected '=' for Objective-C setter">; +def err_objc_expected_selector_for_getter_setter : Error< + "expected selector for Objective-C %select{setter|getter}0">; def err_objc_property_requires_field_name : Error< "property requires fields to be named">; def err_objc_property_bitfield : Error<"property name cannot be a bitfield">; def err_objc_expected_property_attr : Error<"unknown property attribute %0">; -def err_objc_propertoes_require_objc2 : Error< +def err_objc_properties_require_objc2 : Error< "properties are an Objective-C 2 feature">; def err_objc_unexpected_attr : Error< "prefix attribute must be followed by an interface or protocol">; @@ -283,8 +306,6 @@ def err_default_arg_unparsed : Error< def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading -def err_operator_missing_type_specifier : Error< - "missing type specifier after 'operator'">; def err_operator_string_not_empty : Error< "string literal after 'operator' must be '\"\"'">; @@ -334,6 +355,10 @@ def err_enum_template : Error<"enumeration cannot be a template">; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; +def warn_static_inline_explicit_inst_ignored : Warning< + "ignoring '%select{static|inline}0' keyword on explicit template " + "instantiation">; + // Constructor template diagnostics. def err_out_of_line_constructor_template_id : Error< "out-of-line constructor for %0 cannot have template arguments">; @@ -356,18 +381,42 @@ def err_expected_type_name_after_typename : Error< def err_explicit_spec_non_template : Error< "explicit %select{specialization|instantiation}0 of non-template " "%select{class|struct|union}1 %2">; - -def err_variadic_templates : Error< - "variadic templates are only allowed in C++0x">; def err_default_template_template_parameter_not_template : Error< "default template argument for a template template parameter must be a class " "template">; +def err_ctor_init_missing_comma : Error< + "missing ',' between base or member initializers">; + // C++ declarations def err_friend_decl_defines_class : Error< "cannot define a type in a friend declaration">; - + +def warn_deleted_function_accepted_as_extension: ExtWarn< + "deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>; + +// C++0x override control +def ext_override_control_keyword : Extension< + "'%0' keyword accepted as a C++0x extension">, InGroup<CXX0x>; +def ext_override_inline: Extension< + "'%0' keyword only allowed in declarations, allowed as an extension">; + +def err_duplicate_virt_specifier : Error< + "class member already marked '%0'">; +def err_duplicate_class_virt_specifier : Error< + "class already marked '%0'">; + +def err_scoped_enum_missing_identifier : Error< + "scoped enumeration requires a name">; + +def err_expected_parameter_pack : Error< + "expected the name of a parameter pack">; +def err_paren_sizeof_parameter_pack : Error< + "missing parentheses around the size of parameter pack %0">; +def err_sizeof_parameter_pack : Error< + "expected parenthesized parameter pack name in 'sizeof...' expression">; + // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< @@ -398,5 +447,17 @@ def warn_pragma_unused_expected_var : Warning< def warn_pragma_unused_expected_punc : Warning< "expected ')' or ',' in '#pragma unused'">; +// OpenCL Section 6.8.g +def err_not_opencl_storage_class_specifier : Error< + "OpenCL does not support the '%0' storage class specifier">; + +// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) +def warn_pragma_expected_colon : Warning< + "missing ':' after %0 - ignoring">; +def warn_pragma_expected_enable_disable : Warning< + "expected 'enable' or 'disable' - ignoring">; +def warn_pragma_unknown_extension : Warning< + "unknown OpenCL extension %0 - ignoring">; + } // end of Parse Issue category. } // end of Parser diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a25b2a341fc5..2e7f274b8ed5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -46,14 +46,18 @@ def err_vla_decl_has_static_storage : Error< "variable length array declaration can not have 'static' storage duration">; def err_vla_decl_has_extern_linkage : Error< "variable length array declaration can not have 'extern' linkage">; - + // C99 variably modified types def err_variably_modified_template_arg : Error< "variably modified type %0 cannot be used as a template argument">; def err_variably_modified_nontype_template_param : Error< "non-type template parameter of variably modified type %0">; +def err_variably_modified_new_type : Error< + "'new' cannot allocate object of variably modified type %0">; // C99 Designated Initializers +def ext_designated_init : Extension< + "designated initializers are a C99 feature, accepted in C++ as an extension">; def err_array_designator_negative : Error< "array designator value '%0' is negative">; def err_array_designator_empty_range : Error< @@ -93,6 +97,8 @@ def ext_anon_param_requires_type_specifier : Extension< "type specifier required for unnamed parameter, defaults to int">; def err_bad_variable_name : Error< "'%0' cannot be the name of a variable or data member">; +def err_bad_parameter_name : Error< + "'%0' cannot be the name of a parameter">; def err_parameter_name_omitted : Error<"parameter name omitted">; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup<UnusedParameter>, DefaultIgnore; @@ -106,7 +112,16 @@ def warn_unused_function : Warning<"unused function %0">, InGroup<UnusedFunction>, DefaultIgnore; def warn_unused_member_function : Warning<"unused member function %0">, InGroup<UnusedMemberFunction>, DefaultIgnore; - +def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, + InGroup<UsedButMarkedUnused>, DefaultIgnore; + +def warn_parameter_size: Warning< + "%0 is a large (%1 bytes) pass-by-value argument; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; +def warn_return_value_size: Warning< + "return value of %0 is a large (%1 bytes) pass-by-value object; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; + def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup<ImplicitFunctionDeclare>, DefaultIgnore; @@ -147,6 +162,17 @@ def err_using_decl_nested_name_specifier_is_current_class : Error< "using declaration refers to its own class">; def err_using_decl_nested_name_specifier_is_not_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; +def err_using_decl_constructor_not_in_direct_base : Error< + "%0 is not a direct base of %1, can not inherit constructors">; +def err_using_decl_constructor_conflict : Error< + "can not inherit constructor, already inherited constructor with " + "the same signature">; +def note_using_decl_constructor_conflict_current_ctor : Note< + "conflicting constructor">; +def note_using_decl_constructor_conflict_previous_ctor : Note< + "previous constructor">; +def note_using_decl_constructor_conflict_previous_using : Note< + "previously inherited here">; 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< @@ -210,10 +236,12 @@ def note_please_include_header : Note< "please include the header <%0> or explicitly provide a " "declaration for '%1'">; 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_implicit_decl_requires_stdio : Warning< + "declaration of built-in function '%0' requires inclusion of the header " + "<stdio.h>">; +def warn_implicit_decl_requires_setjmp : Warning< + "declaration of built-in function '%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">; @@ -227,6 +255,7 @@ 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_template_decl : Error<"'main' cannot be a template">; def err_main_returns_nonint : Error<"'main' must return 'int'">; def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " "must be 0, 2, or 3">; @@ -261,8 +290,8 @@ 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 warn_pragma_unused_expected_var_arg : Warning< + "only variables can be arguments to '#pragma unused'">; def err_unsupported_pragma_weak : Error< "using '#pragma weak' to refer to an undeclared identifier is not yet supported">; @@ -314,16 +343,23 @@ def err_conflicting_ivar_name : Error< "conflicting instance variable names: %0 vs %1">; def err_inconsistant_ivar_count : Error< "inconsistent number of instance variables specified">; -def warn_incomplete_impl : Warning<"incomplete implementation">; +def warn_incomplete_impl : Warning<"incomplete implementation">, + InGroup<DiagGroup<"incomplete-implementation">>; def note_undef_method_impl : Note<"method definition for %0 not found">; def note_required_for_protocol_at : Note<"required for direct or indirect protocol %0">; def warn_conflicting_ret_types : Warning< "conflicting return type in implementation of %0: %1 vs %2">; +def warn_non_covariant_ret_types : Warning< + "conflicting return type in implementation of %0: %1 vs %2">, + InGroup<DiagGroup<"method-signatures">>, DefaultIgnore; def warn_conflicting_param_types : Warning< "conflicting parameter types in implementation of %0: %1 vs %2">; +def warn_non_contravariant_param_types : Warning< + "conflicting parameter types in implementation of %0: %1 vs %2">, + InGroup<DiagGroup<"method-signatures">>, DefaultIgnore; def warn_conflicting_variadic :Warning< "conflicting variadic declaration of method and its implementation">; @@ -337,6 +373,7 @@ def warn_strict_multiple_method_decl : Warning< def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; def note_declared_at : Note<"declared here">; +def note_method_declared_at : Note<"method declared here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_missing_atend : Warning<"'@end' is missing in implementation context">; @@ -361,9 +398,17 @@ def warn_objc_property_copy_missing_on_block : Warning< def warn_atomic_property_rule : Warning< "writable atomic property %0 cannot pair a synthesized setter/getter " "with a user defined setter/getter">; +def warn_default_atomic_custom_getter_setter : Warning< + "atomic by default property %0 has a user defined %select{getter|setter}1 " + "(property should be marked 'atomic' if this is intended)">, + InGroup<CustomAtomic>, DefaultIgnore; def err_use_continuation_class : Error< - "illegal declaration of property in continuation class %0" - ": attribute must be readwrite, while its primary must be readonly">; + "illegal redeclaration of property in continuation class %0" + " (attribute must be 'readwrite', while its primary must be 'readonly')">; +def err_use_continuation_class_redeclaration_readwrite : Error< + "illegal redeclaration of 'readwrite' property in continuation class %0" + " (perhaps you intended this to be a 'readwrite' redeclaration of a " + "'readonly' public property?)">; def err_continuation_class : Error<"continuation class has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< @@ -400,7 +445,7 @@ def error_ivar_in_superclass_use : Error< def error_weak_property : Error< "existing ivar %1 for __weak property %0 must be __weak">; def error_strong_property : Error< - "existing ivar %1 for a __strong property %0 must be garbage collectable">; + "property %0 must be declared __weak to match existing ivar %1 with __weak attribute">; def error_dynamic_property_ivar_decl : Error< "dynamic property can not have ivar specification">; def error_duplicate_ivar_use : Error< @@ -411,6 +456,11 @@ def warn_objc_property_attr_mutually_exclusive : Warning< InGroup<ReadOnlySetterAttrs>, DefaultIgnore; def warn_undeclared_selector : Warning< "undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore; +def warn_implicit_atomic_property : Warning< + "property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore; +def warn_auto_implicit_atomic_property : Warning< + "property is assumed atomic when auto-synthesizing the property">, + InGroup<ImplicitAtomic>, DefaultIgnore; def warn_unimplemented_selector: Warning< "unimplemented selector %0">, InGroup<Selector>, DefaultIgnore; def warn_unimplemented_protocol_method : Warning< @@ -442,11 +492,15 @@ def err_introducing_special_friend : Error< "destructor|conversion operator}0 as a friend">; def err_tagless_friend_type_template : Error< "friend type templates must use an elaborated type">; +def err_no_matching_local_friend : Error< + "no matching function found in local scope">; +def err_partial_specialization_friend : Error< + "partial specialization cannot be declared as a friend">; def err_abstract_type_in_decl : Error< "%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">; + "allocating an object of abstract class type %0">; def err_throw_abstract_type : Error< "cannot throw an object of abstract type %0">; def err_array_of_abstract_type : Error<"array of abstract class type %0">; @@ -463,7 +517,7 @@ def err_type_defined_in_param_type : Error< "%0 can not be defined in a parameter type">; def note_pure_virtual_function : Note< - "pure virtual function %0">; + "unimplemented pure virtual method %0 in %1">; def err_deleted_non_function : Error< "only functions can have deleted definitions">; @@ -503,65 +557,70 @@ def warn_missing_exception_specification : Warning< def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; def err_access : Error< - "%1 is a %select{private|protected}0 member of %3">, NoSFINAE; + "%1 is a %select{private|protected}0 member of %3">, AccessControl; def err_access_ctor : Error< - "calling a %select{private|protected}0 constructor of class %2">, NoSFINAE; + "calling a %select{private|protected}0 constructor of class %2">, + AccessControl; def ext_rvalue_to_reference_access_ctor : ExtWarn< "C++98 requires an accessible copy constructor for class %2 when binding " "a reference to a temporary; was %select{private|protected}0">, - NoSFINAE, InGroup<BindToTemporaryCopy>; + AccessControl, InGroup<BindToTemporaryCopy>; def err_access_base : Error< "%select{base class|inherited virtual base class}0 %1 has %select{private|" "protected}3 %select{constructor|copy constructor|copy assignment operator|" - "destructor}2">, NoSFINAE; + "destructor}2">, AccessControl; def err_access_field: Error< "field of type %0 has %select{private|protected}2 %select{constructor|copy " - "constructor|copy assignment operator|destructor}1">, NoSFINAE; + "constructor|copy assignment operator|destructor}1">, AccessControl; def err_access_ctor_field : Error<"field of type %1 has %select{private|protected}2 constructor">, - NoSFINAE; + AccessControl; +def err_access_dtor : Error< + "calling a %select{private|protected}1 destructor of class %0">, + AccessControl; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_vbase : Error<"inherited virtual base class %0 has " "%select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_temp : Error<"temporary of type %0 has %select{private|protected}1 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_exception : Error<"exception object of type %0 has %select{private|protected}1 " - "destructor">, NoSFINAE; + "destructor">, AccessControl; def err_access_dtor_field : Error<"field of type %1 has %select{private|protected}2 destructor">, - NoSFINAE; + AccessControl; def err_access_dtor_var : Error<"variable of type %1 has %select{private|protected}2 destructor">, - NoSFINAE; + AccessControl; def err_access_assign_field : Error<"field of type %1 has %select{private|protected}2 copy assignment" " operator">, - NoSFINAE; + AccessControl; def err_access_assign_base : Error<"base class %0 has %select{private|protected}1 copy assignment" " operator">, - NoSFINAE; + AccessControl; def err_access_copy_field : Error<"field of type %1 has %select{private|protected}2 copy constructor">, - NoSFINAE; + AccessControl; def err_access_copy_base : Error<"base class %0 has %select{private|protected}1 copy constructor">, - NoSFINAE; + AccessControl; def err_access_dtor_ivar : Error<"instance variable of type %0 has %select{private|protected}1 " "destructor">, - NoSFINAE; + AccessControl; def note_previous_access_declaration : Note< "previously declared '%1' here">; def err_access_outside_class : Error< - "access to %select{private|protected}0 member outside any class context">; + "access to %select{private|protected}0 member outside any class context">, + AccessControl; def note_access_natural : Note< "%select{|implicitly }1declared %select{private|protected}0 here">; def note_access_constrained_by_path : Note< @@ -604,6 +663,10 @@ def err_virtual_non_function : Error< "'virtual' can only appear on non-static member functions">; def err_virtual_out_of_class : Error< "'virtual' can only be specified inside the class definition">; +def err_virtual_member_function_template : Error< + "'virtual' can not be specified on member function templates">; +def err_static_overrides_virtual : Error< + "'static' member function %0 overrides a virtual function in a base class">; def err_explicit_non_function : Error< "'explicit' can only appear on non-static member functions">; def err_explicit_out_of_class : Error< @@ -619,7 +682,7 @@ def err_not_integral_type_bitfield : Error< def err_not_integral_type_anon_bitfield : Error< "anonymous bit-field has non-integral type %0">; def err_member_initialization : Error< - "%0 can only be initialized if it is a static const integral data member">; + "fields can only be initialized in constructors">; def err_member_function_initialization : Error< "initializer on function does not look like a pure-specifier">; def err_non_virtual_pure : Error< @@ -652,6 +715,10 @@ def note_nontrivial_has_nontrivial : Note< def note_nontrivial_user_defined : Note< "because type %0 has a user-declared %select{constructor|copy constructor|" "copy assignment operator|destructor}1">; +def err_static_data_member_not_allowed_in_union_or_anon_struct : Error< + "static data member %0 not allowed in %select{anonymous struct|union}1">; +def err_union_member_of_reference_type : Error< + "union member %0 has reference type %1">; def err_different_return_type_for_overriding_virtual_function : Error< "virtual function %0 has a different return type (%1) than the " @@ -661,7 +728,7 @@ def note_overridden_virtual_function : Note< def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " - "%select{private|protected}2 base class of %0">, NoSFINAE; + "%select{private|protected}2 base class of %0">, AccessControl; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " @@ -684,6 +751,9 @@ def err_covariant_return_type_class_type_more_qualified : Error< def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; +def err_ref_qualifier_constructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; + def err_constructor_return_type : Error< "constructor cannot have a return type">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">; @@ -694,6 +764,8 @@ def warn_no_constructor_for_refconst : Warning< "initialize its non-modifiable members">; def note_refconst_member_not_initialized : Note< "%select{const|reference}0 member %1 will never be initialized">; +def ext_ms_explicit_constructor_call : ExtWarn< + "explicit constructor calls are a Microsoft extension">, InGroup<Microsoft>; // C++ destructors def err_destructor_not_member : Error< @@ -701,6 +773,8 @@ def err_destructor_not_member : Error< def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; +def err_ref_qualifier_destructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; def err_destructor_redeclared : Error<"destructor cannot be redeclared">; def err_destructor_with_params : Error<"destructor cannot have any parameters">; @@ -721,7 +795,8 @@ def err_init_conversion_failed : Error< "base class|a vector element}0 of type %1 with an %select{rvalue|lvalue}2 of " "type %3">; -def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">; +def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind " + "to lvalue of type %1">; 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 " @@ -745,6 +820,10 @@ def err_reference_bind_init_list : Error< def err_init_list_bad_dest_type : Error< "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " "list">; +def err_member_function_call_bad_cvr : Error<"member function %0 not viable: " + "'this' argument has type %1, but function is not marked " + "%select{const|restrict|const or restrict|volatile|const or volatile|" + "volatile or restrict|const, volatile, or restrict}2">; def err_reference_init_drops_quals : Error< "initialization of reference to type %0 with a %select{value|temporary}1 of type %2 drops " @@ -768,7 +847,16 @@ def err_init_reference_member_uninitialized : Error< def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field is uninitialized when used here">, - InGroup<DiagGroup<"uninitialized">>; + InGroup<Uninitialized>; +def warn_uninit_var : Warning<"variable %0 is possibly uninitialized when used here">, + InGroup<DiagGroup<"uninitialized-experimental">>, DefaultIgnore; +def note_uninit_var_def : Note< + "variable %0 is declared here">; +def warn_uninit_var_captured_by_block : Warning< + "variable %0 is possibly uninitialized when captured by block">, + InGroup<DiagGroup<"uninitialized-experimental">>, DefaultIgnore; +def note_var_fixit_add_initialization : Note< + "add initialization to silence this warning">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; def err_temp_copy_no_viable : Error< @@ -798,20 +886,46 @@ def err_temp_copy_incomplete : Error< // C++0x decltype def err_cannot_determine_declared_type_of_overloaded_function : Error< - "cannot determine the %select{type|declared type}0 of an overloaded " - "function">; + "cannot determine the type of an overloaded function">; // C++0x auto def err_auto_variable_cannot_appear_in_own_initializer : Error< "variable %0 declared with 'auto' type cannot appear in its own initializer">; def err_illegal_decl_array_of_auto : Error< - "'%0' declared as array of 'auto'">; + "'%0' declared as array of %1">; +def err_new_array_of_auto : Error< + "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< - "'auto' not allowed in %select{function prototype|struct member|union member" - "|class member|exception declaration|template parameter|block literal}0">; + "'auto' not allowed %select{in function prototype|in struct member" + "|in union member|in class member|in exception declaration" + "|in template parameter|in block literal|in template argument|here}0">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; - +def err_auto_new_requires_ctor_arg : Error< + "new expression for type %0 requires a constructor argument">; +def err_auto_var_init_multiple_expressions : Error< + "initializer for variable %0 with type %1 contains multiple expressions">; +def err_auto_new_ctor_multiple_expressions : Error< + "new expression for type %0 contains multiple constructor arguments">; +def err_auto_missing_trailing_return : Error< + "'auto' return without trailing return type">; +def err_trailing_return_without_auto : Error< + "function with trailing return type must specify return type 'auto', not %0">; +def err_auto_var_deduction_failure : Error< + "variable %0 with type %1 has incompatible initializer of type %2">; +def err_auto_new_deduction_failure : Error< + "new expression for type %0 has incompatible constructor argument of type %1">; +def err_auto_different_deductions : Error< + "'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">; + +// C++0x override control +def override_keyword_only_allowed_on_virtual_member_functions : Error< + "only virtual member functions can be marked '%0'">; +def err_function_marked_override_not_overriding : Error< + "%0 marked 'override' but does not override any member functions">; +def err_class_marked_final_used_as_base : Error< + "base %0 is marked 'final'">; + // C++0x attributes def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; @@ -820,6 +934,32 @@ def err_final_function_overridden : Error< "declaration of %0 overrides a 'final' function">; def err_final_base : Error< "derivation from 'final' %0">; + +def err_function_overriding_without_override : Error< + "%0 overrides function%s1 without being marked 'override'">; + +// C++0x scoped enumerations +def err_enum_invalid_underlying : Error< + "non-integral type %0 is an invalid underlying type">; +def err_enumerator_too_large : Error< + "enumerator value is not representable in the underlying type %0">; +def ext_enumerator_too_large : ExtWarn< + "enumerator value is not representable in the underlying type %0">, + InGroup<Microsoft>; +def err_enumerator_wrapped : Error< + "enumerator value %0 is not representable in the underlying type %1">; +def err_enum_redeclare_type_mismatch : Error< + "enumeration redeclared with different underlying type %0 (was %1)">; +def err_enum_redeclare_fixed_mismatch : Error< + "enumeration previously declared with %select{non|}0fixed underlying type">; +def err_enum_redeclare_scoped_mismatch : Error< + "enumeration previously declared as %select{un|}0scoped">; + +// C++0x delegating constructors +def err_delegation_0x_only : Error< + "delegating constructors are permitted only in C++0x">; +def err_delegation_unimplemented : Error< + "delegating constructors are not fully implemented">; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< @@ -842,13 +982,15 @@ def err_iboutletcollection_object_type : Error< def err_attribute_missing_parameter_name : Error< "attribute requires unquoted parameter">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; +def err_attribute_bad_neon_vector_size : Error< + "Neon vector size must be 64 or 128 bits">; def err_attribute_argument_not_int : Error< "'%0' attribute requires integer constant">; def err_attribute_argument_outof_range : Error< "init_priority attribute requires integer constant between " "101 and 65535 inclusive">; def err_init_priority_object_attr : Error< - "can only use ‘init_priority’ attribute on file-scope definitions " + "can only use 'init_priority' attribute on file-scope definitions " "of objects of class type">; def err_attribute_argument_n_not_int : Error< "'%0' attribute requires parameter %1 to be an integer constant">; @@ -858,8 +1000,12 @@ def err_attribute_argument_out_of_bounds : Error< "'%0' attribute parameter %1 is out of bounds">; def err_attribute_requires_objc_interface : Error< "attribute may only be applied to an Objective-C interface">; +def err_attribute_uuid_malformed_guid : Error< + "uuid attribute contains a malformed GUID">; def warn_nonnull_pointers_only : Warning< "nonnull attribute only applies to pointer arguments">; +def err_attribute_invalid_implicit_this_argument : Error< + "'%0' attribute is invalid for the implicit this argument">; def err_ownership_type : Error< "%0 attribute only applies to %1 arguments">; def err_format_strftime_third_parameter : Error< @@ -868,6 +1014,9 @@ def err_format_attribute_requires_variadic : Error< "format attribute requires variadic function">; def err_format_attribute_not : Error<"format argument not %0">; def err_format_attribute_result_not : Error<"function does not return %0">; +def err_format_attribute_implicit_this_format_string : Error< + "format attribute cannot specify the implicit this argument as the format " + "string">; def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; @@ -889,9 +1038,6 @@ 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 conversion between two pointers with different address " - "spaces">; def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; def err_arg_with_address_space : Error< @@ -921,32 +1067,39 @@ def warn_attribute_weak_on_local : Warning< def warn_weak_identifier_undeclared : Warning< "weak identifier %0 never declared">; def err_attribute_weak_static : Error< - "weak declaration of '%0' must be public">; + "weak declaration cannot have internal linkage">; def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; def err_attribute_weakref_not_static : Error< - "weakref declaration of '%0' must be static">; + "weakref declaration must have internal linkage">; def err_attribute_weakref_not_global_context : Error< "weakref declaration of '%0' must be in a global context">; def err_attribute_weakref_without_alias : Error< "weakref declaration of '%0' must also have an alias attribute">; +def err_alias_not_supported_on_darwin : Error < + "only weak aliases are supported on darwin">; def warn_attribute_wrong_decl_type : Warning< - "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|" - "parameter or Objective-C method |function, method or block|" - "virtual method or class|function, method, or parameter|class|virtual method" - "|member}1 types">; + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "parameters and methods|functions, methods and blocks|" + "classes and virtual methods|functions, methods, and parameters|" + "classes|virtual methods|class members|variables|methods|" + "variables, functions and labels}1">; def err_attribute_wrong_decl_type : Error< - "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|" - "parameter or Objective-C method |function, method or block|" - "virtual method or class|function, method, or parameter|class|virtual method" - "|member}1 types">; + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "parameters and methods|functions, methods and blocks|" + "classes and virtual methods|functions, methods, and parameters|" + "classes|virtual methods|class members|variables|methods}1">; def warn_function_attribute_wrong_type : Warning< "%0 only applies to function types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; +def err_attribute_vecreturn_only_vector_member : Error< + "the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">; +def err_attribute_vecreturn_only_pod_record : Error< + "the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">; def err_cconv_change : Error< "function declared '%0' here was previously declared " "%select{'%2'|without calling convention}1">; @@ -955,9 +1108,8 @@ def err_cconv_knr : Error< def err_cconv_varargs : Error< "variadic function cannot use %0 calling convention">; def err_regparm_mismatch : Error<"function declared with with regparm(%0) " - "attribute was previously declared %plural{0:without the regparm|1:" - "with the regparm(1)|2:with the regparm(2)|3:with the regparm(3)|:with the" - "regparm}1 attribute">; + "attribute was previously declared " + "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, @@ -983,6 +1135,16 @@ def warn_impcast_integer_precision : Warning< def warn_impcast_integer_64_32 : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore; +def warn_impcast_integer_precision_constant : Warning< + "implicit conversion from %2 to %3 changes value from %0 to %1">, + InGroup<DiagGroup<"constant-conversion">>; +def warn_impcast_bitfield_precision_constant : Warning< + "implicit truncation from %2 to bitfield changes value from %0 to %1">, + InGroup<DiagGroup<"constant-conversion">>; +def warn_impcast_literal_float_to_integer : Warning< + "implicit conversion turns literal floating-point number into integer: " + "%0 to %1">, + InGroup<DiagGroup<"literal-conversion">>, DefaultIgnore; def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, @@ -1023,7 +1185,6 @@ def warn_attribute_malloc_pointer_only : Warning< def warn_transparent_union_nonpointer : Warning< "'transparent_union' attribute support incomplete; only supported for " "pointer unions">; - def warn_attribute_sentinel_named_arguments : Warning< "'sentinel' attribute requires named arguments">; def warn_attribute_sentinel_not_variadic : Warning< @@ -1048,9 +1209,9 @@ def err_attribute_regparm_invalid_number : Error< // Clang-Specific Attributes -def err_attribute_iboutlet : Error< +def warn_attribute_iboutlet : Warning< "%0 attribute can only be applied to instance variables or properties">; -def err_attribute_ibaction: Error< +def warn_attribute_ibaction: Warning< "ibaction attribute can only be applied to Objective-C instance methods">; def err_attribute_overloadable_not_function : Error< "'overloadable' attribute can only be applied to a function">; @@ -1062,8 +1223,11 @@ def note_attribute_overloadable_prev_overload : Note< def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; def warn_ns_attribute_wrong_return_type : Warning< - "%0 attribute only applies to functions or methods that " - "return a pointer or Objective-C object">; + "%0 attribute only applies to %select{functions|methods}1 that " + "return %select{an Objective-C object|a pointer}2">; +def warn_ns_attribute_wrong_parameter_type : Warning< + "%0 attribute only applies to %select{Objective-C object|pointer}1 " + "parameters">; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; @@ -1148,12 +1312,14 @@ def note_ovl_candidate : Note<"candidate " "function |function |constructor |" "is the implicit default constructor|" "is the implicit copy constructor|" - "is the implicit copy assignment operator}0%1">; + "is the implicit copy assignment operator|" + "is an inherited constructor}0%1">; def warn_init_pointer_from_false : Warning< "initialization of pointer of type %0 from literal 'false'">, InGroup<BoolConversions>; +def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " @@ -1181,14 +1347,15 @@ def note_ovl_candidate_arity : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0 %select{|template }1" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0 %select{|template }1" "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " "%plural{1:was|:were}4 provided">; def note_ovl_candidate_deleted : Note< - "candidate %select{function|function|constructor|" - "function |function |constructor |||}0%1 " - "has been explicitly %select{made unavailable|deleted}2">; + "candidate %select{function|function|constructor|" + "function |function |constructor ||||constructor (inherited)}0%1 " + "has been explicitly %select{made unavailable|deleted}2">; // Giving the index of the bad argument really clutters this message, and // it's relatively unimportant because 1) it's generally obvious which @@ -1200,21 +1367,24 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1 " + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1 " "not viable: cannot convert argument of incomplete type %2 to %3">; def note_ovl_candidate_bad_overload : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1" " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1" " not viable: no known conversion from %2 to %3 for " "%select{%ordinal5 argument|object argument}4">; def note_ovl_candidate_bad_addrspace : Note<"candidate " @@ -1222,12 +1392,13 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate " "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1 not viable: " + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function||||" - "function (the implicit copy assignment operator)}0 not viable: " + "function (the implicit copy assignment operator)|}0 not viable: " "'this' argument has type %2, but method is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}3">; @@ -1236,7 +1407,8 @@ def note_ovl_candidate_bad_cvr : Note<"candidate " "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1 not viable: " + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1 not viable: " "%ordinal4 argument (%2) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3 qualifier" @@ -1246,7 +1418,8 @@ def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" - "function (the implicit copy assignment operator)}0%1" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1" " not viable: cannot %select{convert from|convert from|bind}2 " "%select{base class pointer|superclass|base class object of type}2 %3 to " "%select{derived class pointer|subclass|derived class reference}2 %4 for " @@ -1260,13 +1433,26 @@ def note_ovl_builtin_unary_candidate : Note< "built-in candidate %0">; def err_ovl_no_viable_function_in_init : Error< "no matching constructor for initialization of %0">; +def err_ovl_no_conversion_in_cast : Error< + "cannot convert %1 to %2 without a conversion operator">; +def err_ovl_no_viable_conversion_in_cast : Error< + "no matching conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_ambiguous_conversion_in_cast : Error< + "ambiguous conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_deleted_conversion_in_cast : Error< + "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 uses deleted function">; 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< - "use of overloaded operator '%0' is ambiguous">; +def err_ovl_ambiguous_oper_unary : Error< + "use of overloaded operator '%0' is ambiguous (operand type %1)">; +def err_ovl_ambiguous_oper_binary : Error< + "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; def err_ovl_deleted_oper : Error< "overload resolution selected %select{unavailable|deleted}0 operator '%1'">; @@ -1274,6 +1460,9 @@ def err_ovl_no_viable_subscript : Error<"no viable overloaded operator[] for type %0">; def err_ovl_no_oper : Error<"type %0 does not provide a %select{subscript|call}1 operator">; +def err_ovl_unresolvable : + Error<"cannot resolve overloaded function from context">; + def err_ovl_no_viable_object_call : Error< "no matching function for call to object of type %0">; @@ -1337,14 +1526,16 @@ 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_parameter_default_in_function_template : Error< - "a template parameter of a function template cannot have a default argument " - "in C++98">; +def ext_template_parameter_default_in_function_template : ExtWarn< + "default template arguments for a function template are a C++0x extension">, + InGroup<CXX0x>; def err_template_parameter_default_template_member : Error< "cannot add a default template argument to the definition of a member of a " "class template">; def err_template_parameter_default_friend_template : Error< "default template argument not permitted on a friend template">; +def err_template_template_parm_no_parms : Error< + "template template parameter must have its own template parameters">; def err_template_variable : Error<"variable %0 declared as a template">; def err_template_variable_noparams : Error< @@ -1401,10 +1592,10 @@ def err_template_arg_not_convertible : Error< "of type %1">; def warn_template_arg_negative : Warning< "non-type template argument with value '%0' converted to '%1' for unsigned " - "template parameter of type %2">; + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; def warn_template_arg_too_large : Warning< "non-type template argument value '%0' truncated to '%1' for " - "template parameter of type %2">; + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; def err_template_arg_no_ref_bind : Error< "non-type template parameter of reference type %0 cannot bind to template " "argument of type %1">; @@ -1440,10 +1631,15 @@ def err_template_arg_not_object_or_func : Error< "non-type template argument does not refer to an object or function">; def err_template_arg_not_pointer_to_member_form : Error< "non-type template argument is not a pointer to member constant">; -def err_template_arg_extra_parens : Error< - "non-type template argument cannot be surrounded by parentheses">; +def ext_template_arg_extra_parens : ExtWarn< + "address non-type template argument cannot be surrounded by parentheses">; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; +def err_pointer_to_member_call_drops_quals : Error< + "call to pointer to member function of type %0 drops '%1' qualifier%s2">; +def err_pointer_to_member_oper_value_classify: Error< + "pointer-to-member function type %0 can only be called on an " + "%select{rvalue|lvalue}1">; // C++ template specialization def err_template_spec_unknown_kind : Error< @@ -1462,10 +1658,20 @@ def err_template_spec_decl_out_of_scope_global : Error< "%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 ext_template_spec_decl_out_of_scope_global : ExtWarn< + "%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; accepted as a C++0x extension">, + InGroup<CXX0x>; def err_template_spec_decl_out_of_scope : Error< "%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 ext_template_spec_decl_out_of_scope : ExtWarn< + "%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; accepted as a C++0x extension">, + InGroup<CXX0x>; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 not in a " @@ -1549,6 +1755,8 @@ def err_function_template_spec_ambiguous : Error< "arguments to identify a particular function template">; def note_function_template_spec_matched : Note< "function template matches specialization %0">; +def err_function_template_partial_spec : Error< + "function template partial specialization is not allowed">; // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< @@ -1597,6 +1805,8 @@ def note_instantiation_contexts_suppressed : Note< def err_field_instantiates_to_function : Error< "data member instantiated with function type %0">; +def err_variable_instantiates_to_function : Error< + "%select{variable|static data member}0 instantiated with function type %1">; def err_nested_name_spec_non_tag : Error< "type %0 cannot be used prior to '::' because it has no members">; @@ -1607,7 +1817,8 @@ def note_previous_explicit_instantiation : Note< "previous explicit instantiation is here">; def ext_explicit_instantiation_after_specialization : Extension< "explicit instantiation of %0 that occurs after an explicit " - "specialization will be ignored (C++0x extension)">; + "specialization will be ignored (C++0x extension)">, + InGroup<CXX0x>; def note_previous_template_specialization : Note< "previous template specialization is here">; def err_explicit_instantiation_enum : Error< @@ -1678,7 +1889,12 @@ def note_typename_refers_here : Note< def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; def ext_typename_outside_of_template : ExtWarn< - "'typename' occurs outside of a template">; + "'typename' occurs outside of a template">, InGroup<CXX0x>; +def err_typename_refers_to_using_value_decl : Error< + "typename specifier refers to a dependent using declaration for a value " + "%0 in %1">; +def note_using_value_decl_missing_typename : Note< + "add 'typename' to treat this using declaration as a type">; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; @@ -1691,7 +1907,7 @@ def note_referenced_class_template : Error< def err_template_kw_missing : Error< "missing 'template' keyword prior to dependent template name '%0%1'">; def ext_template_outside_of_template : ExtWarn< - "'template' keyword outside of a template">; + "'template' keyword outside of a template">, InGroup<CXX0x>; // C++0x Variadic Templates def err_template_param_pack_default_arg : Error< @@ -1700,17 +1916,62 @@ def err_template_param_pack_must_be_last_template_parameter : Error< "template parameter pack must be the last template parameter">; def err_template_parameter_pack_non_pack : Error< - "template %select{type|non-type|template}0 parameter%select{| pack}1 " - "conflicts with previous template %select{type|non-type|template}0 " - "parameter%select{ pack|}1">; + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 conflicts with previous %select{template type|" + "non-type template|template template}0 parameter%select{ pack|}1">; def note_template_parameter_pack_non_pack : Note< - "template %select{type|non-type|template}0 parameter%select{| pack}1 " - "does not match template %select{type|non-type|template}0 " - "parameter%select{ pack|}1 in template argument">; + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 does not match %select{template type|non-type template" + "|template template}0 parameter%select{ pack|}1 in template argument">; def note_template_parameter_pack_here : Note< - "previous template %select{type|non-type|template}0 " + "previous %select{template type|non-type template|template template}0 " "parameter%select{| pack}1 declared here">; +def err_unexpanded_parameter_pack_0 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization}0 " + "contains an unexpanded parameter pack">; +def err_unexpanded_parameter_pack_1 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization}0 " + "contains unexpanded parameter pack %1">; +def err_unexpanded_parameter_pack_2 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization}0 " + "contains unexpanded parameter packs %1 and %2">; +def err_unexpanded_parameter_pack_3_or_more : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization}0 " + "contains unexpanded parameter packs %1, %2, ...">; + +def err_pack_expansion_without_parameter_packs : Error< + "pack expansion does not contain any unexpanded parameter packs">; +def err_pack_expansion_length_conflict : Error< + "pack expansion contains parameter packs %0 and %1 that have different " + "lengths (%2 vs. %3)">; +def err_pack_expansion_length_conflict_multilevel : Error< + "pack expansion contains parameter pack %0 that has a different " + "length (%1 vs. %2) from outer parameter packs">; +def err_pack_expansion_member_init : Error< + "pack expansion for initialization of member %0">; + +def err_function_parameter_pack_without_parameter_packs : Error< + "type %0 of function parameter pack does not contain any unexpanded " + "parameter packs">; +def err_ellipsis_in_declarator_not_parameter : Error< + "only function and template parameters can be parameter packs">; + +def err_sizeof_pack_no_pack_name : Error< + "%0 does not refer to the name of a parameter pack">; + def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; def err_unexpected_namespace : Error< @@ -1721,9 +1982,20 @@ def note_dependent_var_use : Note<"must qualify identifier to find this " def err_undeclared_use : Error<"use of undeclared %0">; def warn_deprecated : Warning<"%0 is deprecated">, InGroup<DeprecatedDeclarations>; +def warn_deprecated_message : Warning<"%0 is deprecated: %1">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_fwdclass_message : Warning< + "%0 maybe deprecated because receiver type is unknown">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_def : Warning< + "Implementing deprecated %select{method|class|category}0">, + InGroup<DeprecatedImplementations>, DefaultIgnore; def err_unavailable : Error<"%0 is unavailable">; +def err_unavailable_message : Error<"%0 is unavailable: %1">; +def warn_unavailable_fwdclass_message : Warning< + "%0 maybe unavailable because receiver type is unknown">; def note_unavailable_here : Note< - "function has been explicitly marked %select{unavailable|deleted}0 here">; + "function has been explicitly marked %select{unavailable|deleted|deprecated}0 here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">; def warn_missing_sentinel : Warning < @@ -1737,6 +2009,14 @@ def err_redefinition : Error<"redefinition of %0">; def err_definition_of_implicitly_declared_member : Error< "definition of implicitly declared %select{constructor|copy constructor|" "copy assignment operator|destructor}1">; +def err_redefinition_extern_inline : Error< + "redefinition of a 'extern inline' function %0 is not supported in " + "%select{C99 mode|C++}1">; + +// This should eventually be an error. +def warn_undefined_internal : Warning< + "%select{function|variable}0 %q1 has internal linkage but is not defined">; +def note_used_here : Note<"used here">; def warn_redefinition_of_typedef : Warning< "redefinition of typedef %0 is invalid in C">, @@ -1748,6 +2028,10 @@ def err_static_non_static : Error< "static declaration of %0 follows non-static declaration">; def err_non_static_static : Error< "non-static declaration of %0 follows static declaration">; +def err_extern_non_extern : Error< + "extern declaration of %0 follows non-extern declaration">; +def err_non_extern_extern : Error< + "non-extern declaration of %0 follows extern declaration">; def err_non_thread_thread : Error< "non-thread-local declaration of %0 follows thread-local declaration">; def err_thread_non_thread : Error< @@ -1780,6 +2064,8 @@ def ext_forward_ref_enum : Extension< "ISO C forbids forward references to 'enum' types">; def err_forward_ref_enum : Error< "ISO C++ forbids forward references to 'enum' types">; +def ext_ms_forward_ref_enum : Extension< + "forward references to 'enum' types are a Microsoft extension">, InGroup<Microsoft>; def ext_forward_ref_enum_def : Extension< "redeclaration of already-defined enum %0 is a GNU extension">, InGroup<GNU>; @@ -1809,6 +2095,19 @@ def err_vm_func_decl : Error< def err_array_too_large : Error< "array is too large (%0 elements)">; +// -Wpadded, -Wpacked +def warn_padded_struct_field : Warning< + "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " + "to align %5">, InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_anon_field : Warning< + "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " + "to align anonymous bit-field">, InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_size : Warning< + "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 " + "to alignment boundary">, InGroup<Padded>, DefaultIgnore; +def warn_unnecessary_packed : Warning< + "packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore; + def err_typecheck_negative_array_size : Error<"array size is negative">; def warn_typecheck_function_qualifiers : Warning< "qualifier on function type %0 has unspecified behavior">; @@ -1881,17 +2180,18 @@ def warn_missing_braces : Warning< "suggest braces around initialization of subobject">, InGroup<DiagGroup<"missing-braces">>, DefaultIgnore; -def err_redefinition_of_label : Error<"redefinition of label '%0'">; -def err_undeclared_label_use : Error<"use of undeclared label '%0'">; +def err_redefinition_of_label : Error<"redefinition of label %0">; +def err_undeclared_label_use : Error<"use of undeclared label %0">; +def warn_unused_label : Warning<"unused label %0">, + InGroup<UnusedLabel>, DefaultIgnore; def err_goto_into_protected_scope : Error<"goto into protected scope">; def err_switch_into_protected_scope : Error< "switch case is in protected scope">; def err_indirect_goto_without_addrlabel : Error< "indirect goto in function with no address-of-label expressions">; -def warn_indirect_goto_in_protected_scope : Warning< - "indirect goto might cross protected scopes">, - InGroup<DiagGroup<"label-address-scope">>; +def err_indirect_goto_in_protected_scope : Error< + "indirect goto might cross protected scopes">; def note_indirect_goto_target : Note<"possible target of indirect goto">; def note_protected_by_variable_init : Note< "jump bypasses variable initialization">; @@ -1953,6 +2253,13 @@ def ext_flexible_array_in_array : Extension< "%0 may not be used as an array element due to flexible array member">; def err_flexible_array_init_nonempty : Error< "non-empty initialization of flexible array member inside subobject">; +def ext_flexible_array_empty_aggregate : Extension< + "flexible array member %0 in otherwise empty %select{struct|class}1 " + "is a Microsoft extension">, InGroup<Microsoft>; +def ext_flexible_array_union : Extension< + "flexible array member %0 in a union is a Microsoft extension">, + InGroup<Microsoft>; + def err_flexible_array_init_needs_braces : Error< "flexible array requires brace-enclosed initializer">; def err_illegal_decl_array_of_functions : Error< @@ -1963,6 +2270,8 @@ def err_illegal_message_expr_incomplete_type : Error< "objective-c message has incomplete result type %0">; def err_illegal_decl_array_of_references : Error< "'%0' declared as array of references of type %1">; +def err_decl_negative_array_size : Error< + "'%0' declared as an array with a negative size">; def err_array_star_outside_prototype : Error< "star modifier used outside of function prototype">; def err_illegal_decl_pointer_to_reference : Error< @@ -2031,7 +2340,16 @@ def note_precedence_bitwise_silence : Note< def warn_logical_instead_of_bitwise : Warning< "use of logical %0 with constant operand; switch to bitwise %1 or " "remove constant">, InGroup<DiagGroup<"constant-logical-operand">>; - + +def warn_logical_and_in_logical_or : Warning< + "'&&' within '||'">, InGroup<LogicalOpParentheses>; +def note_logical_and_in_logical_or_silence : Note< + "place parentheses around the '&&' expression to silence this warning">; + +def warn_self_assignment : Warning< + "explicitly assigning a variable of type %0 to itself">, + InGroup<SelfAssignment>, DefaultIgnore; + def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " "non-fragile ABI">; @@ -2069,6 +2387,11 @@ def err_typecheck_member_reference_type : Error< def err_typecheck_member_reference_unknown : Error< "cannot refer to member %0 in %1 with '%select{.|->}2'">; def err_member_reference_needs_call : Error< + "base of member reference is an overloaded function; perhaps you meant " + "to call %select{it|the 0-argument overload}0?">; +def note_member_ref_possible_intended_overload : Note< + "possibly valid overload here">; +def err_member_reference_needs_call_zero_arg : Error< "base of member reference has function type %0; perhaps you meant to call " "this function with '()'?">; def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, @@ -2078,12 +2401,17 @@ def err_typecheck_incomplete_tag : Error<"incomplete definition of type %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_name_of_class : Error<"member %0 has the same name as its class">; def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; +def err_member_def_does_not_match_ret_type : Error< + "out-of-line definition of %q0 differ from the declaration in the return type">; def err_nonstatic_member_out_of_line : Error< "non-static data member defined out-of-line">; +def err_nonstatic_flexible_variable : Error< + "non-static initialization of a variable with flexible array member">; def err_qualified_typedef_declarator : Error< "typedef declarator cannot be qualified">; def err_qualified_param_declarator : Error< @@ -2091,6 +2419,10 @@ def err_qualified_param_declarator : Error< def ext_out_of_line_declaration : ExtWarn< "out-of-line declaration of a member must be a definition">, InGroup<OutOfLineDeclaration>, DefaultError; +def warn_member_extra_qualification : Warning< + "extra qualification on member %0">; +def err_member_qualification : Error< + "non-friend class member %0 cannot have a qualified name">; def note_member_def_close_match : Note<"member declaration nearly matches">; def err_typecheck_ivar_variable_size : Error< "instance variables must have a constant size">; @@ -2121,7 +2453,7 @@ def err_array_init_not_init_list : Error< "array initializer must be an initializer " "list%select{| or string literal}0">; def warn_deprecated_string_literal_conversion : Warning< - "conversion from string literal to %0 is deprecated">, InGroup<Deprecated>; + "conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>; def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; def err_typecheck_sclass_fscope : Error< "illegal storage class on file-scoped variable">; @@ -2151,7 +2483,7 @@ def err_typecheck_unary_expr : Error< def err_typecheck_indirection_requires_pointer : Error< "indirection requires pointer operand (%0 invalid)">; def warn_indirection_through_null : Warning< - "indirection of non-volatile null pointer will be deleted, not trap">; + "indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>; def note_indirection_through_null : Note< "consider using __builtin_trap() or qualifying pointer with 'volatile'">; @@ -2200,11 +2532,14 @@ def warn_mixed_sign_conditional : Warning< "operands of ? are integers of different signs: %0 and %1">, InGroup<SignCompare>, DefaultIgnore; def warn_lunsigned_always_true_comparison : Warning< - "comparison of unsigned expression %0 is always %1">, - InGroup<SignCompare>, DefaultIgnore; + "comparison of unsigned%select{| enum}2 expression %0 is always %1">, + InGroup<TautologicalCompare>; def warn_runsigned_always_true_comparison : Warning< - "comparison of %0 unsigned expression is always %1">, - InGroup<SignCompare>, DefaultIgnore; + "comparison of %0 unsigned%select{| enum}2 expression is always %1">, + InGroup<TautologicalCompare>; +def warn_comparison_of_mixed_enum_types : Warning< + "comparison of two values with different enumeration types (%0 and %1)">, + InGroup<DiagGroup<"enum-compare">>; def err_invalid_this_use : Error< "invalid use of 'this' outside of a nonstatic member function">; @@ -2212,11 +2547,26 @@ def err_invalid_member_use_in_static_method : Error< "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< "type qualifier is not allowed on this function">; +def err_invalid_ref_qualifier_function_type : Error< + "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions," + " member function pointers, and typedefs of function types">; +def ext_qualified_function_type_template_arg : ExtWarn< + "template argument of '%0' qualified function type is a GNU extension">, + InGroup<GNU>; + def err_invalid_qualified_function_pointer : Error< "type qualifier is not allowed on this function %select{pointer|reference}0">; def err_invalid_qualified_typedef_function_type_use : Error< "a qualified function type cannot be used to declare a " "%select{static member|nonmember}0 function">; +def err_invalid_ref_qualifier_typedef_function_type_use : Error< + "%select{static member|nonmember}0 function cannot have a ref-qualifier " + "'%select{&&|&}1'">; + +def err_ref_qualifier_overload : Error< + "cannot overload a member function %select{without a ref-qualifier|with " + "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" + "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; def err_invalid_non_static_member_use : Error< "invalid use of nonstatic data member %0">; @@ -2244,6 +2594,15 @@ def err_ref_array_type : Error< "cannot refer to declaration with an array type inside block">; def err_property_not_found : Error< "property %0 not found on object of type %1">; +def err_getter_not_found : Error< + "expected getter method not found on object of type %0">; +def err_property_not_found_forward_class : Error< + "property %0 cannot be found in forward class object %1">; +def err_property_not_as_forward_class : Error< + "property %0 refers to an incomplete Objective-C class %1 " + "(with no @interface available)">; +def note_forward_class : Note< + "forward class is declared here">; def err_duplicate_property : Error< "property has a previous declaration">; def ext_gnu_void_ptr : Extension< @@ -2265,6 +2624,8 @@ def error_no_subobject_property_setting : Error< def ext_freestanding_complex : Extension< "complex numbers are an extension in a freestanding C99 implementation">; +// FIXME: Remove when we support imaginary. +def err_imaginary_not_supported : Error<"imaginary types are not supported">; // Obj-c expressions def warn_root_inst_method_not_found : Warning< @@ -2275,14 +2636,16 @@ def warn_inst_method_not_found : Warning< "method %objcinstance0 not found (return type defaults to 'id')">; def error_no_super_class_message : Error< "no @interface declaration found in class messaging of %0">; -def error_no_super_class : Error< - "no super class declared in @interface for %0">; +def error_root_class_cannot_use_super : Error< + "%0 cannot use 'super' because it is a root class">; def err_invalid_receiver_to_message : Error< "invalid receiver to message expression">; def err_invalid_receiver_to_message_super : Error< "'super' is only valid in a method body">; def err_invalid_receiver_class_message : Error< "receiver type %0 is not an Objective-C class">; +def err_missing_open_square_message_send : Error< + "missing '[' at start of message send expression">; def warn_bad_receiver_type : Warning< "receiver type %0 is not 'id' or interface pointer, consider " "casting it to 'id'">; @@ -2332,6 +2695,16 @@ def note_parameter_here : Note< // C++ casts // 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_reinterpret_cast_overload : Error< + "reinterpret_cast cannot resolve overloaded function %0 to type %1">; + +def err_bad_static_cast_overload : Error< + "address of overloaded function %0 cannot be static_cast to type %1">; + +def err_bad_cstyle_cast_overload : Error< + "address of overloaded function %0 cannot be cast to type %1">; + + 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">; @@ -2389,6 +2762,10 @@ def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; // Other C++ expressions def err_need_header_before_typeid : Error< "you need to include <typeinfo> before using the 'typeid' operator">; +def err_need_header_before_ms_uuidof : Error< + "you need to include <guiddef.h> before using the '__uuidof' operator">; +def err_uuidof_without_guid : Error< + "cannot call operator __uuidof on a type with no GUID">; def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; def err_static_illegal_in_new : Error< "the 'static' modifier for the array size is not legal in new expressions">; @@ -2420,7 +2797,8 @@ def err_array_size_ambiguous_conversion : Error< "enumeration type">; def ext_array_size_conversion : Extension< "implicit conversion from array size expression of type %0 to " - "%select{integral|enumeration}1 type %2 is a C++0x extension">; + "%select{integral|enumeration}1 type %2 is a C++0x extension">, + InGroup<CXX0x>; def err_default_init_const : Error< "default initialization of an object of const type %0" @@ -2434,6 +2812,8 @@ def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behaviour">; def err_delete_incomplete_class_type : Warning< "deleting incomplete class type %0; no conversions to pointer type">; +def warn_delete_array_type : Warning< + "'delete' applied to a pointer-to-array type %0 treated as delete[]">; def err_no_suitable_delete_member_function_found : Error< "no suitable member %0 in %1">; def err_ambiguous_suitable_delete_member_function_found : Error< @@ -2462,6 +2842,18 @@ def err_bad_memptr_lhs : Error< 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_exceptions_disabled : Error< + "cannot use '%0' with exceptions disabled">; +def err_objc_exceptions_disabled : Error< + "cannot use '%0' with Objective-C exceptions disabled">; +def warn_non_virtual_dtor : Warning< + "%0 has virtual functions but non-virtual destructor">, + InGroup<NonVirtualDtor>, DefaultIgnore; +def warn_overloaded_virtual : Warning< + "%q0 hides overloaded virtual %select{function|functions}1">, + InGroup<OverloadedVirtual>, DefaultIgnore; +def note_hidden_overloaded_virtual_declared_here : Note< + "hidden overloaded virtual function %q0 declared here">; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " @@ -2527,6 +2919,8 @@ def err_not_tag_in_scope : Error< 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 err_invalid_use_of_bound_member_func : Error< + "a bound member function may only be called">; def err_incomplete_object_call : Error< "incomplete type in call to object of type %0">; def err_incomplete_pointer_to_member_return : Error< @@ -2541,9 +2935,21 @@ def warn_condition_is_idiomatic_assignment : Warning<"using the result " InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore; def note_condition_assign_to_comparison : Note< "use '==' to turn this assignment into an equality comparison">; +def note_condition_or_assign_to_comparison : Note< + "use '!=' to turn this compound assignment into an inequality comparison">; def note_condition_assign_silence : Note< "place parentheses around the assignment to silence this warning">; +def warn_equality_with_extra_parens : Warning<"equality comparison with " + "extraneous parentheses">, InGroup<Parentheses>; +def note_equality_comparison_to_assign : Note< + "use '=' to turn this equality comparison into an assignment">; +def note_equality_comparison_silence : Note< + "remove extraneous parentheses around the comparison to silence this warning">; + +def warn_synthesized_ivar_access : Warning< + "direct access of synthesized ivar by using property access %0">, + InGroup<NonfragileAbi2>, DefaultIgnore; def warn_ivar_variable_conflict : Warning< "when default property synthesis is on, " "%0 lookup will access property ivar instead of global variable">, @@ -2629,7 +3035,15 @@ def err_typecheck_convert_incompatible_block_pointer : Error< " %0 " "%select{from|to parameter of type|from a function with result type|to type|" "with an expression of type|to parameter of type|to type}2 %1">; - +def err_typecheck_incompatible_address_space : Error< + "%select{assigning %1 to %0" + "|passing %0 to parameter of type %1" + "|returning %0 from a function with result type %1" + "|converting %0 to type %1" + "|initializing %0 with an expression of type %1" + "|sending %0 to parameter of type %1" + "|casting %0 to type %1}2" + " changes address space of pointer">; 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< @@ -2688,9 +3102,14 @@ def err_atomic_builtin_pointer_size : Error< "first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte " "type (%0 invalid)">; - def err_deleted_function_use : Error<"attempt to use a deleted function">; +def err_kern_type_not_void_return : Error< + "kernel function type %0 must have void return type">; +def err_config_scalar_return : Error< + "CUDA special function 'cudaConfigureCall' must have scalar return type">; + + def err_cannot_pass_objc_interface_to_vararg : Error< "cannot pass object with interface type %0 by-value through variadic " "%select{function|block|method}1">; @@ -2709,6 +3128,8 @@ def err_typecheck_cond_expect_scalar : Error< "used type %0 where arithmetic or pointer type is required">; def ext_typecheck_cond_one_void : Extension< "C99 forbids conditional expressions with only one void side">; +def err_typecheck_cond_expect_scalar_or_vector : Error< + "used type %0 where arithmetic, pointer, or vector type is required">; def err_typecheck_cast_to_incomplete : Error< "cast to incomplete type %0">; def ext_typecheck_cast_nonscalar : Extension< @@ -2754,6 +3175,8 @@ def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; def err_expected_ident_or_lparen : Error<"expected identifier or '('">; +def err_typecheck_cond_incompatible_operands_null : Error< + "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; } // End of general sema category. // inline asm. @@ -2771,6 +3194,8 @@ let CategoryName = "Inline Assembly Issue" in { def err_asm_tying_incompatible_types : Error< "unsupported inline asm: input with type %0 matching output with type %1">; def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; + def warn_asm_label_on_auto_decl : Warning< + "ignored asm label '%0' on automatic variable">; def err_invalid_asm_cast_lvalue : Error< "invalid use of a cast in a inline asm context requiring an l-value: " "remove the cast or build with -fheinous-gnu-extensions">; @@ -2824,10 +3249,15 @@ def err_base_init_direct_and_virtual : Error< def err_not_direct_base_or_virtual : Error< "type %0 is not a direct or virtual base of %1">; -def err_in_class_initializer_non_integral_type : Error< - "in-class initializer has non-integral, non-enumeration type %0">; +def err_in_class_initializer_non_const : Error< + "non-const static data member must be initialized out of line">; +def err_in_class_initializer_bad_type : Error< + "static data member of type %0 must be initialized out of line">; +def ext_in_class_initializer_float_type : ExtWarn< + "in-class initializer for static data member of type %0 " + "is a C++0x extension">, InGroup<CXX0x>; def err_in_class_initializer_non_constant : Error< - "in-class initializer is not an integral constant expression">; + "in-class initializer is not a constant expression">; // C++ anonymous unions and GNU anonymous structs/unions def ext_anonymous_union : Extension< @@ -2847,6 +3277,9 @@ def err_anonymous_struct_member_redecl : Error< "member of anonymous struct redeclares %0">; def err_anonymous_record_with_type : Error< "types cannot be declared in an anonymous %select{struct|union}0">; +def ext_anonymous_record_with_type : Extension< + "types declared in an anonymous %select{struct|union}0 are a Microsoft " + "extension">, InGroup<Microsoft>; def err_anonymous_record_with_function : Error< "functions cannot be declared in an anonymous %select{struct|union}0">; def err_anonymous_record_with_static : Error< @@ -2856,6 +3289,8 @@ def err_anonymous_record_bad_member : Error< def err_anonymous_record_nonpublic_member : Error< "anonymous %select{struct|union}0 cannot contain a " "%select{private|protected}1 data member">; +def ext_ms_anonymous_struct : ExtWarn< + "anonymous structs are a Microsoft extension">, InGroup<Microsoft>; // C++ local classes def err_reference_to_local_var_in_enclosing_function : Error< @@ -2885,7 +3320,7 @@ def err_memptr_conv_via_virtual : Error< // C++ access control def err_conv_to_inaccessible_base : Error< - "conversion from %0 to inaccessible base class %1">, NoSFINAE; + "conversion from %0 to inaccessible base class %1">, AccessControl; def note_inheritance_specifier_here : Note< "'%0' inheritance specifier here">; def note_inheritance_implicitly_private_here : Note< @@ -2986,7 +3421,16 @@ def warn_not_compound_assign : Warning< // C++0x explicit conversion operators def warn_explicit_conversion_functions : Warning< - "explicit conversion functions are a C++0x extension">; + "explicit conversion functions are a C++0x extension">, InGroup<CXX0x>; + +def warn_array_index_precedes_bounds : Warning< + "array index of '%0' indexes before the beginning of the array">, + InGroup<DiagGroup<"array-bounds">>; +def warn_array_index_exceeds_bounds : Warning< + "array index of '%0' indexes past the end of an array (that contains %1 elements)">, + InGroup<DiagGroup<"array-bounds">>; +def note_array_index_out_of_bounds : Note< + "array %0 declared here">; def warn_printf_write_back : Warning< "use of '%%n' in format string discouraged (potentially insecure)">, @@ -3054,10 +3498,16 @@ def warn_ret_stack_addr : Warning< "address of stack memory associated with local variable %0 returned">; def warn_ret_stack_ref : Warning< "reference to stack memory associated with local variable %0 returned">; +def warn_ret_local_temp_addr : Warning< + "returning address of local temporary object">; +def warn_ret_local_temp_ref : Warning< + "returning reference to local temporary object">; def warn_ret_addr_label : Warning< "returning address of label, which is local">; def err_ret_local_block : Error< "returning block that lives on the local stack">; +def note_ref_var_local_bind : Note< + "binding reference variable %0 here">; // For non-floating point, expressions of the form x == x or x != x @@ -3065,7 +3515,7 @@ def err_ret_local_block : Error< // Array comparisons have similar warnings def warn_comparison_always : Warning< "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, - InGroup<DiagGroup<"tautological-compare">>; + InGroup<TautologicalCompare>; def warn_stringcompare : Warning< "result of comparison against %select{a string literal|@encode}0 is " @@ -3079,8 +3529,8 @@ def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" def err_expected_block_lbrace : Error<"expected '{' in block literal">; def err_return_in_block_expression : Error< "return not allowed in block expression literal">; -def err_block_returns_array : Error< - "block declared as returning an array">; +def err_block_returning_array_function : Error< + "block cannot return %select{array|function}0 type %1">; // CFString checking @@ -3088,6 +3538,9 @@ def err_cfstring_literal_not_string_constant : Error< "CFString literal is not a string constant">; def warn_cfstring_literal_contains_nul_character : Warning< "CFString literal contains NUL character">; +def warn_cfstring_truncated : Warning< + "input conversion stopped due to an input byte that does not " + "belong to the input codeset UTF-8">; // Statements. def err_continue_not_in_loop : Error< @@ -3106,8 +3559,18 @@ def err_duplicate_case : Error<"duplicate case value '%0'">; def warn_case_empty_range : Warning<"empty case range specified">; def warn_missing_case_for_condition : Warning<"no case matching constant switch condition '%0'">; -def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">, +def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">, + InGroup<DiagGroup<"switch-enum"> >; +def warn_missing_case2 : Warning< + "enumeration values %0 and %1 not handled in switch">, + InGroup<DiagGroup<"switch-enum"> >; +def warn_missing_case3 : Warning< + "enumeration values %0, %1, and %2 not handled in switch">, InGroup<DiagGroup<"switch-enum"> >; +def warn_missing_cases : Warning< + "%0 enumeration values not handled in switch: %1, %2, %3...">, + InGroup<DiagGroup<"switch-enum"> >; + def warn_not_in_enum : Warning<"case value not in enumerated type %0">, InGroup<DiagGroup<"switch-enum"> >; def err_typecheck_statement_requires_scalar : Error< @@ -3225,6 +3688,8 @@ 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_double_requires_fp64 : Error< + "use of type 'double' requires cl_khr_fp64 extension to be enabled">; def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; @@ -3235,9 +3700,9 @@ def warn_ivar_use_hidden : Warning< def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; def error_private_ivar_access : Error<"instance variable %0 is private">, - NoSFINAE; + AccessControl; def error_protected_ivar_access : Error<"instance variable %0 is protected">, - NoSFINAE; + AccessControl; 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">; @@ -3284,6 +3749,9 @@ def err_using_directive_suggest : Error< def err_using_directive_member_suggest : Error< "no namespace named %0 in %1; did you mean %2?">; def note_namespace_defined_here : Note<"namespace %0 defined here">; +def err_sizeof_pack_no_pack_name_suggest : Error< + "%0 does not refer to the name of a parameter pack; did you mean %1?">; +def note_parameter_pack_here : Note<"parameter pack %0 declared here">; } // end of sema category } // end of sema component. diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index e71f51a0e700..563157fa8fbe 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_FILEMANAGER_H #define LLVM_CLANG_FILEMANAGER_H +#include "clang/Basic/FileSystemOptions.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -22,12 +23,20 @@ #include "llvm/Config/config.h" // for mode_t // FIXME: Enhance libsystem to support inode and other fields in stat. #include <sys/types.h> -#include <sys/stat.h> + +struct stat; + +namespace llvm { +class MemoryBuffer; +namespace sys { class Path; } +} namespace clang { class FileManager; - -/// DirectoryEntry - Cached information about one directory on the disk. +class FileSystemStatCache; + +/// DirectoryEntry - Cached information about one directory (either on +/// the disk or in the virtual file system). /// class DirectoryEntry { const char *Name; // Name of the directory. @@ -37,7 +46,9 @@ public: const char *getName() const { return Name; } }; -/// FileEntry - Cached information about one file on the disk. +/// FileEntry - Cached information about one file (either on the disk +/// or in the virtual file system). If the 'FD' member is valid, then +/// this FileEntry has an open file descriptor for the file. /// class FileEntry { const char *Name; // Name of the file. @@ -48,12 +59,29 @@ class FileEntry { dev_t Device; // ID for the device containing the file. ino_t Inode; // Inode number for the file. mode_t FileMode; // The file mode as returned by 'stat'. + + /// FD - The file descriptor for the file entry if it is opened and owned + /// by the FileEntry. If not, this is set to -1. + mutable int FD; friend class FileManager; + public: FileEntry(dev_t device, ino_t inode, mode_t m) - : Name(0), Device(device), Inode(inode), FileMode(m) {} + : Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {} // Add a default constructor for use with llvm::StringMap - FileEntry() : Name(0), Device(0), Inode(0), FileMode(0) {} + FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {} + + FileEntry(const FileEntry &FE) { + memcpy(this, &FE, sizeof(FE)); + assert(FD == -1 && "Cannot copy a file-owning FileEntry"); + } + + void operator=(const FileEntry &FE) { + memcpy(this, &FE, sizeof(FE)); + assert(FD == -1 && "Cannot assign a file-owning FileEntry"); + } + + ~FileEntry(); const char *getName() const { return Name; } off_t getSize() const { return Size; } @@ -67,111 +95,68 @@ public: /// const DirectoryEntry *getDir() const { return Dir; } - bool operator<(const FileEntry& RHS) const { + bool operator<(const FileEntry &RHS) const { return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode); } }; -/// \brief Abstract interface for introducing a FileManager cache for 'stat' -/// system calls, which is used by precompiled and pretokenized headers to -/// improve performance. -class StatSysCallCache { -protected: - llvm::OwningPtr<StatSysCallCache> NextStatCache; - -public: - virtual ~StatSysCallCache() {} - virtual int stat(const char *path, struct stat *buf) { - if (getNextStatCache()) - return getNextStatCache()->stat(path, buf); - - return ::stat(path, buf); - } - - /// \brief Sets the next stat call cache in the chain of stat caches. - /// Takes ownership of the given stat cache. - void setNextStatCache(StatSysCallCache *Cache) { - NextStatCache.reset(Cache); - } - - /// \brief Retrieve the next stat call cache in the chain. - StatSysCallCache *getNextStatCache() { return NextStatCache.get(); } - - /// \brief Retrieve the next stat call cache in the chain, transferring - /// ownership of this cache (and, transitively, all of the remaining caches) - /// to the caller. - StatSysCallCache *takeNextStatCache() { return NextStatCache.take(); } -}; - -/// \brief A stat "cache" that can be used by FileManager to keep -/// track of the results of stat() calls that occur throughout the -/// execution of the front end. -class MemorizeStatCalls : public StatSysCallCache { -public: - /// \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 - 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(); } - - virtual int stat(const char *path, struct stat *buf); -}; - /// FileManager - Implements support for file system lookup, file system /// caching, and directory search management. This also handles more advanced /// properties, such as uniquing files based on "inode", so that a file with two /// names (e.g. symlinked) will be treated as a single file. /// class FileManager { + FileSystemOptions FileSystemOpts; class UniqueDirContainer; class UniqueFileContainer; - /// UniqueDirs/UniqueFiles - Cache for existing directories/files. + /// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files. /// - UniqueDirContainer &UniqueDirs; - UniqueFileContainer &UniqueFiles; + UniqueDirContainer &UniqueRealDirs; + UniqueFileContainer &UniqueRealFiles; - /// DirEntries/FileEntries - This is a cache of directory/file entries we have - /// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above. + /// \brief The virtual directories that we have allocated. For each + /// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent + /// directories (foo/ and foo/bar/) here. + llvm::SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries; + /// \brief The virtual files that we have allocated. + llvm::SmallVector<FileEntry*, 4> VirtualFileEntries; + + /// SeenDirEntries/SeenFileEntries - This is a cache that maps paths + /// to directory/file entries (either real or virtual) we have + /// looked up. The actual Entries for real directories/files are + /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries + /// for virtual directories/files are owned by + /// VirtualDirectoryEntries/VirtualFileEntries above. /// - llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries; - llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries; + llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries; + llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries; /// NextFileUID - Each FileEntry we create is assigned a unique ID #. /// unsigned NextFileUID; - /// \brief The virtual files that we have allocated. - llvm::SmallVector<FileEntry *, 4> VirtualFileEntries; - // Statistics. unsigned NumDirLookups, NumFileLookups; unsigned NumDirCacheMisses, NumFileCacheMisses; // Caching. - llvm::OwningPtr<StatSysCallCache> StatCache; + llvm::OwningPtr<FileSystemStatCache> StatCache; - int stat_cached(const char* path, struct stat* buf) { - return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf); - } + bool getStatValue(const char *Path, struct stat &StatBuf, + int *FileDescriptor); + + /// Add all ancestors of the given path (pointing to either a file + /// or a directory) as virtual directories. + void addAncestorsAsVirtualDirs(llvm::StringRef Path); public: - FileManager(); + FileManager(const FileSystemOptions &FileSystemOpts); ~FileManager(); - /// \brief Installs the provided StatSysCallCache object within - /// the FileManager. + /// \brief Installs the provided FileSystemStatCache object within + /// the FileManager. /// /// Ownership of this object is transferred to the FileManager. /// @@ -181,33 +166,46 @@ public: /// \param AtBeginning whether this new stat cache must be installed at the /// beginning of the chain of stat caches. Otherwise, it will be added to /// the end of the chain. - void addStatCache(StatSysCallCache *statCache, bool AtBeginning = false); + void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false); - /// \brief Removes the provided StatSysCallCache object from the file manager. - void removeStatCache(StatSysCallCache *statCache); - - /// getDirectory - Lookup, cache, and verify the specified directory. This - /// returns null if the directory doesn't exist. + /// \brief Removes the specified FileSystemStatCache object from the manager. + void removeStatCache(FileSystemStatCache *statCache); + + /// getDirectory - Lookup, cache, and verify the specified directory + /// (real or virtual). This returns NULL if the directory doesn't exist. /// - const DirectoryEntry *getDirectory(llvm::StringRef Filename) { - return getDirectory(Filename.begin(), Filename.end()); - } - const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd); + const DirectoryEntry *getDirectory(llvm::StringRef DirName); - /// getFile - Lookup, cache, and verify the specified file. This returns null - /// if the file doesn't exist. + /// getFile - Lookup, cache, and verify the specified file (real or + /// virtual). This returns NULL if the file doesn't exist. /// - const FileEntry *getFile(llvm::StringRef Filename) { - return getFile(Filename.begin(), Filename.end()); - } - const FileEntry *getFile(const char *FilenameStart, - const char *FilenameEnd); + const FileEntry *getFile(llvm::StringRef Filename); /// \brief Retrieve a file entry for a "virtual" file that acts as /// if there were a file with the given name on disk. The file /// itself is not accessed. const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size, time_t ModificationTime); + + /// \brief Open the specified file as a MemoryBuffer, returning a new + /// MemoryBuffer if successful, otherwise returning null. + llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry, + std::string *ErrorStr = 0); + llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename, + std::string *ErrorStr = 0); + + /// \brief If path is not absolute and FileSystemOptions set the working + /// directory, the path is modified to be relative to the given + /// working directory. + static void FixupRelativePath(llvm::sys::Path &path, + const FileSystemOptions &FSOpts); + + + /// \brief Produce an array mapping from the unique IDs assigned to each + /// file to the corresponding FileEntry pointer. + void GetUniqueIDMapping( + llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const; + void PrintStats() const; }; diff --git a/include/clang/Basic/FileSystemOptions.h b/include/clang/Basic/FileSystemOptions.h new file mode 100644 index 000000000000..81e928da2a70 --- /dev/null +++ b/include/clang/Basic/FileSystemOptions.h @@ -0,0 +1,31 @@ +//===--- FileSystemOptions.h - File System Options --------------*- 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 FileSystemOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H +#define LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H + +#include <string> + +namespace clang { + +/// \brief Keeps track of options that affect how file operations are performed. +class FileSystemOptions { +public: + /// \brief If set, paths are resolved as if the working directory was + /// set to the value of WorkingDir. + std::string WorkingDir; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h new file mode 100644 index 000000000000..77828b3ecb8a --- /dev/null +++ b/include/clang/Basic/FileSystemStatCache.h @@ -0,0 +1,101 @@ +//===--- FileSystemStatCache.h - Caching for 'stat' calls -------*- 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 FileSystemStatCache interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FILESYSTEMSTATCACHE_H +#define LLVM_CLANG_FILESYSTEMSTATCACHE_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include <sys/types.h> +#include <sys/stat.h> + +namespace clang { + +/// \brief Abstract interface for introducing a FileManager cache for 'stat' +/// system calls, which is used by precompiled and pretokenized headers to +/// improve performance. +class FileSystemStatCache { +protected: + llvm::OwningPtr<FileSystemStatCache> NextStatCache; + +public: + virtual ~FileSystemStatCache() {} + + enum LookupResult { + CacheExists, //< We know the file exists and its cached stat data. + CacheMissing //< We know that the file doesn't exist. + }; + + /// FileSystemStatCache::get - Get the 'stat' information for the specified + /// path, using the cache to accellerate it if possible. This returns true if + /// the path does not exist or false if it exists. + /// + /// If FileDescriptor is non-null, then this lookup should only return success + /// for files (not directories). If it is null this lookup should only return + /// success for directories (not files). On a successful file lookup, the + /// implementation can optionally fill in FileDescriptor with a valid + /// descriptor and the client guarantees that it will close it. + static bool get(const char *Path, struct stat &StatBuf, int *FileDescriptor, + FileSystemStatCache *Cache); + + + /// \brief Sets the next stat call cache in the chain of stat caches. + /// Takes ownership of the given stat cache. + void setNextStatCache(FileSystemStatCache *Cache) { + NextStatCache.reset(Cache); + } + + /// \brief Retrieve the next stat call cache in the chain. + FileSystemStatCache *getNextStatCache() { return NextStatCache.get(); } + + /// \brief Retrieve the next stat call cache in the chain, transferring + /// ownership of this cache (and, transitively, all of the remaining caches) + /// to the caller. + FileSystemStatCache *takeNextStatCache() { return NextStatCache.take(); } + +protected: + virtual LookupResult getStat(const char *Path, struct stat &StatBuf, + int *FileDescriptor) = 0; + + LookupResult statChained(const char *Path, struct stat &StatBuf, + int *FileDescriptor) { + if (FileSystemStatCache *Next = getNextStatCache()) + return Next->getStat(Path, StatBuf, FileDescriptor); + + // If we hit the end of the list of stat caches to try, just compute and + // return it without a cache. + return get(Path, StatBuf, FileDescriptor, 0) ? CacheMissing : CacheExists; + } +}; + +/// \brief A stat "cache" that can be used by FileManager to keep +/// track of the results of stat() calls that occur throughout the +/// execution of the front end. +class MemorizeStatCalls : public FileSystemStatCache { +public: + /// \brief The set of stat() calls that have been seen. + llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls; + + typedef llvm::StringMap<struct stat, llvm::BumpPtrAllocator>::const_iterator + iterator; + + iterator begin() const { return StatCalls.begin(); } + iterator end() const { return StatCalls.end(); } + + virtual LookupResult getStat(const char *Path, struct stat &StatBuf, + int *FileDescriptor); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 24fe086a79e9..d576643550bd 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -22,8 +22,9 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PointerLikeTypeTraits.h" -#include <string> #include <cassert> +#include <cctype> +#include <string> namespace llvm { template <typename T> struct DenseMapInfo; @@ -53,7 +54,7 @@ class IdentifierInfo { // 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 :11; 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. @@ -63,7 +64,7 @@ class IdentifierInfo { // file and wasn't modified since. bool RevertedTokenID : 1; // True if RevertTokenIDToIdentifier was // called. - // 7 bits left in 32-bit word. + // 6 bits left in 32-bit word. void *FETokenInfo; // Managed by the language front-end. llvm::StringMapEntry<IdentifierInfo*> *Entry; @@ -71,7 +72,7 @@ class IdentifierInfo { void operator=(const IdentifierInfo&); // NONASSIGNABLE. friend class IdentifierTable; - + public: IdentifierInfo(); @@ -254,6 +255,35 @@ private: } }; +/// \brief An iterator that walks over all of the known identifiers +/// in the lookup table. +/// +/// Since this iterator uses an abstract interface via virtual +/// functions, it uses an object-oriented interface rather than the +/// more standard C++ STL iterator interface. In this OO-style +/// iteration, the single function \c Next() provides dereference, +/// advance, and end-of-sequence checking in a single +/// operation. Subclasses of this iterator type will provide the +/// actual functionality. +class IdentifierIterator { +private: + IdentifierIterator(const IdentifierIterator&); // Do not implement + IdentifierIterator &operator=(const IdentifierIterator&); // Do not implement + +protected: + IdentifierIterator() { } + +public: + virtual ~IdentifierIterator(); + + /// \brief Retrieve the next string in the identifier table and + /// advances the iterator for the following string. + /// + /// \returns The next string in the identifier table. If there is + /// no such string, returns an empty \c llvm::StringRef. + virtual llvm::StringRef Next() = 0; +}; + /// IdentifierInfoLookup - An abstract class used by IdentifierTable that /// provides an interface for performing lookups from strings /// (const char *) to IdentiferInfo objects. @@ -266,6 +296,18 @@ public: /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. virtual IdentifierInfo* get(llvm::StringRef Name) = 0; + + /// \brief Retrieve an iterator into the set of all identifiers + /// known to this identifier lookup source. + /// + /// This routine provides access to all of the identifiers known to + /// the identifier lookup, allowing access to the contents of the + /// identifiers without introducing the overhead of constructing + /// IdentifierInfo objects for each. + /// + /// \returns A new iterator into the set of known identifiers. The + /// caller is responsible for deleting this iterator. + virtual IdentifierIterator *getIdentifiers() const; }; /// \brief An abstract class used to resolve numerical identifier @@ -304,6 +346,11 @@ public: ExternalLookup = IILookup; } + /// \brief Retrieve the external identifier lookup object, if any. + IdentifierInfoLookup *getExternalIdentifierLookup() const { + return ExternalLookup; + } + llvm::BumpPtrAllocator& getAllocator() { return HashTable.getAllocator(); } @@ -463,8 +510,33 @@ public: return getIdentifierInfoFlag() == ZeroArg; } unsigned getNumArgs() const; + + + /// \brief Retrieve the identifier at a given position in the selector. + /// + /// Note that the identifier pointer returned may be NULL. Clients that only + /// care about the text of the identifier string, and not the specific, + /// uniqued identifier pointer, should use \c getNameForSlot(), which returns + /// an empty string when the identifier pointer would be NULL. + /// + /// \param argIndex The index for which we want to retrieve the identifier. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the uniqued identifier for this slot, or NULL if this slot has + /// no corresponding identifier. IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; - + + /// \brief Retrieve the name at a given position in the selector. + /// + /// \param argIndex The index for which we want to retrieve the name. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the name for this slot, which may be the empty string if no + /// name was supplied. + llvm::StringRef getNameForSlot(unsigned argIndex) const; + /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return /// it as an std::string. std::string getAsString() const; @@ -570,6 +642,17 @@ struct DenseMapInfo<clang::Selector> { template <> struct isPodLike<clang::Selector> { static const bool value = true; }; +template<> +class PointerLikeTypeTraits<clang::Selector> { +public: + static inline const void *getAsVoidPointer(clang::Selector P) { + return P.getAsOpaquePtr(); + } + static inline clang::Selector getFromVoidPointer(const void *P) { + return clang::Selector(reinterpret_cast<uintptr_t>(P)); + } + enum { NumLowBitsAvailable = 0 }; +}; // Provide PointerLikeTypeTraits for IdentifierInfo pointers, which // are not guaranteed to be 8-byte aligned. diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 5bd0d04a4eea..f4db55ae0626 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LANGOPTIONS_H #include <string> +#include "clang/Basic/Visibility.h" namespace clang { @@ -43,6 +44,8 @@ public: unsigned ObjC2 : 1; // Objective-C 2 support enabled. unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled unsigned ObjCNonFragileABI2 : 1; // Objective-C enhanced modern abi enabled + unsigned ObjCDefaultSynthProperties : 1; // Objective-C auto-synthesized properties. + unsigned AppleKext : 1; // Allow apple kext features. unsigned PascalStrings : 1; // Allow Pascal strings unsigned WritableStrings : 1; // Allow writable strings @@ -51,8 +54,10 @@ public: unsigned AltiVec : 1; // Support AltiVec-style vector initializers. unsigned Exceptions : 1; // Support exception handling. unsigned SjLjExceptions : 1; // Use setjmp-longjump exception handling. + unsigned ObjCExceptions : 1; // Support Objective-C exceptions. unsigned RTTI : 1; // Support RTTI information. + unsigned MSBitfields : 1; // MS-compatible structure layout unsigned NeXTRuntime : 1; // Use NeXT runtime. unsigned Freestanding : 1; // Freestanding implementation unsigned NoBuiltin : 1; // Do not use builtin functions (-fno-builtin) @@ -89,8 +94,12 @@ public: unsigned CharIsSigned : 1; // Whether char is a signed or unsigned type unsigned ShortWChar : 1; // Force wchar_t to be unsigned short int. + unsigned ShortEnums : 1; // The enum type will be equivalent to the + // smallest integer type with enough room. + unsigned OpenCL : 1; // OpenCL C99 language extensions. - + unsigned CUDA : 1; // CUDA C++ language extensions. + unsigned AssumeSaneOperatorNew : 1; // Whether to add __attribute__((malloc)) // to the declaration of C++'s new // operators @@ -101,10 +110,16 @@ public: unsigned DumpVTableLayouts : 1; /// Dump the layouts of emitted vtables. unsigned NoConstantCFStrings : 1; // Do not do CF strings unsigned InlineVisibilityHidden : 1; // Whether inline C++ methods have - // hidden visibility by default. + // hidden visibility by default. unsigned SpellChecking : 1; // Whether to perform spell-checking for error // recovery. + unsigned SinglePrecisionConstants : 1; // Whether to treat double-precision + // floating point constants as + // single precision constants. + unsigned FastRelaxedMath : 1; // OpenCL fast relaxed math (on its own, + // defines __FAST_RELAXED_MATH__). + unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT // FIXME: This is just a temporary option, for testing purposes. unsigned NoBitFieldTypeAlign : 1; @@ -118,47 +133,56 @@ private: public: unsigned InstantiationDepth; // Maximum template instantiation depth. + unsigned NumLargeByValueCopy; // Warn if parameter/return value is larger + // in bytes than this setting. 0 is no check. + + // Version of Microsoft Visual C/C++ we are pretending to be. This is + // temporary until we support all MS extensions used in Windows SDK and stdlib + // headers. Sets _MSC_VER. + unsigned MSCVersion; std::string ObjCConstantStringClass; enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPReq }; - enum VisibilityMode { - Default, - Protected, - Hidden - }; - + enum SignedOverflowBehaviorTy { SOB_Undefined, // Default C standard behavior. SOB_Defined, // -fwrapv SOB_Trapping // -ftrapv }; + /// The name of the handler function to be called when -ftrapv is specified. + /// If none is specified, abort (GCC-compatible behaviour). + std::string OverflowHandler; LangOptions() { Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0; HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0; + AppleKext = 0; + ObjCDefaultSynthProperties = 0; NoConstantCFStrings = 0; InlineVisibilityHidden = 0; C99 = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0; Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0; + ObjCExceptions = 1; + MSBitfields = 0; NeXTRuntime = 1; RTTI = 1; LaxVectorConversions = 1; HeinousExtensions = 0; - AltiVec = OpenCL = StackProtector = 0; + AltiVec = OpenCL = CUDA = StackProtector = 0; + + SymbolVisibility = (unsigned) DefaultVisibility; - SymbolVisibility = (unsigned) Default; - ThreadsafeStatics = 1; POSIXThreads = 0; Blocks = 0; EmitAllDecls = 0; MathErrno = 1; SignedOverflowBehavior = SOB_Undefined; - + AssumeSaneOperatorNew = 1; AccessControl = 1; ElideConstructors = 1; @@ -168,6 +192,9 @@ public: InstantiationDepth = 1024; + NumLargeByValueCopy = 0; + MSCVersion = 0; + Optimize = 0; OptimizeSize = 0; @@ -179,10 +206,14 @@ public: CharIsSigned = 1; ShortWChar = 0; + ShortEnums = 0; CatchUndefined = 0; DumpRecordLayouts = 0; DumpVTableLayouts = 0; SpellChecking = 1; + SinglePrecisionConstants = 0; + FastRelaxedMath = 0; + DefaultFPContract = 0; NoBitFieldTypeAlign = 0; } @@ -196,17 +227,44 @@ public: StackProtector = static_cast<unsigned>(m); } - VisibilityMode getVisibilityMode() const { - return (VisibilityMode) SymbolVisibility; + Visibility getVisibilityMode() const { + return (Visibility) SymbolVisibility; } - void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; } - + void setVisibilityMode(Visibility v) { SymbolVisibility = (unsigned) v; } + SignedOverflowBehaviorTy getSignedOverflowBehavior() const { return (SignedOverflowBehaviorTy)SignedOverflowBehavior; } void setSignedOverflowBehavior(SignedOverflowBehaviorTy V) { SignedOverflowBehavior = (unsigned)V; } + + bool areExceptionsEnabled() const { + return Exceptions; + } +}; + +/// Floating point control options +class FPOptions { +public: + unsigned fp_contract : 1; + + FPOptions() : fp_contract(0) {} + + FPOptions(const LangOptions &LangOpts) : + fp_contract(LangOpts.DefaultFPContract) {} +}; + +/// OpenCL volatile options +class OpenCLOptions { +public: +#define OPENCLEXT(nm) unsigned nm : 1; +#include "clang/Basic/OpenCLExtensions.def" + + OpenCLOptions() { +#define OPENCLEXT(nm) nm = 0; +#include "clang/Basic/OpenCLExtensions.def" + } }; } // end namespace clang diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 8909e47146a7..267ecbcd6df4 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -15,10 +15,10 @@ #define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H #include "llvm/Support/Allocator.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Host.h" +#include "llvm/Support/Host.h" #include <cassert> #include <cstdlib> @@ -320,7 +320,7 @@ public: InfoPtr->ReadKey((const unsigned char* const) Items, L.first); // If the key doesn't match just skip reading the value. - if (!Info::EqualKey(X, iKey)) { + if (!InfoPtr->EqualKey(X, iKey)) { Items += item_len; continue; } @@ -334,6 +334,70 @@ public: iterator end() const { return iterator(); } + /// \brief Iterates over all of the keys in the table. + class key_iterator { + const unsigned char* Ptr; + unsigned NumItemsInBucketLeft; + unsigned NumEntriesLeft; + Info *InfoObj; + public: + typedef external_key_type value_type; + + key_iterator(const unsigned char* const Ptr, unsigned NumEntries, + Info *InfoObj) + : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), + InfoObj(InfoObj) { } + key_iterator() + : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { } + + friend bool operator==(const key_iterator &X, const key_iterator &Y) { + return X.NumEntriesLeft == Y.NumEntriesLeft; + } + friend bool operator!=(const key_iterator& X, const key_iterator &Y) { + return X.NumEntriesLeft != Y.NumEntriesLeft; + } + + key_iterator& operator++() { // Preincrement + if (!NumItemsInBucketLeft) { + // 'Items' starts with a 16-bit unsigned integer representing the + // number of items in this bucket. + NumItemsInBucketLeft = io::ReadUnalignedLE16(Ptr); + } + Ptr += 4; // Skip the hash. + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Ptr); + Ptr += L.first + L.second; + assert(NumItemsInBucketLeft); + --NumItemsInBucketLeft; + assert(NumEntriesLeft); + --NumEntriesLeft; + return *this; + } + key_iterator operator++(int) { // Postincrement + key_iterator tmp = *this; ++*this; return tmp; + } + + value_type operator*() const { + const unsigned char* LocalPtr = Ptr; + if (!NumItemsInBucketLeft) + LocalPtr += 2; // number of items in bucket + LocalPtr += 4; // Skip the hash. + + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L + = Info::ReadKeyDataLength(LocalPtr); + + // Read the key. + const internal_key_type& Key = InfoObj->ReadKey(LocalPtr, L.first); + return InfoObj->GetExternalKey(Key); + } + }; + + key_iterator key_begin() { + return key_iterator(Base + 4, getNumEntries(), &InfoObj); + } + key_iterator key_end() { return key_iterator(); } + /// \brief Iterates over all the entries in the table, returning /// a key/data pair. class item_iterator { diff --git a/include/clang/Basic/OpenCLExtensions.def b/include/clang/Basic/OpenCLExtensions.def new file mode 100644 index 000000000000..95cc1a9a513f --- /dev/null +++ b/include/clang/Basic/OpenCLExtensions.def @@ -0,0 +1,28 @@ +//===--- OpenCLExtensions.def - OpenCL extension list -----------*- 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 list of supported OpenCL extensions. +// +//===----------------------------------------------------------------------===// + +OPENCLEXT(cl_khr_fp64) +OPENCLEXT(cl_khr_int64_base_atomics) +OPENCLEXT(cl_khr_int64_extended_atomics) +OPENCLEXT(cl_khr_fp16) +OPENCLEXT(cl_khr_gl_sharing) +OPENCLEXT(cl_khr_gl_event) +OPENCLEXT(cl_khr_d3d10_sharing) +OPENCLEXT(cl_khr_global_int32_base_atomics) +OPENCLEXT(cl_khr_global_int32_extended_atomics) +OPENCLEXT(cl_khr_local_int32_base_atomics) +OPENCLEXT(cl_khr_local_int32_extended_atomics) +OPENCLEXT(cl_khr_byte_addressable_store) +OPENCLEXT(cl_khr_3d_image_writes) + +#undef OPENCLEXT diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index cd0da97e2ba3..d00195b32674 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -18,7 +18,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cassert> namespace clang { @@ -57,6 +57,10 @@ public: /// what sort of argument kind it is. intptr_t DiagArgumentsVal[MaxArguments]; + /// \brief The values for the various substitution positions that have + /// string arguments. + std::string DiagArgumentsStr[MaxArguments]; + /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. CharSourceRange DiagRanges[10]; @@ -186,6 +190,26 @@ public: *this->DiagStorage = *Other.DiagStorage; } + PartialDiagnostic(const DiagnosticInfo &Other, StorageAllocator &Allocator) + : DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator) + { + // Copy arguments. + for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { + if (Other.getArgKind(I) == Diagnostic::ak_std_string) + AddString(Other.getArgStdStr(I)); + else + AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); + } + + // Copy source ranges. + for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) + AddSourceRange(Other.getRange(I)); + + // Copy fix-its. + for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) + AddFixItHint(Other.getFixItHint(I)); + } + PartialDiagnostic &operator=(const PartialDiagnostic &Other) { DiagID = Other.DiagID; if (Other.DiagStorage) { @@ -216,13 +240,28 @@ public: DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; } + void AddString(llvm::StringRef V) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] + = Diagnostic::ak_std_string; + DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; + } + 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], + if ((Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i] + == Diagnostic::ak_std_string) + DB.AddString(DiagStorage->DiagArgumentsStr[i]); + else + DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); } @@ -230,7 +269,7 @@ public: for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) DB.AddSourceRange(DiagStorage->DiagRanges[i]); - // Add all code modification hints + // Add all fix-its. for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i) DB.AddFixItHint(DiagStorage->FixItHints[i]); } @@ -263,6 +302,13 @@ public: } friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + llvm::StringRef S) { + + PD.AddString(S); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, const SourceRange &R) { PD.AddSourceRange(CharSourceRange::getTokenRange(R)); return PD; @@ -288,6 +334,9 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } +/// \brief A partial diagnostic along with the source location where this +/// diagnostic occurs. +typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt; } // end namespace clang #endif diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 35f27fbebd72..605c4bbafc74 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SOURCELOCATION_H #define LLVM_CLANG_SOURCELOCATION_H +#include "llvm/Support/PointerLikeTypeTraits.h" #include <utility> #include <cassert> @@ -121,7 +122,6 @@ public: /// directly. unsigned getRawEncoding() const { return ID; } - /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into /// a real SourceLocation. static SourceLocation getFromRawEncoding(unsigned Encoding) { @@ -130,6 +130,22 @@ public: return X; } + /// getPtrEncoding - When a SourceLocation itself cannot be used, this returns + /// an (opaque) pointer encoding for it. This should only be passed + /// to SourceLocation::getFromPtrEncoding, it should not be inspected + /// directly. + void* getPtrEncoding() const { + // Double cast to avoid a warning "cast to pointer from integer of different + // size". + return (void*)(uintptr_t)getRawEncoding(); + } + + /// getFromPtrEncoding - Turn a pointer encoding of a SourceLocation object + /// into a real SourceLocation. + static SourceLocation getFromPtrEncoding(void *Encoding) { + return getFromRawEncoding((unsigned)(uintptr_t)Encoding); + } + void print(llvm::raw_ostream &OS, const SourceManager &SM) const; void dump(const SourceManager &SM) const; }; @@ -265,6 +281,20 @@ public: bool isInSystemHeader() const; + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { + assert(Loc.isValid()); + assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); + return isBeforeInTranslationUnitThan((SourceLocation)Loc); + } + /// Prints information about this FullSourceLoc to stderr. Useful for /// debugging. void dump() const { SourceLocation::dump(*SrcMgr); } @@ -350,6 +380,19 @@ namespace llvm { template <> struct isPodLike<clang::FileID> { static const bool value = true; }; + // Teach SmallPtrSet how to handle SourceLocation. + template<> + class PointerLikeTypeTraits<clang::SourceLocation> { + public: + static inline void *getAsVoidPointer(clang::SourceLocation L) { + return L.getPtrEncoding(); + } + static inline clang::SourceLocation getFromVoidPointer(void *P) { + return clang::SourceLocation::getFromRawEncoding((unsigned)(uintptr_t)P); + } + enum { NumLowBitsAvailable = 0 }; + }; + } // end namespace llvm #endif diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 7a66117f2076..c0fbd089e760 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -16,7 +16,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/Support/Allocator.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/DenseMap.h" @@ -369,7 +369,9 @@ public: class SourceManager { /// \brief Diagnostic object. Diagnostic &Diag; - + + FileManager &FileMgr; + mutable llvm::BumpPtrAllocator ContentCacheAlloc; /// FileInfos - Memoized information about all of the files tracked by this @@ -427,15 +429,15 @@ class SourceManager { explicit SourceManager(const SourceManager&); void operator=(const SourceManager&); public: - SourceManager(Diagnostic &Diag) - : Diag(Diag), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0) { - clearIDTables(); - } + SourceManager(Diagnostic &Diag, FileManager &FileMgr); ~SourceManager(); void clearIDTables(); + Diagnostic &getDiagnostics() const { return Diag; } + + FileManager &getFileManager() const { return FileMgr; } + //===--------------------------------------------------------------------===// // MainFileID creation and querying methods. //===--------------------------------------------------------------------===// @@ -450,6 +452,13 @@ public: return MainFileID; } + /// \brief Set the file ID for the precompiled preamble, which is also the + /// main file. + void SetPreambleFileID(FileID Preamble) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = Preamble; + } + //===--------------------------------------------------------------------===// // Methods to create new FileID's and instantiations. //===--------------------------------------------------------------------===// @@ -464,7 +473,7 @@ public: unsigned PreallocatedID = 0, unsigned Offset = 0) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); - if (IR == 0) return FileID(); // Error opening file? + assert(IR && "getOrCreateContentCache() cannot return NULL"); return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset); } @@ -514,9 +523,7 @@ public: /// /// \param DoNotFree If true, then the buffer will not be freed when the /// source manager is destroyed. - /// - /// \returns true if an error occurred, false otherwise. - bool overrideFileContents(const FileEntry *SourceFile, + void overrideFileContents(const FileEntry *SourceFile, const llvm::MemoryBuffer *Buffer, bool DoNotFree = false); @@ -715,6 +722,11 @@ public: /// /// Note that a presumed location is always given as the instantiation point /// of an instantiation location, not at the spelling location. + /// + /// \returns The presumed location of the specified SourceLocation. If the + /// presumed location cannot be calculate (e.g., because \p Loc is invalid + /// or the file containing \p Loc has changed on disk), returns an invalid + /// presumed location. PresumedLoc getPresumedLoc(SourceLocation Loc) const; /// isFromSameFile - Returns true if both SourceLocations correspond to @@ -771,7 +783,7 @@ public: /// If the source file is included multiple times, the source location will /// be based upon the first inclusion. SourceLocation getLocation(const FileEntry *SourceFile, - unsigned Line, unsigned Col) const; + unsigned Line, unsigned Col); /// \brief Determines the order of 2 source locations in the translation unit. /// diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index e757a2f4a185..e6b6218100ad 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -95,6 +95,23 @@ namespace clang { VK_XValue }; + /// A further classification of the kind of object referenced by an + /// l-value or x-value. + enum ExprObjectKind { + /// An ordinary object is located at an address in memory. + OK_Ordinary, + + /// A bitfield object is a bitfield on a C or C++ record. + OK_BitField, + + /// A vector component is an element or range of elements on a vector. + OK_VectorComponent, + + /// An Objective C property is a logical field of an Objective-C + /// object which is read and written via Objective C method calls. + OK_ObjCProperty + }; + // \brief Describes the kind of template specialization that a // particular template specialization declaration represents. enum TemplateSpecializationKind { diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 4aa055e695e9..be0d8ff091e8 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -23,7 +23,7 @@ def ContinueStmt : Stmt; def BreakStmt : Stmt; def ReturnStmt : Stmt; def DeclStmt : Stmt; -def SwitchCase : Stmt; +def SwitchCase : Stmt<1>; def CaseStmt : DStmt<SwitchCase>; def DefaultStmt : DStmt<SwitchCase>; @@ -61,7 +61,9 @@ def MemberExpr : DStmt<Expr>; def CastExpr : DStmt<Expr, 1>; def BinaryOperator : DStmt<Expr>; def CompoundAssignOperator : DStmt<BinaryOperator>; -def ConditionalOperator : DStmt<Expr>; +def AbstractConditionalOperator : DStmt<Expr, 1>; +def ConditionalOperator : DStmt<AbstractConditionalOperator>; +def BinaryConditionalOperator : DStmt<AbstractConditionalOperator>; def ImplicitCastExpr : DStmt<CastExpr>; def ExplicitCastExpr : DStmt<CastExpr, 1>; def CStyleCastExpr : DStmt<ExplicitCastExpr>; @@ -76,7 +78,6 @@ def VAArgExpr : DStmt<Expr>; // GNU Extensions. def AddrLabelExpr : DStmt<Expr>; def StmtExpr : DStmt<Expr>; -def TypesCompatibleExpr : DStmt<Expr>; def ChooseExpr : DStmt<Expr>; def GNUNullExpr : DStmt<Expr>; @@ -100,16 +101,21 @@ def CXXNewExpr : DStmt<Expr>; def CXXDeleteExpr : DStmt<Expr>; def CXXPseudoDestructorExpr : DStmt<Expr>; def UnaryTypeTraitExpr : DStmt<Expr>; +def BinaryTypeTraitExpr : DStmt<Expr>; def DependentScopeDeclRefExpr : DStmt<Expr>; def CXXConstructExpr : DStmt<Expr>; def CXXBindTemporaryExpr : DStmt<Expr>; -def CXXExprWithTemporaries : DStmt<Expr>; +def ExprWithCleanups : DStmt<Expr>; def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>; def CXXUnresolvedConstructExpr : DStmt<Expr>; def CXXDependentScopeMemberExpr : DStmt<Expr>; def OverloadExpr : DStmt<Expr, 1>; def UnresolvedLookupExpr : DStmt<OverloadExpr>; def UnresolvedMemberExpr : DStmt<OverloadExpr>; +def CXXNoexceptExpr : DStmt<Expr>; +def PackExpansionExpr : DStmt<Expr>; +def SizeOfPackExpr : DStmt<Expr>; +def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>; // Obj-C Expressions. def ObjCStringLiteral : DStmt<Expr>; @@ -119,11 +125,17 @@ def ObjCSelectorExpr : DStmt<Expr>; def ObjCProtocolExpr : DStmt<Expr>; def ObjCIvarRefExpr : DStmt<Expr>; def ObjCPropertyRefExpr : DStmt<Expr>; -def ObjCImplicitSetterGetterRefExpr : DStmt<Expr>; -def ObjCSuperExpr : DStmt<Expr>; def ObjCIsaExpr : DStmt<Expr>; +// CUDA Expressions. +def CUDAKernelCallExpr : DStmt<CallExpr>; + // Clang Extensions. def ShuffleVectorExpr : DStmt<Expr>; def BlockExpr : DStmt<Expr>; def BlockDeclRefExpr : DStmt<Expr>; +def OpaqueValueExpr : DStmt<Expr>; + +// Microsoft Extensions. +def CXXUuidofExpr : DStmt<Expr>; + diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 40df9ba11da4..b9087f2c47e8 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -18,7 +18,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cassert> #include <vector> #include <string> @@ -64,6 +64,7 @@ protected: bool TLSSupported; bool NoAsmVariants; // True if {|} are normal characters. unsigned char PointerWidth, PointerAlign; + unsigned char BoolWidth, BoolAlign; unsigned char IntWidth, IntAlign; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; @@ -73,6 +74,7 @@ protected: unsigned char LongLongWidth, LongLongAlign; const char *DescriptionString; const char *UserLabelPrefix; + const char *MCountName; const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI CXXABI; @@ -139,7 +141,7 @@ public: IntType getSigAtomicType() const { return SigAtomicType; } - /// getTypeWidth - Return the width (in bits) of the specified integer type + /// getTypeWidth - Return the width (in bits) of the specified integer type /// enum. For example, SignedInt -> getIntWidth(). unsigned getTypeWidth(IntType T) const; @@ -149,7 +151,7 @@ public: /// isTypeSigned - Return whether an integer types is signed. Returns true if /// the type is signed; false otherwise. - bool isTypeSigned(IntType T) const; + static bool isTypeSigned(IntType T); /// getPointerWidth - Return the width of pointers on this target, for the /// specified address space. @@ -162,8 +164,8 @@ public: /// 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 getBoolWidth() const { return BoolWidth; } + unsigned getBoolAlign() const { return BoolAlign; } unsigned getCharWidth() const { return 8; } // FIXME unsigned getCharAlign() const { return 8; } // FIXME @@ -240,6 +242,11 @@ public: return UserLabelPrefix; } + /// MCountName - This returns name of the mcount instrumentation function. + const char *getMCountName() const { + return MCountName; + } + bool useBitFieldTypeAlignment() const { return UseBitFieldTypeAlignment; } @@ -306,7 +313,7 @@ public: std::string Name; // Operand name: [foo] with no []'s. public: ConstraintInfo(llvm::StringRef ConstraintStr, llvm::StringRef Name) - : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), + : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), Name(Name.str()) {} const std::string &getConstraintStr() const { return ConstraintStr; } @@ -356,6 +363,9 @@ public: unsigned NumOutputs, unsigned &Index) const; virtual std::string convertConstraint(const char Constraint) const { + // 'p' defaults to 'r', but can be overridden by targets. + if (Constraint == 'p') + return std::string("r"); return std::string(1, Constraint); } @@ -391,7 +401,7 @@ public: return "__OBJC,__cstring_object,regular,no_dead_strip"; } - /// getNSStringNonFragileABISection - Return the section to use for + /// getNSStringNonFragileABISection - Return the section to use for /// NSString literals, or 0 if no special section is used (NonFragile ABI). virtual const char *getNSStringNonFragileABISection() const { return "__DATA, __objc_stringobj, regular, no_dead_strip"; @@ -499,7 +509,7 @@ public: bool isTLSSupported() const { return TLSSupported; } - + /// hasNoAsmVariants - Return true if {|} are normal characters in the /// asm string. If this returns false (the default), then {abc|xyz} is syntax /// that says that when compiling for asm variant #0, "abc" should be @@ -508,19 +518,18 @@ public: bool hasNoAsmVariants() const { return NoAsmVariants; } - + /// getEHDataRegisterNumber - Return the register number that /// __builtin_eh_return_regno would return with the specified argument. virtual int getEHDataRegisterNumber(unsigned RegNo) const { - return -1; + return -1; } - - /// getStaticInitSectionSpecifier - Return the section to use for C++ static + + /// getStaticInitSectionSpecifier - Return the section to use for C++ static /// initialization functions. virtual const char *getStaticInitSectionSpecifier() const { return 0; } - protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return PointerWidth; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index dc360adf8f19..b84b04da3de2 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -103,6 +103,7 @@ TOK(comment) // Comment (only in -E -C[C] mode) // C99 6.4.2: Identifiers. TOK(identifier) // abcde123 +TOK(raw_identifier) // Used only in raw lexing mode. // C99 6.4.4.1: Integer Constants // C99 6.4.4.2: Floating Constants @@ -175,6 +176,10 @@ PUNCTUATOR(coloncolon, "::") // Objective C support. PUNCTUATOR(at, "@") +// CUDA support. +PUNCTUATOR(lesslessless, "<<<") +PUNCTUATOR(greatergreatergreater, ">>>") + // C99 6.4.1: Keywords. These turn into kw_* tokens. // Flags allowed: // KEYALL - This is a keyword in all variants of C and C++, or it @@ -183,9 +188,12 @@ PUNCTUATOR(at, "@") // KEYC99 - This is a keyword introduced to C in C99 // KEYCXX - This is a C++ keyword, or a C++-specific keyword in the // implementation namespace +// KEYNOCXX - This is a keyword in every non-C++ dialect. // KEYCXX0X - This is a C++ keyword introduced to C++ in C++0x // KEYGNU - This is a keyword if GNU extensions are enabled // KEYMS - This is a keyword if Microsoft extensions are enabled +// KEYOPENCL - This is a keyword in OpenCL +// KEYALTIVEC - This is a keyword in AltiVec // KEYBORLAND - This is a keyword if Borland extensions are enabled // KEYWORD(auto , KEYALL) @@ -222,7 +230,7 @@ KEYWORD(unsigned , KEYALL) KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) -KEYWORD(_Bool , KEYNOMS) +KEYWORD(_Bool , KEYNOCXX) KEYWORD(_Complex , KEYALL) KEYWORD(_Imaginary , KEYALL) KEYWORD(__func__ , KEYALL) @@ -278,6 +286,7 @@ KEYWORD(char16_t , KEYCXX0X) KEYWORD(char32_t , KEYCXX0X) KEYWORD(constexpr , KEYCXX0X) KEYWORD(decltype , KEYCXX0X) +KEYWORD(noexcept , KEYCXX0X) KEYWORD(nullptr , KEYCXX0X) KEYWORD(static_assert , KEYCXX0X) KEYWORD(thread_local , KEYCXX0X) @@ -316,6 +325,7 @@ KEYWORD(__has_virtual_destructor , KEYCXX) KEYWORD(__is_abstract , KEYCXX) KEYWORD(__is_base_of , KEYCXX) KEYWORD(__is_class , KEYCXX) +KEYWORD(__is_convertible_to , KEYCXX) KEYWORD(__is_empty , KEYCXX) KEYWORD(__is_enum , KEYCXX) KEYWORD(__is_pod , KEYCXX) @@ -323,7 +333,6 @@ KEYWORD(__is_polymorphic , KEYCXX) KEYWORD(__is_union , KEYCXX) // Tentative name - there's no implementation of std::is_literal_type yet. KEYWORD(__is_literal , KEYCXX) -// FIXME: Add MS's traits, too. // Apple Extension. KEYWORD(__private_extern__ , KEYALL) @@ -336,7 +345,11 @@ KEYWORD(__fastcall , KEYALL) KEYWORD(__thiscall , KEYALL) KEYWORD(__forceinline , KEYALL) -// Borland Extension. +// OpenCL-specific keywords (see OpenCL 1.1 [6.1.9]) +KEYWORD(__kernel , KEYOPENCL) +ALIAS("kernel", __kernel , KEYOPENCL) + +// Borland Extensions. KEYWORD(__pascal , KEYALL) // Altivec Extension. @@ -356,6 +369,7 @@ ALIAS("__complex__" , _Complex , KEYALL) ALIAS("__imag__" , __imag , KEYALL) ALIAS("__inline" , inline , KEYALL) ALIAS("__inline__" , inline , KEYALL) +ALIAS("__nullptr" , nullptr , KEYCXX) ALIAS("__real__" , __real , KEYALL) ALIAS("__restrict" , restrict , KEYALL) ALIAS("__restrict__" , restrict , KEYALL) @@ -369,15 +383,23 @@ ALIAS("__volatile__" , volatile , KEYALL) // Microsoft extensions which should be disabled in strict conformance mode KEYWORD(__ptr64 , KEYMS) KEYWORD(__w64 , KEYMS) +KEYWORD(__uuidof , KEYMS | KEYBORLAND) ALIAS("_asm" , asm , KEYMS) -ALIAS("_cdecl" , __cdecl , KEYMS) -ALIAS("_fastcall" , __fastcall , KEYMS) -ALIAS("_stdcall" , __stdcall , KEYMS) +ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND) +ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND) +ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND) ALIAS("_thiscall" , __thiscall , KEYMS) +ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND) +ALIAS("_inline" , inline , KEYMS) // Borland Extensions which should be disabled in strict conformance mode. ALIAS("_pascal" , __pascal , KEYBORLAND) +// Clang Extensions. +ALIAS("__char16_t" , char16_t , KEYCXX) +ALIAS("__char32_t" , char32_t , KEYCXX) + + //===----------------------------------------------------------------------===// // Objective-C @-preceeded keywords. //===----------------------------------------------------------------------===// @@ -421,6 +443,12 @@ ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly ANNOTATION(template_id) // annotation for a C++ template-id that names a // function template specialization (not a type), // e.g., "std::swap<int>" + +// Annotation for #pragma unused(...) +// For each argument inside the parentheses the pragma handler will produce +// one 'pragma_unused' annotation token followed by the argument token. +ANNOTATION(pragma_unused) + #undef ANNOTATION #undef OBJC2_AT_KEYWORD #undef OBJC1_AT_KEYWORD diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h index 85dc0671de62..515390a8ce93 100644 --- a/include/clang/Basic/TokenKinds.h +++ b/include/clang/Basic/TokenKinds.h @@ -43,6 +43,12 @@ enum ObjCKeywordKind { NUM_OBJC_KEYWORDS }; +/// OnOffSwitch - This defines the possible values of an on-off-switch +/// (C99 6.10.6p2). +enum OnOffSwitch { + OOS_ON, OOS_OFF, OOS_DEFAULT +}; + /// \brief Determines the name of a token as used within the front end. /// /// The name of a token will be an internal name (such as "l_square") diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 36b830069f86..00c6e9ed5000 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -36,6 +36,12 @@ namespace clang { UTT_IsLiteral }; + /// BinaryTypeTrait - Names for the binary type traits. + enum BinaryTypeTrait { + BTT_IsBaseOf, + BTT_TypeCompatible, + BTT_IsConvertibleTo + }; } #endif diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h index 9948677662cd..ede68ed50d52 100644 --- a/include/clang/Basic/Version.h +++ b/include/clang/Basic/Version.h @@ -44,7 +44,7 @@ namespace clang { /// \brief Retrieves the repository path (e.g., Subversion path) that /// identifies the particular Clang branch, tag, or trunk from which this /// Clang was built. - llvm::StringRef getClangRepositoryPath(); + std::string getClangRepositoryPath(); /// \brief Retrieves the repository revision number (or identifer) from which /// this Clang was built. diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h new file mode 100644 index 000000000000..90e288a224ec --- /dev/null +++ b/include/clang/Basic/Visibility.h @@ -0,0 +1,48 @@ +//===--- Visibility.h - Visibility enumeration and utilities ----*- 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 Visibility enumeration and various utility +// functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VISIBILITY_H +#define LLVM_CLANG_BASIC_VISIBILITY_H + +namespace clang { + +/// \link Describes the different kinds of visibility that a +/// declaration may have. Visibility determines how a declaration +/// interacts with the dynamic linker. It may also affect whether the +/// symbol can be found by runtime symbol lookup APIs. +/// +/// Visibility is not described in any language standard and +/// (nonetheless) sometimes has odd behavior. Not all platforms +/// support all visibility kinds. +enum Visibility { + /// Objects with "hidden" visibility are not seen by the dynamic + /// linker. + HiddenVisibility, + + /// Objects with "protected" visibility are seen by the dynamic + /// linker but always dynamically resolve to an object within this + /// shared object. + ProtectedVisibility, + + /// Objects with "default" visibility are seen by the dynamic linker + /// and act like normal objects. + DefaultVisibility +}; + +inline Visibility minVisibility(Visibility L, Visibility R) { + return L < R ? L : R; +} + +} + +#endif // LLVM_CLANG_BASIC_VISIBILITY_H diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td index fa6ebb756ca3..880a0da6bc68 100644 --- a/include/clang/Basic/arm_neon.td +++ b/include/clang/Basic/arm_neon.td @@ -16,13 +16,34 @@ class Op; def OP_NONE : Op; def OP_ADD : Op; +def OP_ADDL : Op; +def OP_ADDW : Op; def OP_SUB : Op; +def OP_SUBL : Op; +def OP_SUBW : Op; def OP_MUL : Op; +def OP_MULL : Op; def OP_MLA : Op; +def OP_MLAL : Op; def OP_MLS : Op; +def OP_MLSL : Op; def OP_MUL_N : Op; +def OP_MULL_N: Op; def OP_MLA_N : Op; def OP_MLS_N : Op; +def OP_MLAL_N : Op; +def OP_MLSL_N : Op; +def OP_MUL_LN: Op; +def OP_MULL_LN : Op; +def OP_MLA_LN: Op; +def OP_MLS_LN: Op; +def OP_MLAL_LN : Op; +def OP_MLSL_LN : Op; +def OP_QDMULL_LN : Op; +def OP_QDMLAL_LN : Op; +def OP_QDMLSL_LN : Op; +def OP_QDMULH_LN : Op; +def OP_QRDMULH_LN : Op; def OP_EQ : Op; def OP_GE : Op; def OP_LE : Op; @@ -40,22 +61,31 @@ def OP_HI : Op; def OP_LO : Op; def OP_CONC : Op; def OP_DUP : Op; +def OP_DUP_LN: Op; def OP_SEL : Op; def OP_REV64 : Op; def OP_REV32 : Op; def OP_REV16 : Op; +def OP_REINT : Op; +def OP_ABDL : Op; +def OP_ABA : Op; +def OP_ABAL : Op; -class Inst <string p, string t, Op o> { +class Inst <string n, string p, string t, Op o> { + string Name = n; string Prototype = p; string Types = t; Op Operand = o; bit isShift = 0; } -// Used to generate Builtins.def -class SInst<string p, string t> : Inst<p, t, OP_NONE> {} -class IInst<string p, string t> : Inst<p, t, OP_NONE> {} -class WInst<string p, string t> : Inst<p, t, OP_NONE> {} +// Used to generate Builtins.def: +// SInst: Instruction with signed/unsigned suffix (e.g., "s8", "u8", "p8") +// IInst: Instruction with generic integer suffix (e.g., "i8") +// WInst: Instruction with only bit size suffix (e.g., "8") +class SInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class IInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class WInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} // prototype: return (arg, arg, ...) // v: void @@ -93,251 +123,273 @@ class WInst<string p, string t> : Inst<p, t, OP_NONE> {} //////////////////////////////////////////////////////////////////////////////// // E.3.1 Addition -def VADD : Inst<"ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_ADD>; -def VADDL : SInst<"wdd", "csiUcUsUi">; -def VADDW : SInst<"wwd", "csiUcUsUi">; -def VHADD : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VRHADD : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VQADD : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VADDHN : IInst<"dww", "csiUcUsUi">; -def VRADDHN : IInst<"dww", "csiUcUsUi">; +def VADD : Inst<"vadd", "ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_ADD>; +def VADDL : Inst<"vaddl", "wdd", "csiUcUsUi", OP_ADDL>; +def VADDW : Inst<"vaddw", "wwd", "csiUcUsUi", OP_ADDW>; +def VHADD : SInst<"vhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VRHADD : SInst<"vrhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VQADD : SInst<"vqadd", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VADDHN : IInst<"vaddhn", "hkk", "silUsUiUl">; +def VRADDHN : IInst<"vraddhn", "hkk", "silUsUiUl">; //////////////////////////////////////////////////////////////////////////////// // E.3.2 Multiplication -def VMUL : Inst<"ddd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_MUL>; -def VMLA : Inst<"dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLA>; -def VMLAL : SInst<"wwdd", "csiUcUsUi">; -def VMLS : Inst<"dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLS>; -def VMLSL : SInst<"wwdd", "csiUcUsUi">; -def VQDMULH : SInst<"ddd", "siQsQi">; -def VQRDMULH : SInst<"ddd", "siQsQi">; -def VQDMLAL : SInst<"wwdd", "si">; -def VQDMLSL : SInst<"wwdd", "si">; -def VMULL : SInst<"wdd", "csiUcUsUiPc">; -def VQDMULL : SInst<"wdd", "si">; +def VMUL : Inst<"vmul", "ddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MUL>; +def VMULP : SInst<"vmul", "ddd", "PcQPc">; +def VMLA : Inst<"vmla", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLA>; +def VMLAL : Inst<"vmlal", "wwdd", "csiUcUsUi", OP_MLAL>; +def VMLS : Inst<"vmls", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLS>; +def VMLSL : Inst<"vmlsl", "wwdd", "csiUcUsUi", OP_MLSL>; +def VQDMULH : SInst<"vqdmulh", "ddd", "siQsQi">; +def VQRDMULH : SInst<"vqrdmulh", "ddd", "siQsQi">; +def VQDMLAL : SInst<"vqdmlal", "wwdd", "si">; +def VQDMLSL : SInst<"vqdmlsl", "wwdd", "si">; +def VMULL : Inst<"vmull", "wdd", "csiUcUsUi", OP_MULL>; +def VMULLP : SInst<"vmull", "wdd", "Pc">; +def VQDMULL : SInst<"vqdmull", "wdd", "si">; //////////////////////////////////////////////////////////////////////////////// // E.3.3 Subtraction -def VSUB : Inst<"ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_SUB>; -def VSUBL : SInst<"wdd", "csiUcUsUi">; -def VSUBW : SInst<"wwd", "csiUcUsUi">; -def VQSUB : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VHSUB : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VSUBHN : IInst<"dww", "csiUcUsUi">; -def VRSUBHN : IInst<"dww", "csiUcUsUi">; +def VSUB : Inst<"vsub", "ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_SUB>; +def VSUBL : Inst<"vsubl", "wdd", "csiUcUsUi", OP_SUBL>; +def VSUBW : Inst<"vsubw", "wwd", "csiUcUsUi", OP_SUBW>; +def VQSUB : SInst<"vqsub", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VHSUB : SInst<"vhsub", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VSUBHN : IInst<"vsubhn", "hkk", "silUsUiUl">; +def VRSUBHN : IInst<"vrsubhn", "hkk", "silUsUiUl">; //////////////////////////////////////////////////////////////////////////////// // E.3.4 Comparison -def VCEQ : Inst<"udd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_EQ>; -def VCGE : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GE>; -def VCLE : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LE>; -def VCGT : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GT>; -def VCLT : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LT>; -def VCAGE : IInst<"udd", "fQf">; -def VCALE : IInst<"udd", "fQf">; -def VCAGT : IInst<"udd", "fQf">; -def VCALT : IInst<"udd", "fQf">; -def VTST : WInst<"udd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc">; +def VCEQ : Inst<"vceq", "udd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_EQ>; +def VCGE : Inst<"vcge", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GE>; +def VCLE : Inst<"vcle", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LE>; +def VCGT : Inst<"vcgt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GT>; +def VCLT : Inst<"vclt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LT>; +def VCAGE : IInst<"vcage", "udd", "fQf">; +def VCALE : IInst<"vcale", "udd", "fQf">; +def VCAGT : IInst<"vcagt", "udd", "fQf">; +def VCALT : IInst<"vcalt", "udd", "fQf">; +def VTST : WInst<"vtst", "udd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc">; //////////////////////////////////////////////////////////////////////////////// // E.3.5 Absolute Difference -def VABD : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; -def VABDL : SInst<"wdd", "csiUcUsUi">; -def VABA : SInst<"dddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VABAL : SInst<"wwdd", "csiUcUsUi">; +def VABD : SInst<"vabd", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VABDL : Inst<"vabdl", "wdd", "csiUcUsUi", OP_ABDL>; +def VABA : Inst<"vaba", "dddd", "csiUcUsUiQcQsQiQUcQUsQUi", OP_ABA>; +def VABAL : Inst<"vabal", "wwdd", "csiUcUsUi", OP_ABAL>; //////////////////////////////////////////////////////////////////////////////// // E.3.6 Max/Min -def VMAX : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; -def VMIN : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VMAX : SInst<"vmax", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VMIN : SInst<"vmin", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; //////////////////////////////////////////////////////////////////////////////// // E.3.7 Pairdise Addition -def VPADD : IInst<"ddd", "csiUcUsUif">; -def VPADDL : SInst<"nd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VPADAL : SInst<"nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VPADD : IInst<"vpadd", "ddd", "csiUcUsUif">; +def VPADDL : SInst<"vpaddl", "nd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VPADAL : SInst<"vpadal", "nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; //////////////////////////////////////////////////////////////////////////////// // E.3.8-9 Folding Max/Min -def VPMAX : SInst<"ddd", "csiUcUsUif">; -def VPMIN : SInst<"ddd", "csiUcUsUif">; +def VPMAX : SInst<"vpmax", "ddd", "csiUcUsUif">; +def VPMIN : SInst<"vpmin", "ddd", "csiUcUsUif">; //////////////////////////////////////////////////////////////////////////////// // E.3.10 Reciprocal/Sqrt -def VRECPS : IInst<"ddd", "fQf">; -def VRSQRTS : IInst<"ddd", "fQf">; +def VRECPS : IInst<"vrecps", "ddd", "fQf">; +def VRSQRTS : IInst<"vrsqrts", "ddd", "fQf">; //////////////////////////////////////////////////////////////////////////////// // E.3.11 Shifts by signed variable -def VSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQRSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSHL : SInst<"vshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL : SInst<"vqshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHL : SInst<"vrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQRSHL : SInst<"vqrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; //////////////////////////////////////////////////////////////////////////////// // E.3.12 Shifts by constant let isShift = 1 in { -def VSHR_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VSHL_N : IInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSHR_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VSRA_N : SInst<"dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSRA_N : SInst<"dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHL_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHLU_N : SInst<"udi", "csilQcQsQiQl">; -def VSHRN_N : IInst<"hki", "silUsUiUl">; -def VQSHRUN_N : SInst<"eki", "sil">; -def VQRSHRUN_N : SInst<"eki", "sil">; -def VQSHRN_N : SInst<"hki", "silUsUiUl">; -def VRSHRN_N : IInst<"hki", "silUsUiUl">; -def VQRSHRN_N : SInst<"hki", "silUsUiUl">; -def VSHLL_N : SInst<"wdi", "csiUcUsUi">; +def VSHR_N : SInst<"vshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSHL_N : IInst<"vshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHR_N : SInst<"vrshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSRA_N : SInst<"vsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSRA_N : SInst<"vrsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL_N : SInst<"vqshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHLU_N : SInst<"vqshlu_n", "udi", "csilQcQsQiQl">; +def VSHRN_N : IInst<"vshrn_n", "hki", "silUsUiUl">; +def VQSHRUN_N : SInst<"vqshrun_n", "eki", "sil">; +def VQRSHRUN_N : SInst<"vqrshrun_n", "eki", "sil">; +def VQSHRN_N : SInst<"vqshrn_n", "hki", "silUsUiUl">; +def VRSHRN_N : IInst<"vrshrn_n", "hki", "silUsUiUl">; +def VQRSHRN_N : SInst<"vqrshrn_n", "hki", "silUsUiUl">; +def VSHLL_N : SInst<"vshll_n", "wdi", "csiUcUsUi">; //////////////////////////////////////////////////////////////////////////////// // E.3.13 Shifts with insert -def VSRI_N : WInst<"dddi", "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; -def VSLI_N : WInst<"dddi", "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +def VSRI_N : WInst<"vsri_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +def VSLI_N : WInst<"vsli_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; } //////////////////////////////////////////////////////////////////////////////// // E.3.14 Loads and stores of a single vector -def VLD1 : WInst<"dc", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD1_LANE : WInst<"dcdi", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD1_DUP : WInst<"dc", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST1 : WInst<"vpd", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST1_LANE : WInst<"vpdi", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1 : WInst<"vld1", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_LANE : WInst<"vld1_lane", "dcdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_DUP : WInst<"vld1_dup", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1 : WInst<"vst1", "vpd", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1_LANE : WInst<"vst1_lane", "vpdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; //////////////////////////////////////////////////////////////////////////////// // E.3.15 Loads and stores of an N-element structure -def VLD2 : WInst<"2c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD3 : WInst<"3c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD4 : WInst<"4c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD2_DUP : WInst<"2c", "UcUsUiUlcsilhfPcPs">; -def VLD3_DUP : WInst<"3c", "UcUsUiUlcsilhfPcPs">; -def VLD4_DUP : WInst<"4c", "UcUsUiUlcsilhfPcPs">; -def VLD2_LANE : WInst<"2c2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VLD3_LANE : WInst<"3c3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VLD4_LANE : WInst<"4c4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST2 : WInst<"vp2", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST3 : WInst<"vp3", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST4 : WInst<"vp4", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST2_LANE : WInst<"vp2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST3_LANE : WInst<"vp3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST4_LANE : WInst<"vp4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD2 : WInst<"vld2", "2c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD3 : WInst<"vld3", "3c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD4 : WInst<"vld4", "4c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD2_DUP : WInst<"vld2_dup", "2c", "UcUsUiUlcsilhfPcPs">; +def VLD3_DUP : WInst<"vld3_dup", "3c", "UcUsUiUlcsilhfPcPs">; +def VLD4_DUP : WInst<"vld4_dup", "4c", "UcUsUiUlcsilhfPcPs">; +def VLD2_LANE : WInst<"vld2_lane", "2c2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD3_LANE : WInst<"vld3_lane", "3c3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD4_LANE : WInst<"vld4_lane", "4c4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST2 : WInst<"vst2", "vp2", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST3 : WInst<"vst3", "vp3", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST4 : WInst<"vst4", "vp4", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST2_LANE : WInst<"vst2_lane", "vp2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST3_LANE : WInst<"vst3_lane", "vp3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST4_LANE : WInst<"vst4_lane", "vp4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; //////////////////////////////////////////////////////////////////////////////// // E.3.16 Extract lanes from a vector -def VGET_LANE : IInst<"sdi", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; +def VGET_LANE : IInst<"vget_lane", "sdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; //////////////////////////////////////////////////////////////////////////////// // E.3.17 Set lanes within a vector -def VSET_LANE : IInst<"dsdi", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; +def VSET_LANE : IInst<"vset_lane", "dsdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; //////////////////////////////////////////////////////////////////////////////// // E.3.18 Initialize a vector from bit pattern -def VCREATE: Inst<"dl", "csihfUcUsUiUlPcPsl", OP_CAST>; +def VCREATE: Inst<"vcreate", "dl", "csihfUcUsUiUlPcPsl", OP_CAST>; //////////////////////////////////////////////////////////////////////////////// // E.3.19 Set all lanes to same value -def VDUP_N : Inst<"ds", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; -def VMOV_N : Inst<"ds", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; -def VDUP_LANE : WInst<"dgi", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; +def VDUP_N : Inst<"vdup_n", "ds", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; +def VMOV_N : Inst<"vmov_n", "ds", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; +def VDUP_LANE : Inst<"vdup_lane", "dgi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl",OP_DUP_LN>; //////////////////////////////////////////////////////////////////////////////// // E.3.20 Combining vectors -def VCOMBINE : Inst<"kdd", "csilhfUcUsUiUlPcPs", OP_CONC>; +def VCOMBINE : Inst<"vcombine", "kdd", "csilhfUcUsUiUlPcPs", OP_CONC>; //////////////////////////////////////////////////////////////////////////////// // E.3.21 Splitting vectors -def VGET_HIGH : Inst<"dk", "csilhfUcUsUiUlPcPs", OP_HI>; -def VGET_LOW : Inst<"dk", "csilhfUcUsUiUlPcPs", OP_LO>; +def VGET_HIGH : Inst<"vget_high", "dk", "csilhfUcUsUiUlPcPs", OP_HI>; +def VGET_LOW : Inst<"vget_low", "dk", "csilhfUcUsUiUlPcPs", OP_LO>; //////////////////////////////////////////////////////////////////////////////// // E.3.22 Converting vectors -def VCVT_S32 : SInst<"xd", "fQf">; -def VCVT_U32 : SInst<"ud", "fQf">; -def VCVT_F16 : SInst<"hk", "f">; -def VCVT_N_S32 : SInst<"xdi", "fQf">; -def VCVT_N_U32 : SInst<"udi", "fQf">; -def VCVT_F32 : SInst<"fd", "iUiQiQUi">; -def VCVT_F32_F16 : SInst<"kh", "f">; -def VCVT_N_F32 : SInst<"fdi", "iUiQiQUi">; -def VMOVN : IInst<"hk", "silUsUiUl">; -def VMOVL : SInst<"wd", "csiUcUsUi">; -def VQMOVN : SInst<"hk", "silUsUiUl">; -def VQMOVUN : SInst<"ek", "sil">; +def VCVT_S32 : SInst<"vcvt_s32", "xd", "fQf">; +def VCVT_U32 : SInst<"vcvt_u32", "ud", "fQf">; +def VCVT_F16 : SInst<"vcvt_f16", "hk", "f">; +def VCVT_N_S32 : SInst<"vcvt_n_s32", "xdi", "fQf">; +def VCVT_N_U32 : SInst<"vcvt_n_u32", "udi", "fQf">; +def VCVT_F32 : SInst<"vcvt_f32", "fd", "iUiQiQUi">; +def VCVT_F32_F16 : SInst<"vcvt_f32_f16", "fd", "h">; +def VCVT_N_F32 : SInst<"vcvt_n_f32", "fdi", "iUiQiQUi">; +def VMOVN : IInst<"vmovn", "hk", "silUsUiUl">; +def VMOVL : SInst<"vmovl", "wd", "csiUcUsUi">; +def VQMOVN : SInst<"vqmovn", "hk", "silUsUiUl">; +def VQMOVUN : SInst<"vqmovun", "ek", "sil">; //////////////////////////////////////////////////////////////////////////////// // E.3.23-24 Table lookup, Extended table lookup -def VTBL1 : WInst<"ddt", "UccPc">; -def VTBL2 : WInst<"d2t", "UccPc">; -def VTBL3 : WInst<"d3t", "UccPc">; -def VTBL4 : WInst<"d4t", "UccPc">; -def VTBX1 : WInst<"dddt", "UccPc">; -def VTBX2 : WInst<"dd2t", "UccPc">; -def VTBX3 : WInst<"dd3t", "UccPc">; -def VTBX4 : WInst<"dd4t", "UccPc">; +def VTBL1 : WInst<"vtbl1", "ddt", "UccPc">; +def VTBL2 : WInst<"vtbl2", "d2t", "UccPc">; +def VTBL3 : WInst<"vtbl3", "d3t", "UccPc">; +def VTBL4 : WInst<"vtbl4", "d4t", "UccPc">; +def VTBX1 : WInst<"vtbx1", "dddt", "UccPc">; +def VTBX2 : WInst<"vtbx2", "dd2t", "UccPc">; +def VTBX3 : WInst<"vtbx3", "dd3t", "UccPc">; +def VTBX4 : WInst<"vtbx4", "dd4t", "UccPc">; //////////////////////////////////////////////////////////////////////////////// // E.3.25 Operations with a scalar value -def VMLA_LANE : IInst<"ddddi", "siUsUifQsQiQUsQUiQf">; -def VMLAL_LANE : SInst<"wwddi", "siUsUi">; -def VQDMLAL_LANE : SInst<"wwddi", "si">; -def VMLS_LANE : IInst<"ddddi", "siUsUifQsQiQUsQUiQf">; -def VMLSL_LANE : SInst<"wwddi", "siUsUi">; -def VQDMLSL_LANE : SInst<"wwddi", "si">; -def VMUL_N : Inst<"dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>; -def VMULL_N : SInst<"wda", "siUsUi">; -def VMULL_LANE : SInst<"wddi", "siUsUi">; -def VQDMULL_N : SInst<"wda", "si">; -def VQDMULL_LANE : SInst<"wddi", "si">; -def VQDMULH_N : SInst<"dda", "siQsQi">; -def VQDMULH_LANE : SInst<"dddi", "siQsQi">; -def VQRDMULH_N : SInst<"dda", "siQsQi">; -def VQRDMULH_LANE : SInst<"dddi", "siQsQi">; -def VMLA_N : Inst<"ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>; -def VMLAL_N : SInst<"wwda", "siUsUi">; -def VQDMLAL_N : SInst<"wwda", "si">; -def VMLS_N : Inst<"ddds", "siUsUifQsQiQUsQUiQf", OP_MLS_N>; -def VMLSL_N : SInst<"wwda", "siUsUi">; -def VQDMLSL_N : SInst<"wwda", "si">; +def VMLA_LANE : Inst<"vmla_lane", "dddgi", "siUsUifQsQiQUsQUiQf", OP_MLA_LN>; +def VMLAL_LANE : Inst<"vmlal_lane", "wwddi", "siUsUi", OP_MLAL_LN>; +def VQDMLAL_LANE : Inst<"vqdmlal_lane", "wwddi", "si", OP_QDMLAL_LN>; +def VMLS_LANE : Inst<"vmls_lane", "dddgi", "siUsUifQsQiQUsQUiQf", OP_MLS_LN>; +def VMLSL_LANE : Inst<"vmlsl_lane", "wwddi", "siUsUi", OP_MLSL_LN>; +def VQDMLSL_LANE : Inst<"vqdmlsl_lane", "wwddi", "si", OP_QDMLSL_LN>; +def VMUL_N : Inst<"vmul_n", "dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>; +def VMUL_LANE : Inst<"vmul_lane", "ddgi", "sifUsUiQsQiQfQUsQUi", OP_MUL_LN>; +def VMULL_N : Inst<"vmull_n", "wda", "siUsUi", OP_MULL_N>; +def VMULL_LANE : Inst<"vmull_lane", "wddi", "siUsUi", OP_MULL_LN>; +def VQDMULL_N : SInst<"vqdmull_n", "wda", "si">; +def VQDMULL_LANE : Inst<"vqdmull_lane", "wddi", "si", OP_QDMULL_LN>; +def VQDMULH_N : SInst<"vqdmulh_n", "dda", "siQsQi">; +def VQDMULH_LANE : Inst<"vqdmulh_lane", "ddgi", "siQsQi", OP_QDMULH_LN>; +def VQRDMULH_N : SInst<"vqrdmulh_n", "dda", "siQsQi">; +def VQRDMULH_LANE : Inst<"vqrdmulh_lane", "ddgi", "siQsQi", OP_QRDMULH_LN>; +def VMLA_N : Inst<"vmla_n", "ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>; +def VMLAL_N : Inst<"vmlal_n", "wwda", "siUsUi", OP_MLAL_N>; +def VQDMLAL_N : SInst<"vqdmlal_n", "wwda", "si">; +def VMLS_N : Inst<"vmls_n", "ddds", "siUsUifQsQiQUsQUiQf", OP_MLS_N>; +def VMLSL_N : Inst<"vmlsl_n", "wwda", "siUsUi", OP_MLSL_N>; +def VQDMLSL_N : SInst<"vqdmlsl_n", "wwda", "si">; //////////////////////////////////////////////////////////////////////////////// // E.3.26 Vector Extract -def VEXT : WInst<"dddi", "cUcPcsUsPsiUilUlQcQUcQPcQsQUsQPsQiQUiQlQUl">; +def VEXT : WInst<"vext", "dddi", + "cUcPcsUsPsiUilUlfQcQUcQPcQsQUsQPsQiQUiQlQUlQf">; //////////////////////////////////////////////////////////////////////////////// // E.3.27 Reverse vector elements (sdap endianness) -def VREV64 : Inst<"dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", OP_REV64>; -def VREV32 : Inst<"dd", "csUcUsPcQcQsQUcQUsQPc", OP_REV32>; -def VREV16 : Inst<"dd", "cUcPcQcQUcQPc", OP_REV16>; +def VREV64 : Inst<"vrev64", "dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", + OP_REV64>; +def VREV32 : Inst<"vrev32", "dd", "csUcUsPcPsQcQsQUcQUsQPcQPs", OP_REV32>; +def VREV16 : Inst<"vrev16", "dd", "cUcPcQcQUcQPc", OP_REV16>; //////////////////////////////////////////////////////////////////////////////// // E.3.28 Other single operand arithmetic -def VABS : SInst<"dd", "csifQcQsQiQf">; -def VQABS : SInst<"dd", "csiQcQsQi">; -def VNEG : Inst<"dd", "csifQcQsQiQf", OP_NEG>; -def VQNEG : SInst<"dd", "csiQcQsQi">; -def VCLS : SInst<"dd", "csiQcQsQi">; -def VCLZ : IInst<"dd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VCNT : WInst<"dd", "UccPcQUcQcQPc">; -def VRECPE : SInst<"dd", "fUiQfQUi">; -def VRSQRTE : SInst<"dd", "fUiQfQUi">; +def VABS : SInst<"vabs", "dd", "csifQcQsQiQf">; +def VQABS : SInst<"vqabs", "dd", "csiQcQsQi">; +def VNEG : Inst<"vneg", "dd", "csifQcQsQiQf", OP_NEG>; +def VQNEG : SInst<"vqneg", "dd", "csiQcQsQi">; +def VCLS : SInst<"vcls", "dd", "csiQcQsQi">; +def VCLZ : IInst<"vclz", "dd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VCNT : WInst<"vcnt", "dd", "UccPcQUcQcQPc">; +def VRECPE : SInst<"vrecpe", "dd", "fUiQfQUi">; +def VRSQRTE : SInst<"vrsqrte", "dd", "fUiQfQUi">; //////////////////////////////////////////////////////////////////////////////// // E.3.29 Logical operations -def VMVN : Inst<"dd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc", OP_NOT>; -def VAND : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_AND>; -def VORR : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>; -def VEOR : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>; -def VBIC : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>; -def VORN : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>; -def VBSL : Inst<"dudd", "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs", OP_SEL>; +def VMVN : Inst<"vmvn", "dd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc", OP_NOT>; +def VAND : Inst<"vand", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_AND>; +def VORR : Inst<"vorr", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>; +def VEOR : Inst<"veor", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>; +def VBIC : Inst<"vbic", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>; +def VORN : Inst<"vorn", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>; +def VBSL : Inst<"vbsl", "dudd", + "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs", OP_SEL>; //////////////////////////////////////////////////////////////////////////////// // E.3.30 Transposition operations -def VTRN: WInst<"2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; -def VZIP: WInst<"2dd", "csUcUsfPcPsQcQsQiQUcQUsQUiQfQPcQPs">; -def VUZP: WInst<"2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VTRN : WInst<"vtrn", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VZIP : WInst<"vzip", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VUZP : WInst<"vuzp", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; //////////////////////////////////////////////////////////////////////////////// // E.3.31 Vector reinterpret cast operations +def VREINTERPRET + : Inst<"vreinterpret", "dd", + "csilUcUsUiUlhfPcPsQcQsQiQlQUcQUsQUiQUlQhQfQPcQPs", OP_REINT>; + diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt index e82cf429eecc..375ae5bdabc8 100644 --- a/include/clang/CMakeLists.txt +++ b/include/clang/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(AST) add_subdirectory(Basic) add_subdirectory(Driver) +add_subdirectory(Lex) add_subdirectory(Serialization) diff --git a/include/clang/Checker/AnalysisConsumer.h b/include/clang/Checker/AnalysisConsumer.h deleted file mode 100644 index c236766f0ac9..000000000000 --- a/include/clang/Checker/AnalysisConsumer.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header contains the functions necessary for a front-end to run various -// analyses. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_CHECKER_ANALYSISCONSUMER_H -#define LLVM_CLANG_CHECKER_ANALYSISCONSUMER_H - -#include <string> - -namespace clang { - -class AnalyzerOptions; -class ASTConsumer; -class Preprocessor; - -/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code -/// analysis passes. (The set of analyses run is controlled by command-line -/// options.) -ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp, - const std::string &output, - const AnalyzerOptions& Opts); - -} - -#endif diff --git a/include/clang/Checker/Checkers/LocalCheckers.h b/include/clang/Checker/Checkers/LocalCheckers.h deleted file mode 100644 index 4a9e381a7c15..000000000000 --- a/include/clang/Checker/Checkers/LocalCheckers.h +++ /dev/null @@ -1,61 +0,0 @@ -//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive 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 the interface to call a set of intra-procedural (local) -// checkers that use flow/path-sensitive analyses to find bugs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H -#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H - -namespace clang { - -class CFG; -class Decl; -class Diagnostic; -class ASTContext; -class PathDiagnosticClient; -class GRTransferFuncs; -class BugType; -class LangOptions; -class ParentMap; -class LiveVariables; -class BugReporter; -class ObjCImplementationDecl; -class LangOptions; -class GRExprEngine; -class TranslationUnitDecl; - -void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, - BugReporter& BR); - -GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); - -void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L, - BugReporter& BR); - -void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, - BugReporter& BR); - -void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR); - -void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D); -void RegisterExperimentalChecks(GRExprEngine &Eng); -void RegisterExperimentalInternalChecks(GRExprEngine &Eng); - -void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR); -void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR); -void CheckSizeofPointer(const Decl *D, BugReporter &BR); - -void RegisterCallInliner(GRExprEngine &Eng); -} // end namespace clang - -#endif diff --git a/include/clang/Checker/ManagerRegistry.h b/include/clang/Checker/ManagerRegistry.h deleted file mode 100644 index ebfd28e10930..000000000000 --- a/include/clang/Checker/ManagerRegistry.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- 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 ManagerRegistry and Register* classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H -#define LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H - -#include "clang/Checker/PathSensitive/GRState.h" - -namespace clang { - -/// ManagerRegistry - This class records manager creators registered at -/// runtime. The information is communicated to AnalysisManager through static -/// members. Better design is expected. - -class ManagerRegistry { -public: - static StoreManagerCreator StoreMgrCreator; - static ConstraintManagerCreator ConstraintMgrCreator; -}; - -/// RegisterConstraintManager - This class is used to setup the constraint -/// manager of the static analyzer. The constructor takes a creator function -/// pointer for creating the constraint manager. -/// -/// It is used like this: -/// -/// class MyConstraintManager {}; -/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) { -/// return new MyConstraintManager(statemgr); -/// } -/// RegisterConstraintManager X(CreateMyConstraintManager); - -class RegisterConstraintManager { -public: - RegisterConstraintManager(ConstraintManagerCreator CMC) { - assert(ManagerRegistry::ConstraintMgrCreator == 0 - && "ConstraintMgrCreator already set!"); - ManagerRegistry::ConstraintMgrCreator = CMC; - } -}; - -} -#endif diff --git a/include/clang/Checker/PathSensitive/GRAuditor.h b/include/clang/Checker/PathSensitive/GRAuditor.h deleted file mode 100644 index 015c82e80bb5..000000000000 --- a/include/clang/Checker/PathSensitive/GRAuditor.h +++ /dev/null @@ -1,35 +0,0 @@ -//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface -// to audit the creation of ExplodedNodes. This interface can be used -// to implement simple checkers that do not mutate analysis state but -// instead operate by perfoming simple logical checks at key monitoring -// locations (e.g., function calls). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR -#define LLVM_CLANG_ANALYSIS_GRAUDITOR - -namespace clang { - -class ExplodedNode; -class GRStateManager; - -class GRAuditor { -public: - virtual ~GRAuditor() {} - virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0; -}; - - -} // end clang namespace - -#endif diff --git a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h deleted file mode 100644 index 6d85e5fe6a90..000000000000 --- a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h +++ /dev/null @@ -1,31 +0,0 @@ -// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- 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 for building simple, path-sensitive checks -// that are stateless and only emit warnings at errors that occur at -// CallExpr or ObjCMessageExpr. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS -#define LLVM_CLANG_ANALYSIS_GRAPICHECKS - -#include "clang/Checker/PathSensitive/GRAuditor.h" - -namespace clang { - -class GRSimpleAPICheck : public GRAuditor { -public: - GRSimpleAPICheck() {} - virtual ~GRSimpleAPICheck() {} -}; - -} // end namespace clang - -#endif diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h deleted file mode 100644 index 1904835fbc34..000000000000 --- a/include/clang/Checker/PathSensitive/GRSubEngine.h +++ /dev/null @@ -1,107 +0,0 @@ -//== 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 - -#include "clang/Checker/PathSensitive/SVals.h" - -namespace clang { - -class AnalysisManager; -class CFGBlock; -class CFGElement; -class ExplodedNode; -class GRState; -class GRStateManager; -class GRBlockCounter; -class GRStmtNodeBuilder; -class GRBranchNodeBuilder; -class GRIndirectGotoNodeBuilder; -class GRSwitchNodeBuilder; -class GREndPathNodeBuilder; -class GRCallEnterNodeBuilder; -class GRCallExitNodeBuilder; -class LocationContext; -class MemRegion; -class Stmt; - -class GRSubEngine { -public: - virtual ~GRSubEngine() {} - - virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; - - virtual AnalysisManager &getAnalysisManager() = 0; - - virtual GRStateManager &getStateManager() = 0; - - /// Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - virtual void ProcessStmt(const CFGElement E, GRStmtNodeBuilder& builder) = 0; - - /// 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(const CFGBlock* B, const ExplodedNode *Pred, - GRBlockCounter BC) = 0; - - /// Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a branch condition. - virtual void ProcessBranch(const Stmt* Condition, const Stmt* Term, - GRBranchNodeBuilder& builder) = 0; - - /// Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a computed goto jump. - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; - - /// 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; - - // Generate the entry node of the callee. - virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0; - - // Generate the first post callsite node. - virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; - - /// Called by ConstraintManager. Used to call checker-specific - /// logic for handling assumptions on symbolic values. - virtual const GRState* ProcessAssume(const GRState *state, - SVal cond, bool assumption) = 0; - - /// WantsRegionChangeUpdate - Called by GRStateManager to determine if a - /// region change should trigger a ProcessRegionChanges update. - virtual bool WantsRegionChangeUpdate(const GRState* state) = 0; - - /// ProcessRegionChanges - Called by GRStateManager whenever a change is made - /// to the store. Used to update checkers that track region values. - virtual const GRState* ProcessRegionChanges(const GRState* state, - const MemRegion* const *Begin, - const MemRegion* const *End) = 0; - - inline const GRState* ProcessRegionChange(const GRState* state, - const MemRegion* MR) { - return ProcessRegionChanges(state, &MR, &MR+1); - } - - /// Called by GRCoreEngine when the analysis worklist is either empty or the - // maximum number of analysis steps have been reached. - virtual void ProcessEndWorklist(bool hasWorkRemaining) = 0; -}; -} - -#endif diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h deleted file mode 100644 index 320b7f7b8abd..000000000000 --- a/include/clang/Checker/PathSensitive/GRTransferFuncs.h +++ /dev/null @@ -1,87 +0,0 @@ -//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- C++ -*--=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRTransferFuncs, which provides a base-class that -// defines an interface for transfer functions used by GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRTF -#define LLVM_CLANG_ANALYSIS_GRTF - -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/PathSensitive/SVals.h" -#include <vector> - -namespace clang { -class ExplodedNode; -class ExplodedNodeSet; -class GREndPathNodeBuilder; -class GRExprEngine; -class GRStmtNodeBuilder; -class GRStmtNodeBuilderRef; -class ObjCMessageExpr; - -class GRTransferFuncs { -public: - GRTransferFuncs() {} - virtual ~GRTransferFuncs() {} - - virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} - virtual void RegisterChecks(GRExprEngine& Eng) {} - - - // Calls. - - virtual void EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - const CallExpr* CE, SVal L, - ExplodedNode* Pred) {} - - virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - const ObjCMessageExpr* ME, - ExplodedNode* Pred, - const GRState *state) {} - - // Stores. - - virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} - - // End-of-path and dead symbol notification. - - virtual void EvalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder& Builder) {} - - - virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, - const GRState* state, - SymbolReaper& SymReaper) {} - - // Return statements. - virtual void EvalReturn(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - const ReturnStmt* S, - ExplodedNode* Pred) {} - - // Assumptions. - virtual const GRState* EvalAssume(const GRState *state, - SVal Cond, bool Assumption) { - return state; - } -}; -} // end clang namespace - -#endif diff --git a/include/clang/Checker/PathSensitive/GRWorkList.h b/include/clang/Checker/PathSensitive/GRWorkList.h deleted file mode 100644 index 315b614043d4..000000000000 --- a/include/clang/Checker/PathSensitive/GRWorkList.h +++ /dev/null @@ -1,79 +0,0 @@ -//==- GRWorkList.h - Worklist class used by 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 GRWorkList, a pure virtual class that represents an opaque -// worklist used by GRCoreEngine to explore the reachability state space. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST -#define LLVM_CLANG_ANALYSIS_GRWORKLIST - -#include "clang/Checker/PathSensitive/GRBlockCounter.h" -#include <cstddef> - -namespace clang { - -class CFGBlock; -class ExplodedNode; -class ExplodedNodeImpl; - -class GRWorkListUnit { - ExplodedNode* Node; - GRBlockCounter Counter; - const CFGBlock* Block; - unsigned BlockIdx; // This is the index of the next statement. - -public: - GRWorkListUnit(ExplodedNode* N, GRBlockCounter C, - const CFGBlock* B, unsigned idx) - : Node(N), - Counter(C), - Block(B), - BlockIdx(idx) {} - - explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C) - : Node(N), - Counter(C), - Block(NULL), - BlockIdx(0) {} - - ExplodedNode* getNode() const { return Node; } - GRBlockCounter getBlockCounter() const { return Counter; } - const CFGBlock* getBlock() const { return Block; } - unsigned getIndex() const { return BlockIdx; } -}; - -class GRWorkList { - GRBlockCounter CurrentCounter; -public: - virtual ~GRWorkList(); - virtual bool hasWork() const = 0; - - virtual void Enqueue(const GRWorkListUnit& U) = 0; - - void Enqueue(ExplodedNode* N, const CFGBlock* B, unsigned idx) { - Enqueue(GRWorkListUnit(N, CurrentCounter, B, idx)); - } - - 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 -#endif diff --git a/include/clang/Checker/PathSensitive/SValuator.h b/include/clang/Checker/PathSensitive/SValuator.h deleted file mode 100644 index 9192ca7b8614..000000000000 --- a/include/clang/Checker/PathSensitive/SValuator.h +++ /dev/null @@ -1,70 +0,0 @@ -// SValuator.h - Construction of SVals from evaluating expressions -*- C++ -*--- -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SValuator, a class that defines the interface for -// "symbolical evaluators" which construct an SVal from an expression. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR -#define LLVM_CLANG_ANALYSIS_SVALUATOR - -#include "clang/AST/Expr.h" -#include "clang/Checker/PathSensitive/SVals.h" - -namespace clang { - -class GRState; -class ValueManager; - -class SValuator { - friend class ValueManager; -protected: - ValueManager &ValMgr; - -public: - // FIXME: Make these protected again one RegionStoreManager correctly - // handles loads from differening bound value types. - virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0; - virtual SVal EvalCastL(Loc val, QualType castTy) = 0; - -public: - SValuator(ValueManager &valMgr) : ValMgr(valMgr) {} - virtual ~SValuator() {} - - SVal EvalCast(SVal V, QualType castTy, QualType originalType); - - virtual SVal EvalMinus(NonLoc val) = 0; - - virtual SVal EvalComplement(NonLoc val) = 0; - - virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, - NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; - - virtual SVal EvalBinOpLL(const GRState *state, 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; - - /// getKnownValue - Evaluates a given SVal. If the SVal has only one possible - /// (integer) value, that value is returned. Otherwise, returns NULL. - virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0; - - 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/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h index cecfcda461bb..052c6603f5a7 100644 --- a/include/clang/CodeGen/CodeGenAction.h +++ b/include/clang/CodeGen/CodeGenAction.h @@ -14,18 +14,25 @@ #include "llvm/ADT/OwningPtr.h" namespace llvm { + class LLVMContext; class Module; } namespace clang { +class BackendConsumer; class CodeGenAction : public ASTFrontendAction { private: unsigned Act; llvm::OwningPtr<llvm::Module> TheModule; + llvm::LLVMContext *VMContext; + bool OwnsVMContext; protected: - CodeGenAction(unsigned _Act); + /// Create a new code generation action. If the optional \arg _VMContext + /// parameter is supplied, the action uses it without taking ownership, + /// otherwise it creates a fresh LLVM context and takes ownership. + CodeGenAction(unsigned _Act, llvm::LLVMContext *_VMContext = 0); virtual bool hasIRSupport() const; @@ -42,36 +49,41 @@ public: /// takeModule - Take the generated LLVM module, for use after the action has /// been run. The result may be null on failure. llvm::Module *takeModule(); + + /// Take the LLVM context used by this action. + llvm::LLVMContext *takeLLVMContext(); + + BackendConsumer *BEConsumer; }; class EmitAssemblyAction : public CodeGenAction { public: - EmitAssemblyAction(); + EmitAssemblyAction(llvm::LLVMContext *_VMContext = 0); }; class EmitBCAction : public CodeGenAction { public: - EmitBCAction(); + EmitBCAction(llvm::LLVMContext *_VMContext = 0); }; class EmitLLVMAction : public CodeGenAction { public: - EmitLLVMAction(); + EmitLLVMAction(llvm::LLVMContext *_VMContext = 0); }; class EmitLLVMOnlyAction : public CodeGenAction { public: - EmitLLVMOnlyAction(); + EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext = 0); }; class EmitCodeGenOnlyAction : public CodeGenAction { public: - EmitCodeGenOnlyAction(); + EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext = 0); }; class EmitObjAction : public CodeGenAction { public: - EmitObjAction(); + EmitObjAction(llvm::LLVMContext *_VMContext = 0); }; } diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake new file mode 100644 index 000000000000..5f13d2faa311 --- /dev/null +++ b/include/clang/Config/config.h.cmake @@ -0,0 +1,17 @@ +/* Relative directory for resource files */ +#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" + +/* 32 bit multilib directory. */ +#define CXX_INCLUDE_32BIT_DIR "${CXX_INCLUDE_32BIT_DIR}" + +/* 64 bit multilib directory. */ +#define CXX_INCLUDE_64BIT_DIR "${CXX_INCLUDE_64BIT_DIR}" + +/* Arch the libstdc++ headers. */ +#define CXX_INCLUDE_ARCH "${CXX_INCLUDE_ARCH}" + +/* Directory with the libstdc++ headers. */ +#define CXX_INCLUDE_ROOT "${CXX_INCLUDE_ROOT}" + +/* Directories clang will search for headers */ +#define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}" diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index 257b653f57e6..0fcf821c752c 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -288,7 +288,7 @@ namespace driver { unsigned NumInputArgStrings; public: - InputArgList(const char **ArgBegin, const char **ArgEnd); + InputArgList(const char* const *ArgBegin, const char* const *ArgEnd); ~InputArgList(); virtual const char *getArgString(unsigned Index) const { diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td index 5c08dc630551..50472ffdf9cd 100644 --- a/include/clang/Driver/CC1AsOptions.td +++ b/include/clang/Driver/CC1AsOptions.td @@ -46,6 +46,7 @@ def _help : Flag<"--help">, Alias<help>; def version : Flag<"-version">, HelpText<"Print the assembler version">; def _version : Flag<"--version">, Alias<version>; +def v : Flag<"-v">, Alias<version>; // Generic forwarding to LLVM options. This should only be used for debugging // and experimental features. @@ -69,3 +70,6 @@ def show_inst : Flag<"-show-inst">, def relax_all : Flag<"-relax-all">, HelpText<"Relax all fixups (for performance testing)">; + +def no_exec_stack : Flag<"--noexecstack">, + HelpText<"Mark the file as not needing an executable stack">;
\ No newline at end of file diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index fd40aa0c5f4b..a2c69f99540e 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -36,34 +36,20 @@ def triple_EQ : Joined<"-triple=">, Alias<triple>; // Analyzer Options //===----------------------------------------------------------------------===// -def analysis_CFGDump : Flag<"-cfg-dump">, - HelpText<"Display Control-Flow Graphs">; -def analysis_CFGView : Flag<"-cfg-view">, - HelpText<"View Control-Flow Graphs using GraphViz">; def analysis_UnoptimizedCFG : Flag<"-unoptimized-cfg">, HelpText<"Generate unoptimized CFGs for all analyses">; -def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">, - HelpText<"Print results of live variable analysis">; -def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">, - HelpText<"Check code for LLVM codebase conventions (domain-specific)">; -def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">, - HelpText<"Perform quick security checks that require no data flow">; -def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">, - HelpText<"Warn about stores to dead variables">; +def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">, + HelpText<"Add C++ implicit destructors to CFGs for all analyses">; +def analysis_CFGAddInitializers : Flag<"-cfg-add-initializers">, + HelpText<"Add C++ initializers to CFGs for all analyses">; def analysis_WarnUninitVals : Flag<"-warn-uninit-values">, HelpText<"Warn about uses of uninitialized variables">; -def analysis_WarnObjCMethSigs : Flag<"-analyzer-check-objc-methodsigs">, - HelpText<"Warn about Objective-C method signatures with type incompatibilities">; -def analysis_WarnObjCDealloc : Flag<"-analyzer-check-objc-missing-dealloc">, - HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">; -def analysis_WarnObjCUnusedIvars : Flag<"-analyzer-check-objc-unused-ivars">, - HelpText<"Warn about private ivars that are never used">; def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">, HelpText<"Run the [Core] Foundation reference count checker">; -def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, - HelpText<"Warn about unintended use of sizeof() on pointer expressions">; -def analysis_WarnIdempotentOps : Flag<"-analyzer-check-idempotent-operations">, - HelpText<"Warn about idempotent operations">; +def analysis_AnalyzerStats : Flag<"-analyzer-stats">, + HelpText<"Emit warnings with analyzer statistics">; +def analysis_WarnBufferOverflows : Flag<"-analyzer-check-buffer-overflows">, + HelpText<"Warn about buffer overflows">; def analyzer_store : Separate<"-analyzer-store">, HelpText<"Source Code Analysis - Abstract Memory Store Models">; @@ -82,7 +68,7 @@ def analyzer_output_EQ : Joined<"-analyzer-output=">, def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, HelpText<"Force the static analyzer to analyze functions defined in header files">; def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">, - HelpText<"Analyze the definitions of blocks in addition to functions">; + HelpText<"Analyze the definitions of blocks in addition to functions">; def analyzer_display_progress : Flag<"-analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">; def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">, @@ -97,6 +83,8 @@ def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">, HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; def analyzer_no_purge_dead : Flag<"-analyzer-no-purge-dead">, HelpText<"Don't remove dead symbols, bindings, and constraints before processing a statement">; +def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">, + HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">; def trim_egraph : Flag<"-trim-egraph">, HelpText<"Only show error-related paths in the analysis graph">; def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, @@ -106,10 +94,20 @@ def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, def analyzer_inline_call : Flag<"-analyzer-inline-call">, HelpText<"Experimental transfer function inlining callees when its definition is available.">; def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, - HelpText<"The maximum number of nodes the analyzer can generate">; + HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">; def analyzer_max_loop : Separate<"-analyzer-max-loop">, HelpText<"The maximum number of times the analyzer will go through a loop">; +def analyzer_checker : Separate<"-analyzer-checker">, + HelpText<"Choose analyzer checkers to enable">; +def analyzer_checker_EQ : Joined<"-analyzer-checker=">, + Alias<analyzer_checker>; + +def analyzer_disable_checker : Separate<"-analyzer-disable-checker">, + HelpText<"Choose analyzer checkers to disable">; +def analyzer_disable_checker_EQ : Joined<"-analyzer-disable-checker=">, + Alias<analyzer_disable_checker>; + //===----------------------------------------------------------------------===// // CodeGen Options //===----------------------------------------------------------------------===// @@ -125,6 +123,8 @@ def dwarf_debug_flags : Separate<"-dwarf-debug-flags">, def g : Flag<"-g">, HelpText<"Generate source level debug information">; def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, HelpText<"Generate runtime checks for undefined behavior.">; +def flimit_debug_info : Flag<"-flimit-debug-info">, + HelpText<"Limit debug information produced to reduce size of debug binary">; def fno_common : Flag<"-fno-common">, HelpText<"Compile common globals like normal definitions">; def no_implicit_float : Flag<"-no-implicit-float">, @@ -143,6 +143,8 @@ def fdata_sections : Flag<"-fdata-sections">, HelpText<"Place each data in its own section (ELF Only)">; def funroll_loops : Flag<"-funroll-loops">, HelpText<"Turn on loop unroller">; +def relaxed_aliasing : Flag<"-relaxed-aliasing">, + HelpText<"Turn off Type Based Alias Analysis">; def masm_verbose : Flag<"-masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<"-mcode-model">, @@ -161,6 +163,8 @@ def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, HelpText<"Omit frame pointer setup for leaf functions.">; def msoft_float : Flag<"-msoft-float">, HelpText<"Use software floating point">; +def mregparm : Separate<"-mregparm">, + HelpText<"Limit the number of registers available for integer arguments">; def mrelax_all : Flag<"-mrelax-all">, HelpText<"Relax all machine instructions">; def mrelocation_model : Separate<"-mrelocation-model">, @@ -169,8 +173,11 @@ def munwind_tables : Flag<"-munwind-tables">, HelpText<"Generate unwinding tables for all functions">; def mconstructor_aliases : Flag<"-mconstructor-aliases">, HelpText<"Emit complete constructors and destructors as aliases when possible">; +def mms_bitfields : Flag<"-mms-bitfields">, + HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">; def O : Joined<"-O">, HelpText<"Optimization level">; def Os : Flag<"-Os">, HelpText<"Optimize for size">; +def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">; //===----------------------------------------------------------------------===// // Dependency Output Options @@ -180,6 +187,10 @@ def dependency_file : Separate<"-dependency-file">, HelpText<"Filename (or -) to write dependency output to">; def sys_header_deps : Flag<"-sys-header-deps">, HelpText<"Include system headers in dependency output">; +def header_include_file : Separate<"-header-include-file">, + HelpText<"Filename (or -) to write header include output to">; +def H : Flag<"-H">, + HelpText<"Show header includes and nesting depth">; def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">; def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; def MP : Flag<"-MP">, @@ -203,7 +214,6 @@ def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, HelpText<"Do not include source line and caret with diagnostics">; def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, HelpText<"Do not include fixit information in diagnostics">; -def fdiagnostics_binary : Flag<"-fdiagnostics-binary">; def w : Flag<"-w">, HelpText<"Suppress all warnings">; def pedantic : Flag<"-pedantic">; def pedantic_errors : Flag<"-pedantic-errors">; @@ -221,7 +231,7 @@ def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, HelpText<"Print diagnostic name with mappable diagnostics">; def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">, HelpText<"Print diagnostic category">; - + def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">, HelpText<"Set the tab stop distance.">; def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">, @@ -260,8 +270,6 @@ def remap_file : Separate<"-remap-file">, HelpText<"Replace the contents of the <from> file with the contents of the <to> file">; def code_completion_at_EQ : Joined<"-code-completion-at=">, Alias<code_completion_at>; -def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer">, - HelpText<"Don't use the \"debug\" code-completion print">; def code_completion_macros : Flag<"-code-completion-macros">, HelpText<"Include macros in code-completion results">; def code_completion_patterns : Flag<"-code-completion-patterns">, @@ -274,17 +282,16 @@ def help : Flag<"-help">, HelpText<"Print this help text">; def _help : Flag<"--help">, Alias<help>; def x : Separate<"-x">, HelpText<"Input language type">; -def cxx_inheritance_view : Separate<"-cxx-inheritance-view">, - MetaVarName<"<class name>">, - HelpText<"View C++ inheritance for a specified class">; def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">; def load : Separate<"-load">, MetaVarName<"<dsopath>">, HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<"-plugin">, MetaVarName<"<name>">, - HelpText<"Use the named plugin action (use \"help\" to list available options)">; -def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; +def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, MetaVarName<"<name> <arg>">, HelpText<"Pass <arg> to plugin <name>">; +def add_plugin : Separate<"-add-plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action in addition to the default action">; def resource_dir : Separate<"-resource-dir">, HelpText<"The directory which holds the compiler resource files">; def version : Flag<"-version">, @@ -323,6 +330,8 @@ def ast_print_xml : Flag<"-ast-print-xml">, HelpText<"Build ASTs and then print them in XML format">; def ast_dump : Flag<"-ast-dump">, HelpText<"Build ASTs and then debug dump them">; +def ast_dump_xml : Flag<"-ast-dump-xml">, + HelpText<"Build ASTs and then debug dump them in a verbose XML format">; def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; def boostcon : Flag<"-boostcon">, @@ -359,6 +368,11 @@ def create_module : Flag<"-create-module">, def import_module : Separate<"-import-module">, HelpText<"Import a module definition file">; +def working_directory : JoinedOrSeparate<"-working-directory">, + HelpText<"Resolve file paths relative to the specified directory">; +def working_directory_EQ : Joined<"-working-directory=">, + Alias<working_directory>; + def relocatable_pch : Flag<"-relocatable-pch">, HelpText<"Whether to build a relocatable precompiled header">; def chained_pch : Flag<"-chained-pch">, @@ -401,11 +415,13 @@ def femit_all_decls : Flag<"-femit-all-decls">, HelpText<"Emit all declarations, even if unused">; def fblocks : Flag<"-fblocks">, HelpText<"enable the 'blocks' language feature">; -def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; +def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; def fexceptions : Flag<"-fexceptions">, HelpText<"Enable support for exception handling">; def fsjlj_exceptions : Flag<"-fsjlj-exceptions">, HelpText<"Use SjLj style exceptions">; +def fno_objc_exceptions : Flag<"-fno-objc-exceptions">, + HelpText<"Disable Objective-C exceptions">; def ffreestanding : Flag<"-ffreestanding">, HelpText<"Assert that the compilation takes place in a freestanding environment">; def fgnu_runtime : Flag<"-fgnu-runtime">, @@ -418,6 +434,8 @@ def fmath_errno : Flag<"-fmath-errno">, HelpText<"Require math functions to indicate errors by setting errno">; def fms_extensions : Flag<"-fms-extensions">, HelpText<"Accept some non-standard constructs used in Microsoft header files ">; +def fmsc_version : Joined<"-fmsc-version=">, + HelpText<"Version of the Microsoft C/C++ compiler to report in _MSC_VER (0 = don't define it (default))">; def fborland_extensions : Flag<"-fborland-extensions">, HelpText<"Accept non-standard constructs supported by the Borland compiler">; def main_file_name : Separate<"-main-file-name">, @@ -431,7 +449,7 @@ def fno_operator_names : Flag<"-fno-operator-names">, def fno_signed_char : Flag<"-fno-signed-char">, HelpText<"Char is unsigned">; def fno_spell_checking : Flag<"-fno-spell-checking">, - HelpText<"Disable spell-checking">; + HelpText<"Disable spell-checking">; def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, HelpText<"Don't use __cxa_atexit for calling destructors">; def fconstant_string_class : Separate<"-fconstant-string-class">, @@ -443,16 +461,21 @@ def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; def fobjc_gc_only : Flag<"-fobjc-gc-only">, HelpText<"Use GC exclusively for Objective-C related memory management">; +def fapple_kext : Flag<"-fapple-kext">, + HelpText<"Use Apple's kernel extensions ABI">; def fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">, HelpText<"Objective-C dispatch method to use">; +def fobjc_default_synthesize_properties : Flag<"-fobjc-default-synthesize-properties">, + HelpText<"enable the default synthesis of Objective-C properties">; def print_ivar_layout : Flag<"-print-ivar-layout">, HelpText<"Enable Objective-C Ivar layout bitmap print trace">; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, HelpText<"enable objective-c's nonfragile abi">; -def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, - HelpText<"enable objective-c's enhanced nonfragile abi">; def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; +def ftrapv_handler : Separate<"-ftrapv-handler">, + MetaVarName<"<function name>">, + HelpText<"Specify the function to be called on overflow.">; def fwrapv : Flag<"-fwrapv">, HelpText<"Treat signed integer overflow as two's complement">; def pic_level : Separate<"-pic-level">, @@ -465,8 +488,14 @@ def fno_rtti : Flag<"-fno-rtti">, HelpText<"Disable generation of rtti information">; def fno_validate_pch : Flag<"-fno-validate-pch">, HelpText<"Disable validation of precompiled headers">; +def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">, + HelpText<"Dump declarations that are deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">, + HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">; def fshort_wchar : Flag<"-fshort-wchar">, HelpText<"Force wchar_t to be a short unsigned int">; +def fshort_enums : Flag<"-fshort-enums">, + HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; def static_define : Flag<"-static-define">, HelpText<"Should __STATIC__ be defined">; def stack_protector : Separate<"-stack-protector">, @@ -477,6 +506,11 @@ def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, HelpText<"Give inline C++ member functions default visibility by default">; def ftemplate_depth : Separate<"-ftemplate-depth">, HelpText<"Maximum depth of recursive template instantiation">; +def Wlarge_by_value_copy : Separate<"-Wlarge-by-value-copy">, + HelpText<"Warn if a function definition returns or accepts an object larger " + "in bytes that a given value">; +def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">, + Alias<Wlarge_by_value_copy>; def trigraphs : Flag<"-trigraphs">, HelpText<"Process trigraph sequences">; def fwritable_strings : Flag<"-fwritable-strings">, @@ -516,6 +550,8 @@ def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, HelpText<"Set directory to include search path with prefix">; def isysroot : JoinedOrSeparate<"-isysroot">, MetaVarName<"<dir>">, HelpText<"Set the system root directory (usually /)">; +def cxx_system_include : Separate<"-cxx-system-include">, + HelpText<"Add a system #include directory for the C++ standard library">; def v : Flag<"-v">, HelpText<"Enable verbose output">; //===----------------------------------------------------------------------===// @@ -543,7 +579,7 @@ def undef : Flag<"-undef">, MetaVarName<"<macro>">, HelpText<"undef all system defines">; def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">, HelpText<"include a detailed record of preprocessing actions">; - + //===----------------------------------------------------------------------===// // Preprocessed Output Options //===----------------------------------------------------------------------===// @@ -558,5 +594,22 @@ def dM : Flag<"-dM">, HelpText<"Print macro definitions in -E mode instead of normal output">; def dD : Flag<"-dD">, HelpText<"Print macro definitions in -E mode in addition to normal output">; -def H : Flag<"-H">, - HelpText<"Show header includes and nesting depth">; + +//===----------------------------------------------------------------------===// +// OpenCL Options +//===----------------------------------------------------------------------===// + +def cl_opt_disable : Flag<"-cl-opt-disable">, + HelpText<"OpenCL only. This option disables all optimizations. The default is optimizations are enabled.">; +def cl_single_precision_constant : Flag<"-cl-single-precision-constant">, + HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">; +def cl_finite_math_only : Flag<"-cl-finite-math-only">, + HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; +def cl_unsafe_math_optimizations : Flag<"-cl-unsafe-math-optimizations">, + HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">; +def cl_fast_relaxed_math : Flag<"-cl-fast-relaxed-math">, + HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__">; +def cl_mad_enable : Flag<"-cl-mad-enable">, + HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">; +def cl_std_EQ : Joined<"-cl-std=">, + HelpText<"OpenCL language standard to compile for">; diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 28eff4f1d71d..03fa0ef972d0 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -17,7 +17,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo +#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo // lands. #include <list> #include <set> @@ -74,7 +74,8 @@ public: /// functionality. /// FIXME: This type of customization should be removed in favor of the /// universal driver when it is ready. - std::string PrefixDir; + typedef llvm::SmallVector<std::string, 4> prefix_list; + prefix_list PrefixDirs; /// Default host triple. std::string DefaultHostTriple; @@ -92,12 +93,12 @@ public: /// Information about the host which can be overriden by the user. std::string HostBits, HostMachine, HostSystem, HostRelease; - /// Name to use when calling the generic gcc. - std::string CCCGenericGCCName; - /// The file to log CC_PRINT_OPTIONS output to, if enabled. const char *CCPrintOptionsFilename; + /// The file to log CC_PRINT_HEADERS output to, if enabled. + const char *CCPrintHeadersFilename; + /// Whether the driver should follow g++ like behavior. unsigned CCCIsCXX : 1; @@ -111,7 +112,14 @@ public: /// CCPrintOptionsFilename or to stderr. unsigned CCPrintOptions : 1; + /// Set CC_PRINT_HEADERS mode, which causes the frontend to log header include + /// information to CCPrintHeadersFilename or to stderr. + unsigned CCPrintHeaders : 1; + private: + /// Name to use when calling the generic gcc. + std::string CCCGenericGCCName; + /// Whether to check that input files exist when constructing compilation /// jobs. unsigned CheckInputsExist : 1; @@ -157,6 +165,10 @@ public: /// @name Accessors /// @{ + /// Name to use when calling the generic gcc. + const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; } + + const OptTable &getOpts() const { return *Opts; } const Diagnostic &getDiags() const { return Diags; } diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h index c20d807b5811..0733c51027d9 100644 --- a/include/clang/Driver/DriverDiagnostic.h +++ b/include/clang/Driver/DriverDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define DRIVERSTART #include "clang/Basic/DiagnosticDriverKinds.inc" #undef DIAG diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h index 04e72992d684..7285a48b1cca 100644 --- a/include/clang/Driver/HostInfo.h +++ b/include/clang/Driver/HostInfo.h @@ -71,6 +71,8 @@ const HostInfo *createOpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple); const HostInfo *createFreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple); +const HostInfo *createNetBSDHostInfo(const Driver &D, + const llvm::Triple& Triple); const HostInfo *createMinixHostInfo(const Driver &D, const llvm::Triple& Triple); const HostInfo *createDragonFlyHostInfo(const Driver &D, diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h index 08b483c90017..3befe1defba9 100644 --- a/include/clang/Driver/OptTable.h +++ b/include/clang/Driver/OptTable.h @@ -170,8 +170,8 @@ namespace options { /// \param MissingArgCount - On error, the number of missing options. /// \return - An InputArgList; on error this will contain all the options /// which could be parsed. - InputArgList *ParseArgs(const char **ArgBegin, - const char **ArgEnd, + InputArgList *ParseArgs(const char* const *ArgBegin, + const char* const *ArgEnd, unsigned &MissingArgIndex, unsigned &MissingArgCount) const; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index c51d12a48769..7e3ddc616e1c 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -38,6 +38,7 @@ def u_Group : OptionGroup<"<u group>">; def pedantic_Group : OptionGroup<"<pedantic group>">, Group<CompileOnly_Group>; +def reserved_lib_Group : OptionGroup<"<reserved libs group>">; // Temporary groups for clang options which we know we don't support, // but don't want to verbosely warn the user about. @@ -195,6 +196,7 @@ def allowable__client : Separate<"-allowable_client">; def ansi : Flag<"-ansi">, Group<a_Group>; def arch__errors__fatal : Flag<"-arch_errors_fatal">; def arch : Separate<"-arch">, Flags<[DriverOption]>; +def arch__only : Separate<"-arch_only">; def a : Joined<"-a">, Group<a_Group>; def bind__at__load : Flag<"-bind_at_load">; def bundle__loader : Separate<"-bundle_loader">; @@ -213,7 +215,7 @@ def dD : Flag<"-dD">, Group<d_Group>; def dM : Flag<"-dM">, Group<d_Group>; def dead__strip : Flag<"-dead_strip">; def dependency_file : Separate<"-dependency-file">; -def dumpmachine : Flag<"-dumpmachine">, Flags<[Unsupported]>; +def dumpmachine : Flag<"-dumpmachine">; def dumpspecs : Flag<"-dumpspecs">, Flags<[Unsupported]>; def dumpversion : Flag<"-dumpversion">; def dylib__file : Separate<"-dylib_file">; @@ -233,9 +235,13 @@ def fPIC : Flag<"-fPIC">, Group<f_Group>; def fPIE : Flag<"-fPIE">, Group<f_Group>; def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>; def faccess_control : Flag<"-faccess-control">, Group<f_Group>; +def fallow_unsupported : Flag<"-fallow-unsupported">, Group<f_Group>; def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>; def fasm : Flag<"-fasm">, Group<f_Group>; -def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_f_Group>; + +def fasm_blocks : Flag<"-fasm-blocks">, Group<f_Group>; +def fno_asm_blocks : Flag<"-fno-asm-blocks">, Group<f_Group>; + def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>; def fastcp : Flag<"-fastcp">, Group<f_Group>; def fastf : Flag<"-fastf">, Group<f_Group>; @@ -259,13 +265,13 @@ def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Grou def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>; def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>; def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>; -def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[HelpHidden]>; def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>; def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>; def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_Group>; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>; def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_Group>; def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>; +def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>; def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>; def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>; def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>; @@ -274,6 +280,10 @@ def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>; def fhosted : Flag<"-fhosted">, Group<f_Group>; def ffast_math : Flag<"-ffast-math">, Group<clang_ignored_f_Group>; def ffinite_math_only : Flag<"-ffinite-math-only">, Group<clang_ignored_f_Group>; + +def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>; +def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>; + def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>; def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>; def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>; @@ -286,14 +296,17 @@ def finstrument_functions : Flag<"-finstrument-functions">, Group<f_Group>; def fkeep_inline_functions : Flag<"-fkeep-inline-functions">, Group<clang_ignored_f_Group>; def flat__namespace : Flag<"-flat_namespace">; def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>; +def flimit_debug_info : Flag<"-flimit-debug-info">, Group<f_Group>, + HelpText<"Limit debug information produced to reduce size of debug binary">; def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>; def flto : Flag<"-flto">, Group<f_Group>; -def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">, +def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">, Group<f_Group>; def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>; def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>; def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>; def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>; +def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>; def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>; def fmudflap : Flag<"-fmudflap">, Group<f_Group>; def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>; @@ -314,6 +327,7 @@ def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, Group<f_Group>; def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, Group<f_Group>; def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_Group>; def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>; +def fno_elide_constructors : Flag<"-fno-elide-constructors">, Group<f_Group>; def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>; def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>; def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<clang_ignored_f_Group>; @@ -325,15 +339,19 @@ def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Gr def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>; def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>; def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>; +def fno_objc_default_synthesize_properties + : Flag<"-fno-objc-default-synthesize-properties">, Group<f_Group>; +def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>; def fno_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group<f_Group>; def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group<f_Group>; def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group<f_Group>; def fno_rtti : Flag<"-fno-rtti">, Group<f_Group>; +def fno_short_enums : Flag<"-fno-short-enums">, Group<f_Group>; def fno_show_column : Flag<"-fno-show-column">, Group<f_Group>; def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>; def fno_spell_checking : Flag<"-fno-spell-checking">, Group<f_Group>; def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>; -def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_f_Group>; +def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<f_Group>; def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>; def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>; def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>; @@ -341,15 +359,23 @@ def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>; def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>; def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>; def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>; -def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>; def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>; def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>; +def fobjc_default_synthesize_properties : + Flag<"-fobjc-default-synthesize-properties">, Group<f_Group>; +def fobjc_exceptions: Flag<"-fobjc-exceptions">, Group<f_Group>; + def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>; def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>; def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>; def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>; + +// Objective-C ABI options. +def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>; +def fobjc_nonfragile_abi_version_EQ : Joined<"-fobjc-nonfragile-abi-version=">, Group<f_Group>; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, Group<f_Group>; -def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, Group<f_Group>; +def fno_objc_nonfragile_abi : Flag<"-fno-objc-nonfragile-abi">, Group<f_Group>; + def fobjc_sender_dependent_dispatch : Flag<"-fobjc-sender-dependent-dispatch">, Group<f_Group>; def fobjc : Flag<"-fobjc">, Group<f_Group>; def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group<f_Group>; @@ -368,7 +394,7 @@ def framework : Separate<"-framework">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<"-frandom-seed=">, Group<clang_ignored_f_Group>; def frtti : Flag<"-frtti">, Group<f_Group>; def fsched_interblock : Flag<"-fsched-interblock">, Group<clang_ignored_f_Group>; -def fshort_enums : Flag<"-fshort-enums">, Group<clang_ignored_f_Group>; +def fshort_enums : Flag<"-fshort-enums">, Group<f_Group>; def freorder_blocks : Flag<"-freorder-blocks">, Group<clang_ignored_f_Group>; def fshort_wchar : Flag<"-fshort-wchar">, Group<f_Group>; def fshow_overloads_EQ : Joined<"-fshow-overloads=">, Group<f_Group>; @@ -378,17 +404,20 @@ def fsigned_bitfields : Flag<"-fsigned-bitfields">, Group<f_Group>; def fsigned_char : Flag<"-fsigned-char">, Group<f_Group>; def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>; def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>; -def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<clang_ignored_f_Group>; +def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<f_Group>; def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>; def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>; def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>; def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>; -def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">, +def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">, Group<f_Group>; +def Wlarge_by_value_copy_def : Flag<"-Wlarge-by-value-copy">; +def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">; def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>; def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>; def ftime_report : Flag<"-ftime-report">, Group<f_Group>; def ftrapv : Flag<"-ftrapv">, Group<f_Group>; +def ftrapv_handler_EQ : Joined<"-ftrapv-handler=">, Group<f_Group>; def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>; def funroll_loops : Flag<"-funroll-loops">, Group<f_Group>; def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>; @@ -417,6 +446,7 @@ def iframework : JoinedOrSeparate<"-iframework">, Group<clang_i_Group>; def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>; def image__base : Separate<"-image_base">; def include_ : JoinedOrSeparate<"-include">, Group<clang_i_Group>, EnumName<"include">; +def include_pch : Separate<"-include-pch">, Group<clang_i_Group>; def init : Separate<"-init">; def install__name : Separate<"-install_name">; def integrated_as : Flag<"-integrated-as">, Flags<[DriverOption]>; @@ -450,6 +480,7 @@ def mkernel : Flag<"-mkernel">, Group<m_Group>; def mlinker_version_EQ : Joined<"-mlinker-version=">, Flags<[NoForward]>; def mllvm : Separate<"-mllvm">; def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>; +def mms_bitfields : Flag<"-mms-bitfields">, Group<m_Group>; def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>; def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>; def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>; @@ -478,6 +509,7 @@ def mno_omit_leaf_frame_pointer : Flag<"-mno-omit-leaf-frame-pointer">, Group<f_ def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, Group<f_Group>; def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>; def mred_zone : Flag<"-mred-zone">, Group<m_Group>; +def mregparm_EQ : Joined<"-mregparm=">, Group<m_Group>; def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>; def msoft_float : Flag<"-msoft-float">, Group<m_Group>; def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>; @@ -544,10 +576,12 @@ def private__bundle : Flag<"-private_bundle">; def pthreads : Flag<"-pthreads">; def pthread : Flag<"-pthread">; def p : Flag<"-p">; +def pie : Flag<"-pie">; def read__only__relocs : Separate<"-read_only_relocs">; def remap : Flag<"-remap">; def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption]>, HelpText<"Rewrite Objective-C source to C++">; +def rdynamic : Flag<"-rdynamic">; def rpath : Separate<"-rpath">, Flags<[LinkerInput]>; def r : Flag<"-r">; def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>, @@ -575,6 +609,7 @@ def static_libgcc : Flag<"-static-libgcc">; def static : Flag<"-static">, Flags<[NoArgumentUnused]>; def std_default_EQ : Joined<"-std-default=">; def std_EQ : Joined<"-std=">; +def stdlib_EQ : Joined<"-stdlib=">; def sub__library : JoinedOrSeparate<"-sub_library">; def sub__umbrella : JoinedOrSeparate<"-sub_umbrella">; def s : Flag<"-s">; @@ -591,6 +626,7 @@ def undefined : JoinedOrSeparate<"-undefined">, Group<u_Group>; def undef : Flag<"-undef">, Group<u_Group>; def unexported__symbols__list : Separate<"-unexported_symbols_list">; def u : JoinedOrSeparate<"-u">, Group<u_Group>; +def use_gold_plugin : Flag<"-use-gold-plugin">; def v : Flag<"-v">, HelpText<"Show commands to run and use verbose output">; def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>; @@ -605,6 +641,11 @@ def x : JoinedOrSeparate<"-x">, Flags<[DriverOption]>, MetaVarName<"<language>">; def y : Joined<"-y">; +def working_directory : Separate<"-working-directory">, + HelpText<"Resolve file paths relative to the specified directory">; +def working_directory_EQ : Joined<"-working-directory=">, + Alias<working_directory>; + // Double dash options, which are usually an alias for one of the previous // options. @@ -719,6 +760,8 @@ def _specs : Separate<"--specs">, Alias<specs_EQ>; def _static : Flag<"--static">, Alias<static>; def _std_EQ : Joined<"--std=">, Alias<std_EQ>; def _std : Separate<"--std">, Alias<std_EQ>; +def _stdlib_EQ : Joined<"--stdlib=">, Alias<std_EQ>; +def _stdlib : Separate<"--stdlib">, Alias<std_EQ>; def _sysroot_EQ : Joined<"--sysroot=">; def _sysroot : Separate<"--sysroot">, Alias<_sysroot_EQ>; def _target_help : Flag<"--target-help">; @@ -739,4 +782,15 @@ def _write_user_dependencies : Flag<"--write-user-dependencies">, Alias<MMD>; def _ : Joined<"--">, Flags<[Unsupported]>; // Special internal option to handle -Xlinker --no-demangle. -def Z_Xlinker__no_demangle : Flag<"-Z-Xlinker-no-demangle">, Flags<[Unsupported]>; +def Z_Xlinker__no_demangle : Flag<"-Z-Xlinker-no-demangle">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Special internal option to allow forwarding arbitrary arguments to linker. +def Zlinker_input : Separate<"-Zlinker-input">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Reserved library options. +def Z_reserved_lib_stdcxx : Flag<"-Z-reserved-lib-stdc++">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; +def Z_reserved_lib_cckext : Flag<"-Z-reserved-lib-cckext">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 55be4eee3d19..f0012bd851eb 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -10,10 +10,11 @@ #ifndef CLANG_DRIVER_TOOLCHAIN_H_ #define CLANG_DRIVER_TOOLCHAIN_H_ +#include "clang/Driver/Util.h" #include "clang/Driver/Types.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include <string> namespace clang { @@ -32,6 +33,11 @@ class ToolChain { public: typedef llvm::SmallVector<std::string, 4> path_list; + enum CXXStdlibType { + CST_Libcxx, + CST_Libstdcxx + }; + private: const HostInfo &Host; const llvm::Triple Triple; @@ -92,6 +98,10 @@ public: // Platform defaults information + /// HasNativeLTOLinker - Check whether the linker and related tools have + /// native LLVM support. + virtual bool HasNativeLLVMSupport() const; + /// LookupTypeForExtension - Return the default language type to use for the /// given extension. virtual types::ID LookupTypeForExtension(const char *Ext) const; @@ -103,6 +113,14 @@ public: /// by default. virtual bool IsIntegratedAssemblerDefault() const { return false; } + /// IsStrictAliasingDefault - Does this tool chain use -fstrict-aliasing by + /// default. + virtual bool IsStrictAliasingDefault() const { return true; } + + /// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable + /// -fobjc-default-synthesize-properties by default. + virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; } + /// IsObjCNonFragileABIDefault - Does this tool chain set /// -fobjc-nonfragile-abi by default. virtual bool IsObjCNonFragileABIDefault() const { return false; } @@ -153,6 +171,25 @@ public: /// sets the deployment target) determines the version in the triple passed to /// Clang. virtual std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + + // GetCXXStdlibType - Determine the C++ standard library type to use with the + // given compilation arguments. + virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + + /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set + /// the include paths to use for the given C++ standard library type. + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use + /// for the given C++ standard library type. + virtual void AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + /// AddCCKextLibArgs - Add the system specific linker arguments to use + /// for kernel extensions (Darwin-specific). + virtual void AddCCKextLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; }; } // end namespace driver diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index 06a8690ce833..f09a1dcaf26f 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -42,6 +42,7 @@ TYPE("cpp-output", PP_C, INVALID, "i", "u") TYPE("c", C, PP_C, 0, "u") TYPE("cl", CL, PP_C, 0, "u") +TYPE("cuda", CUDA, PP_CXX, 0, "u") TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u") TYPE("objective-c", ObjC, PP_ObjC, 0, "u") TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u") diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index cca243d6cd71..c45bd4070600 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -18,8 +18,6 @@ namespace llvm { class raw_ostream; - class Module; - class LLVMContext; namespace sys { class Path; } } namespace clang { @@ -48,6 +46,10 @@ ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream *OS); // intended for debugging. ASTConsumer *CreateASTDumper(); +// AST XML-dumper: dumps out the AST to stderr in a very detailed XML +// format; this is intended for particularly intense debugging. +ASTConsumer *CreateASTDumperXML(llvm::raw_ostream &OS); + // Graphical AST viewer: for each function definition, creates a graph of // the AST and displays it with the graph viewer "dotty". Also outputs // function declarations to stderr. @@ -57,10 +59,6 @@ ASTConsumer *CreateASTViewer(); // to stderr; this is intended for debugging. ASTConsumer *CreateDeclContextPrinter(); -// Inheritance viewer: for C++ code, creates a graph of the inheritance -// tree for the given class and displays it with "dotty". -ASTConsumer *CreateInheritanceViewer(const std::string& clsname); - } // end clang namespace #endif diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index e3fd4b37edac..e93563311b85 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -21,13 +21,13 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" #include "clang-c/Index.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" -#include "llvm/System/Path.h" -#include "llvm/Support/Timer.h" +#include "llvm/Support/Path.h" #include <map> #include <string> #include <vector> @@ -54,6 +54,14 @@ class TargetInfo; using namespace idx; +/// \brief Allocator for a cached set of global code completions. +class GlobalCodeCompletionAllocator + : public CodeCompletionAllocator, + public llvm::RefCountedBase<GlobalCodeCompletionAllocator> +{ + +}; + /// \brief Utility class for loading a ASTContext from an AST file. /// class ASTUnit { @@ -69,7 +77,9 @@ private: llvm::OwningPtr<TargetInfo> Target; llvm::OwningPtr<Preprocessor> PP; llvm::OwningPtr<ASTContext> Ctx; - + + FileSystemOptions FileSystemOpts; + /// \brief The AST consumer that received information about the translation /// unit as it was parsed or loaded. llvm::OwningPtr<ASTConsumer> Consumer; @@ -82,6 +92,13 @@ private: /// LoadFromCommandLine available. llvm::OwningPtr<CompilerInvocation> Invocation; + /// \brief The set of target features. + /// + /// FIXME: each time we reparse, we need to restore the set of target + /// features from this vector, because TargetInfo::CreateTargetInfo() + /// mangles the target options in place. Yuck! + std::vector<std::string> TargetFeatures; + // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. @@ -89,13 +106,16 @@ private: /// \brief Whether to capture any diagnostics produced. bool CaptureDiagnostics; - + /// \brief Track whether the main file was loaded from an AST or not. bool MainFileIsAST; /// \brief Whether this AST represents a complete translation unit. bool CompleteTranslationUnit; + /// \brief Whether we should time each operation. + bool WantTiming; + /// Track the top-level decls which appeared in an ASTUnit which was loaded /// from a source file. // @@ -105,6 +125,14 @@ private: // more scalable search mechanisms. std::vector<Decl*> TopLevelDecls; + /// \brief The list of preprocessed entities which appeared when the ASTUnit + /// was loaded. + /// + /// FIXME: This is just an optimization hack to avoid deserializing large + /// parts of a PCH file while performing a walk or search. In the long term, + /// we should provide more scalable search mechanisms. + std::vector<PreprocessedEntity *> PreprocessedEntities; + /// The name of the original source file used to generate this ASTUnit. std::string OriginalSourceFile; @@ -115,6 +143,13 @@ private: /// translation unit. llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + /// \brief The number of stored diagnostics that come from the driver + /// itself. + /// + /// Diagnostics that come from the driver are retained from one parse to + /// the next. + unsigned NumStoredDiagnosticsFromDriver; + /// \brief Temporary files that should be removed when the ASTUnit is /// destroyed. llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles; @@ -199,22 +234,21 @@ private: /// a precompiled preamble. unsigned NumStoredDiagnosticsInPreamble; - /// \brief The group of timers associated with this translation unit. - llvm::OwningPtr<llvm::TimerGroup> TimerGroup; - /// \brief A list of the serialization ID numbers for each of the top-level /// declarations parsed within the precompiled preamble. std::vector<serialization::DeclID> TopLevelDeclsInPreamble; - /// - /// \defgroup CodeCompleteCaching Code-completion caching - /// - /// \{ - /// - + /// \brief A list of the offsets into the precompiled preamble which + /// correspond to preprocessed entities. + std::vector<uint64_t> PreprocessedEntitiesInPreamble; + /// \brief Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults; + static void ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags, + const char **ArgBegin, const char **ArgEnd, + ASTUnit &AST, bool CaptureDiagnostics); + public: /// \brief A cached code-completion result, which may be introduced in one of /// many different contexts. @@ -261,7 +295,17 @@ public: return CachedCompletionTypes; } + /// \brief Retrieve the allocator used to cache global code completions. + llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + getCachedCompletionAllocator() { + return CachedCompletionAllocator; + } + private: + /// \brief Allocator used to store cached code completions. + llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + /// \brief The set of cached code-completion results. std::vector<CachedCodeCompletionResult> CachedCompletionResults; @@ -269,20 +313,24 @@ private: /// type, which is used for type equality comparisons. llvm::StringMap<unsigned> CachedCompletionTypes; - /// \brief The number of top-level declarations present the last time we - /// cached code-completion results. + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the file. /// - /// The value is used to help detect when we should repopulate the global - /// completion cache. - unsigned NumTopLevelDeclsAtLastCompletionCache; + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache. + unsigned CompletionCacheTopLevelHashValue; - /// \brief The number of reparses left until we'll consider updating the - /// code-completion cache. + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the precompiled preamble. /// - /// This is meant to avoid thrashing during reparsing, by not allowing the - /// code-completion cache to be updated on every reparse. - unsigned CacheCodeCompletionCoolDown; + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache after a rebuild of the precompiled preamble. + unsigned PreambleTopLevelHashValue; + /// \brief The current hash value for the top-level declaration and macro + /// definition names + unsigned CurrentTopLevelHashValue; + /// \brief Bit used by CIndex to mark when a translation unit may be in an /// inconsistent state, and is not safe to free. unsigned UnsafeToFree : 1; @@ -294,14 +342,6 @@ private: /// \brief Clear out and deallocate void ClearCachedCompletionResults(); - /// - /// \} - /// - - /// \brief The timers we've created from the various parses, reparses, etc. - /// involved in this translation unit. - std::vector<llvm::Timer *> Timers; - ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT @@ -319,7 +359,8 @@ private: bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); - + void RealizePreprocessedEntitiesFromPreamble(); + public: class ConcurrencyCheck { volatile ASTUnit &Self; @@ -367,6 +408,8 @@ public: const FileManager &getFileManager() const { return *FileMgr; } FileManager &getFileManager() { return *FileMgr; } + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } + const std::string &getOriginalSourceFileName(); const std::string &getASTFileName(); @@ -386,6 +429,9 @@ public: void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } ASTLocation getLastASTLocation() const { return LastLoc; } + + llvm::StringRef getMainFileName() const; + typedef std::vector<Decl *>::iterator top_level_iterator; top_level_iterator top_level_begin() { @@ -423,6 +469,22 @@ public: TopLevelDeclsInPreamble.push_back(D); } + /// \brief Retrieve a reference to the current top-level name hash value. + /// + /// Note: This is used internally by the top-level tracking action + unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; } + + typedef std::vector<PreprocessedEntity *>::iterator pp_entity_iterator; + + pp_entity_iterator pp_entity_begin(); + pp_entity_iterator pp_entity_end(); + + /// \brief Add a new preprocessed entity that's stored at the given offset + /// in the precompiled preamble. + void addPreprocessedEntityFromPreamble(uint64_t Offset) { + PreprocessedEntitiesInPreamble.push_back(Offset); + } + /// \brief Retrieve the mapping from File IDs to the preprocessed entities /// within that file. PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() { @@ -457,7 +519,10 @@ public: unsigned cached_completion_size() const { return CachedCompletionResults.size(); } - + + llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename, + std::string *ErrorStr = 0); + /// \brief Whether this AST represents a complete translation unit. /// /// If false, this AST is only a partial translation unit, e.g., one @@ -478,11 +543,25 @@ public: /// \returns - The initialized ASTUnit or null if the AST failed to load. static ASTUnit *LoadFromASTFile(const std::string &Filename, llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls = false, RemappedFile *RemappedFiles = 0, unsigned NumRemappedFiles = 0, bool CaptureDiagnostics = false); +private: + /// \brief Helper function for \c LoadFromCompilerInvocation() and + /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. + /// + /// \param PrecompilePreamble Whether to precompile the preamble of this + /// translation unit, to improve the performance of reparsing. + /// + /// \returns \c true if a catastrophic failure occurred (which means that the + /// \c ASTUnit itself is invalid), or \c false otherwise. + bool LoadFromCompilerInvocation(bool PrecompilePreamble); + +public: + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. /// @@ -521,12 +600,14 @@ public: llvm::IntrusiveRefCntPtr<Diagnostic> Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls = false, + bool CaptureDiagnostics = false, RemappedFile *RemappedFiles = 0, unsigned NumRemappedFiles = 0, - bool CaptureDiagnostics = false, bool PrecompilePreamble = false, bool CompleteTranslationUnit = true, - bool CacheCodeCompletionResults = false); + bool CacheCodeCompletionResults = false, + bool CXXPrecompilePreamble = false, + bool CXXChainedPCH = false); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index aaa3920cee4f..75b52a824c63 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -15,45 +15,12 @@ #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) #endif -ANALYSIS(CFGDump, "cfg-dump", - "Display Control-Flow Graphs", Code) - -ANALYSIS(CFGView, "cfg-view", - "View Control-Flow Graphs using GraphViz", Code) - -ANALYSIS(DisplayLiveVariables, "dump-live-variables", - "Print results of live variable analysis", Code) - -ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic", - "Perform quick security checks that require no data flow", Code) - -ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions", - "Check code for LLVM codebase conventions (domain-specific)", - TranslationUnit) - -ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores", - "Warn about stores to dead variables", Code) - ANALYSIS(WarnUninitVals, "warn-uninit-values", "Warn about uses of uninitialized variables", Code) - -ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs", - "Warn about Objective-C method signatures with type incompatibilities", - ObjCImplementation) - -ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc", -"Warn about Objective-C classes that lack a correct implementation of -dealloc", - ObjCImplementation) -ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars", - "Warn about private ivars that are never used", ObjCImplementation) - ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", "Run the [Core] Foundation reference count checker", Code) -ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer", - "Warn about unintended use of sizeof() on pointer expressions", Code) - #ifndef ANALYSIS_STORE #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif @@ -73,9 +40,10 @@ ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of conc #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) #endif -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) +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) +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticClient, true) #undef ANALYSIS #undef ANALYSIS_STORE diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h index 9ed15ba2f996..580692865819 100644 --- a/include/clang/Frontend/AnalyzerOptions.h +++ b/include/clang/Frontend/AnalyzerOptions.h @@ -56,6 +56,8 @@ NUM_ANALYSIS_DIAG_CLIENTS class AnalyzerOptions { public: std::vector<Analyses> AnalysisList; + /// \brief Pair of checker name and enable/disable. + std::vector<std::pair<std::string, bool> > CheckersControlList; AnalysisStores AnalysisStoreOpt; AnalysisConstraints AnalysisConstraintsOpt; AnalysisDiagClients AnalysisDiagOpt; @@ -65,17 +67,20 @@ public: unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; + unsigned AnalyzerStats : 1; unsigned EagerlyAssume : 1; - unsigned IdempotentOps : 1; + unsigned BufferOverflows : 1; unsigned PurgeDead : 1; unsigned TrimGraph : 1; unsigned VisualizeEGDot : 1; unsigned VisualizeEGUbi : 1; unsigned EnableExperimentalChecks : 1; unsigned EnableExperimentalInternalChecks : 1; - unsigned EnableIdempotentOperationChecker : 1; unsigned InlineCall : 1; unsigned UnoptimizedCFG : 1; + unsigned CFGAddImplicitDtors : 1; + unsigned CFGAddInitializers : 1; + unsigned EagerlyTrimEGraph : 1; public: AnalyzerOptions() { @@ -85,14 +90,20 @@ public: AnalyzeAll = 0; AnalyzerDisplayProgress = 0; AnalyzeNestedBlocks = 0; + AnalyzerStats = 0; EagerlyAssume = 0; + BufferOverflows = 0; PurgeDead = 1; TrimGraph = 0; VisualizeEGDot = 0; VisualizeEGUbi = 0; EnableExperimentalChecks = 0; EnableExperimentalInternalChecks = 0; + InlineCall = 0; UnoptimizedCFG = 0; + CFGAddImplicitDtors = 0; + CFGAddInitializers = 0; + EagerlyTrimEGraph = 0; } }; diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index b3f57094b4af..ee85b655c23f 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -40,24 +40,32 @@ public: /// aliases to base ctors when possible. unsigned DataSections : 1; /// Set when -fdata-sections is enabled unsigned DebugInfo : 1; /// Should generate debug info (-g). + unsigned LimitDebugInfo : 1; /// Limit generated debug info to reduce size. unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled. unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in /// getting .bc files that correspond to the /// internal state before optimizations are /// done. unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled. - unsigned EmitDeclMetadata : 1; /// Emit special metadata indicating what Decl* - /// various IR entities came from. Only useful - /// when running CodeGen as a subroutine. + unsigned EmitDeclMetadata : 1; /// Emit special metadata indicating what + /// Decl* various IR entities came from. Only + /// useful when running CodeGen as a + /// subroutine. unsigned FunctionSections : 1; /// Set when -ffunction-sections is enabled unsigned HiddenWeakTemplateVTables : 1; /// Emit weak vtables and RTTI for /// template classes with hidden visibility unsigned HiddenWeakVTables : 1; /// Emit weak vtables, RTTI, and thunks with - /// hidden visibility - unsigned InstrumentFunctions : 1; /// Set when -finstrument-functions is enabled + /// hidden visibility. + unsigned InstrumentFunctions : 1; /// Set when -finstrument-functions is + /// enabled. + unsigned InstrumentForProfiling : 1; /// Set when -pg is enabled + unsigned LessPreciseFPMAD : 1; /// Enable less precise MAD instructions to be + /// generated. unsigned MergeAllConstants : 1; /// Merge identical constants. unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. + unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf. + unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN. unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use. unsigned OmitLeafFramePointer : 1; /// Set when -momit-leaf-frame-pointer is @@ -65,12 +73,14 @@ public: unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. unsigned RelaxAll : 1; /// Relax all machine code instructions. + unsigned RelaxedAliasing : 1; /// Set when -fno-strict-aliasing is enabled. unsigned SimplifyLibCalls : 1; /// Set when -fbuiltin is enabled. unsigned SoftFloat : 1; /// -soft-float. unsigned TimePasses : 1; /// Set when -ftime-report is enabled. unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization /// selection. unsigned UnrollLoops : 1; /// Control whether loops are unrolled. + unsigned UnsafeFPMath : 1; /// Allow unsafe floating point optzns. unsigned UnwindTables : 1; /// Emit unwind tables. unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. @@ -102,6 +112,10 @@ public: /// The name of the relocation model to use. std::string RelocationModel; + /// The user specified number of registers to be used for integral arguments, + /// or 0 if unspecified. + unsigned NumRegisterParameters; + public: CodeGenOptions() { AsmVerbose = 0; @@ -109,6 +123,7 @@ public: CXXCtorDtorAliases = 0; DataSections = 0; DebugInfo = 0; + LimitDebugInfo = 0; DisableFPElim = 0; DisableLLVMOpts = 0; DisableRedZone = 0; @@ -117,20 +132,27 @@ public: HiddenWeakTemplateVTables = 0; HiddenWeakVTables = 0; InstrumentFunctions = 0; + InstrumentForProfiling = 0; + LessPreciseFPMAD = 0; MergeAllConstants = 1; NoCommon = 0; NoImplicitFloat = 0; + NoInfsFPMath = 0; + NoNaNsFPMath = 0; NoZeroInitializedInBSS = 0; + NumRegisterParameters = 0; ObjCDispatchMethod = Legacy; OmitLeafFramePointer = 0; OptimizationLevel = 0; OptimizeSize = 0; RelaxAll = 0; + RelaxedAliasing = 0; SimplifyLibCalls = 1; SoftFloat = 0; TimePasses = 0; UnitAtATime = 1; UnrollLoops = 0; + UnsafeFPMath = 0; UnwindTables = 0; VerifyModule = 1; diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h index bea468b01791..8911cfadd530 100644 --- a/include/clang/Frontend/CommandLineSourceLoc.h +++ b/include/clang/Frontend/CommandLineSourceLoc.h @@ -37,9 +37,15 @@ public: // If both tail splits were valid integers, return success. if (!ColSplit.second.getAsInteger(10, PSL.Column) && - !LineSplit.second.getAsInteger(10, PSL.Line)) + !LineSplit.second.getAsInteger(10, PSL.Line)) { PSL.FileName = LineSplit.first; + // On the command-line, stdin may be specified via "-". Inside the + // compiler, stdin is called "<stdin>". + if (PSL.FileName == "-") + PSL.FileName = "<stdin>"; + } + return PSL; } }; diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 1b3c336fc0eb..7ea79e5599ff 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -19,7 +19,6 @@ #include <string> namespace llvm { -class LLVMContext; class raw_ostream; class raw_fd_ostream; class Timer; @@ -59,9 +58,6 @@ class TargetInfo; /// come in two forms; a short form that reuses the CompilerInstance objects, /// and a long form that takes explicit instances of any required objects. class CompilerInstance { - /// The LLVM context used for this instance. - llvm::OwningPtr<llvm::LLVMContext> LLVMContext; - /// The options used in this compiler instance. llvm::OwningPtr<CompilerInvocation> Invocation; @@ -95,8 +91,23 @@ class CompilerInstance { /// The frontend timer llvm::OwningPtr<llvm::Timer> FrontendTimer; + /// \brief Holds information about the output file. + /// + /// If TempFilename is not empty we must rename it to Filename at the end. + /// TempFilename may be empty and Filename non empty if creating the temporary + /// failed. + struct OutputFile { + std::string Filename; + std::string TempFilename; + llvm::raw_ostream *OS; + + OutputFile(const std::string &filename, const std::string &tempFilename, + llvm::raw_ostream *os) + : Filename(filename), TempFilename(tempFilename), OS(os) { } + }; + /// The list of active output files. - std::list< std::pair<std::string, llvm::raw_ostream*> > OutputFiles; + std::list<OutputFile> OutputFiles; void operator=(const CompilerInstance &); // DO NOT IMPLEMENT CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT @@ -140,23 +151,6 @@ public: bool ExecuteAction(FrontendAction &Act); /// } - /// @name LLVM Context - /// { - - bool hasLLVMContext() const { return LLVMContext != 0; } - - llvm::LLVMContext &getLLVMContext() const { - assert(LLVMContext && "Compiler instance has no LLVM context!"); - return *LLVMContext; - } - - llvm::LLVMContext *takeLLVMContext() { return LLVMContext.take(); } - - /// setLLVMContext - Replace the current LLVM context and take ownership of - /// \arg Value. - void setLLVMContext(llvm::LLVMContext *Value); - - /// } /// @name Compiler Invocation and Options /// { @@ -205,6 +199,10 @@ public: return Invocation->getDiagnosticOpts(); } + const FileSystemOptions &getFileSystemOpts() const { + return Invocation->getFileSystemOpts(); + } + FrontendOptions &getFrontendOpts() { return Invocation->getFrontendOpts(); } @@ -435,16 +433,10 @@ public: /// @name Output Files /// { - /// getOutputFileList - Get the list of (path, output stream) pairs of output - /// files; the path may be empty but the stream will always be non-null. - const std::list< std::pair<std::string, - llvm::raw_ostream*> > &getOutputFileList() const; - /// addOutputFile - Add an output file onto the list of tracked output files. /// - /// \param Path - The path to the output file, or empty. - /// \param OS - The output stream, which should be non-null. - void addOutputFile(llvm::StringRef Path, llvm::raw_ostream *OS); + /// \param OutFile - The output file info. + void addOutputFile(const OutputFile &OutFile); /// clearOutputFiles - Clear the output file list, destroying the contained /// output streams. @@ -459,8 +451,14 @@ public: /// Create the diagnostics engine using the invocation's diagnostic options /// and replace any existing one with it. /// - /// Note that this routine also replaces the diagnostic client. - void createDiagnostics(int Argc, char **Argv); + /// Note that this routine also replaces the diagnostic client, + /// allocating one if one is not provided. + /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the Diagnostic inside this AST + /// unit. + void createDiagnostics(int Argc, const char* const *Argv, + DiagnosticClient *Client = 0); /// Create a Diagnostic object with a the TextDiagnosticPrinter. /// @@ -468,23 +466,30 @@ public: /// when the diagnostic options indicate that the compiler should output /// logging information. /// - /// Note that this creates an unowned DiagnosticClient, if using directly the - /// caller is responsible for releasing the returned Diagnostic's client - /// eventually. + /// If no diagnostic client is provided, this creates a + /// DiagnosticClient that is owned by the returned diagnostic + /// object, if using directly the caller is responsible for + /// releasing the returned Diagnostic's client eventually. /// /// \param Opts - The diagnostic options; note that the created text /// diagnostic object contains a reference to these options and its lifetime /// must extend past that of the diagnostic engine. /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the returned Diagnostic + /// object. + /// /// \return The new object on success, or null on failure. static llvm::IntrusiveRefCntPtr<Diagnostic> - createDiagnostics(const DiagnosticOptions &Opts, int Argc, char **Argv); + createDiagnostics(const DiagnosticOptions &Opts, int Argc, + const char* const *Argv, + DiagnosticClient *Client = 0); /// Create the file manager and replace any existing one with it. void createFileManager(); /// Create the source manager and replace any existing one with it. - void createSourceManager(); + void createSourceManager(FileManager &FileMgr); /// Create the preprocessor, using the invocation, file, and source managers, /// and replace any existing one with it. @@ -511,6 +516,7 @@ public: /// context. void createPCHExternalASTSource(llvm::StringRef Path, bool DisablePCHValidation, + bool DisableStatCache, void *DeserializationListener); /// Create an external AST source to read a PCH file. @@ -519,8 +525,9 @@ public: static ExternalASTSource * createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + bool DisableStatCache, Preprocessor &PP, ASTContext &Context, - void *DeserializationListener); + void *DeserializationListener, bool Preamble); /// Create a code completion consumer using the invocation; note that this /// will cause the source manager to truncate the input source file at the @@ -533,7 +540,7 @@ public: static CodeCompleteConsumer * createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column, - bool UseDebugPrinter, bool ShowMacros, + bool ShowMacros, bool ShowCodePatterns, bool ShowGlobals, llvm::raw_ostream &OS); @@ -557,7 +564,8 @@ public: /// /// \return - Null on error. llvm::raw_fd_ostream * - createOutputFile(llvm::StringRef OutputPath, bool Binary = true, + createOutputFile(llvm::StringRef OutputPath, + bool Binary = true, bool RemoveFileOnSignal = true, llvm::StringRef BaseInput = "", llvm::StringRef Extension = ""); @@ -565,7 +573,8 @@ public: /// /// If \arg OutputPath is empty, then createOutputFile will derive an output /// path location as \arg BaseInput, with any suffix removed, and \arg - /// Extension appended. + /// Extension appended. If OutputPath is not stdout createOutputFile will + /// create a new temporary file that must be renamed to OutputPath in the end. /// /// \param OutputPath - If given, the path to the output file. /// \param Error [out] - On failure, the error message. @@ -573,13 +582,20 @@ public: /// for deriving the output path. /// \param Extension - The extension to use for derived output names. /// \param Binary - The mode to open the file in. + /// \param RemoveFileOnSignal - Whether the file should be registered with + /// llvm::sys::RemoveFileOnSignal. Note that this is not safe for + /// multithreaded use, as the underlying signal mechanism is not reentrant /// \param ResultPathName [out] - If given, the result path name will be /// stored here on success. + /// \param TempPathName [out] - If given, the temporary file path name + /// will be stored here on success. static llvm::raw_fd_ostream * createOutputFile(llvm::StringRef OutputPath, std::string &Error, - bool Binary = true, llvm::StringRef BaseInput = "", + bool Binary = true, bool RemoveFileOnSignal = true, + llvm::StringRef BaseInput = "", llvm::StringRef Extension = "", - std::string *ResultPathName = 0); + std::string *ResultPathName = 0, + std::string *TempPathName = 0); /// } /// @name Initialization Utility Methods diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index d558ad391406..e0329dbc96ec 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -12,12 +12,14 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Basic/FileSystemOptions.h" #include "clang/Frontend/AnalyzerOptions.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Frontend/LangStandard.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Frontend/PreprocessorOutputOptions.h" #include "llvm/ADT/StringRef.h" @@ -52,6 +54,9 @@ class CompilerInvocation { /// Options controlling the diagnostic engine. DiagnosticOptions DiagnosticOpts; + /// Options controlling file system operations. + FileSystemOptions FileSystemOpts; + /// Options controlling the frontend itself. FrontendOptions FrontendOpts; @@ -83,8 +88,10 @@ public: /// \param ArgBegin - The first element in the argument vector. /// \param ArgEnd - The last element in the argument vector. /// \param Diags - The diagnostic engine to use for errors. - static void CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, - const char **ArgEnd, Diagnostic &Diags); + static void CreateFromArgs(CompilerInvocation &Res, + const char* const *ArgBegin, + const char* const *ArgEnd, + Diagnostic &Diags); /// GetBuiltinIncludePath - Get the directory where the compiler headers /// reside, relative to the compiler binary (found by the passed in @@ -100,6 +107,25 @@ public: /// passing to CreateFromArgs. void toArgs(std::vector<std::string> &Res); + /// setLangDefaults - Set language defaults for the given input language and + /// language standard in this CompilerInvocation. + /// + /// \param IK - The input language. + /// \param LangStd - The input language standard. + void setLangDefaults(InputKind IK, + LangStandard::Kind LangStd = LangStandard::lang_unspecified) { + setLangDefaults(LangOpts, IK, LangStd); + } + + /// setLangDefaults - Set language defaults for the given input language and + /// language standard in the given LangOptions object. + /// + /// \param LangOpts - The LangOptions object to set up. + /// \param IK - The input language. + /// \param LangStd - The input language standard. + static void setLangDefaults(LangOptions &Opts, InputKind IK, + LangStandard::Kind LangStd = LangStandard::lang_unspecified); + /// @} /// @name Option Subgroups /// @{ @@ -124,6 +150,11 @@ public: DiagnosticOptions &getDiagnosticOpts() { return DiagnosticOpts; } const DiagnosticOptions &getDiagnosticOpts() const { return DiagnosticOpts; } + FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + const FileSystemOptions &getFileSystemOpts() const { + return FileSystemOpts; + } + HeaderSearchOptions &getHeaderSearchOpts() { return HeaderSearchOpts; } const HeaderSearchOptions &getHeaderSearchOpts() const { return HeaderSearchOpts; diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index 18451189bc06..1b158fdfafc0 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -103,6 +103,9 @@ NODE_XML(FunctionDecl, "Function") ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") //ATTRIBUTE_OPT_XML(isVariadic(), "variadic") // in the type reference ATTRIBUTE_XML(getNumParams(), "num_args") + ATTRIBUTE_OPT_XML(isMain(), "main") + ATTRIBUTE_OPT_XML(isExternC(), "externc") + ATTRIBUTE_OPT_XML(isGlobal(), "global") SUB_NODE_SEQUENCE_XML(ParmVarDecl) SUB_NODE_FN_BODY_XML END_NODE_XML @@ -117,6 +120,7 @@ NODE_XML(CXXMethodDecl, "CXXMethod") ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") ATTRIBUTE_OPT_XML(isStatic(), "static") ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_OPT_XML(isPure(), "pure") ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access") ENUM_XML(AS_none, "") ENUM_XML(AS_public, "public") @@ -316,6 +320,7 @@ NODE_XML(LinkageSpecDecl, "LinkageSpec") ENUM_XML(LinkageSpecDecl::lang_c, "C") ENUM_XML(LinkageSpecDecl::lang_cxx, "CXX") END_ENUM_XML + SUB_NODE_XML(DeclContext) END_NODE_XML NODE_XML(TemplateDecl, "Template") diff --git a/include/clang/Frontend/DependencyOutputOptions.h b/include/clang/Frontend/DependencyOutputOptions.h index ab8e49df9a88..35aa6c6aace6 100644 --- a/include/clang/Frontend/DependencyOutputOptions.h +++ b/include/clang/Frontend/DependencyOutputOptions.h @@ -20,13 +20,20 @@ namespace clang { class DependencyOutputOptions { public: unsigned IncludeSystemHeaders : 1; ///< Include system header dependencies. + unsigned ShowHeaderIncludes : 1; ///< Show header inclusions (-H). unsigned UsePhonyTargets : 1; ///< Include phony targets for each /// dependency, which can avoid some 'make' /// problems. - /// The file to write depencency output to. + /// The file to write dependency output to. std::string OutputFile; + /// The file to write header include output to. This is orthogonal to + /// ShowHeaderIncludes (-H) and will include headers mentioned in the + /// predefines buffer. If the output file is "-", output will be sent to + /// stderr. + std::string HeaderIncludeOutputFile; + /// A list of names to use as the targets in the dependency file; this list /// must contain at least one entry. std::vector<std::string> Targets; @@ -34,6 +41,7 @@ public: public: DependencyOutputOptions() { IncludeSystemHeaders = 0; + ShowHeaderIncludes = 0; UsePhonyTargets = 0; } }; diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index c80bc037212b..f7f498bff024 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -41,9 +41,6 @@ public: unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected /// diagnostics, indicated by markers in the /// input source file. - unsigned BinaryOutput : 1; /// Emit diagnostics via the diagnostic - /// binary serialization mechanism, to be - /// deserialized by, e.g., the CIndex library. unsigned ErrorLimit; /// Limit # errors emitted. unsigned MacroBacktraceLimit; /// Limit depth of macro instantiation @@ -86,7 +83,6 @@ public: ShowSourceRanges = 0; ShowParseableFixits = 0; VerifyDiagnostics = 0; - BinaryOutput = 0; ErrorLimit = 0; TemplateBacktraceLimit = DefaultTemplateBacktraceLimit; MacroBacktraceLimit = DefaultMacroBacktraceLimit; diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index 773543ac06a5..ee0863a4776f 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -37,6 +37,7 @@ enum InputKind { IK_PreprocessedObjC, IK_PreprocessedObjCXX, IK_OpenCL, + IK_CUDA, IK_AST, IK_LLVM_IR }; @@ -51,6 +52,10 @@ class FrontendAction { CompilerInstance *Instance; friend class ASTMergeAction; +private: + ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); + protected: /// @name Implementation Action Interface /// @{ @@ -130,7 +135,7 @@ public: } ASTUnit &getCurrentASTUnit() const { - assert(!CurrentASTUnit && "No current AST unit!"); + assert(CurrentASTUnit && "No current AST unit!"); return *CurrentASTUnit; } diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 7b8063ce549c..4df2e71571f7 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -54,6 +54,12 @@ protected: llvm::StringRef InFile); }; +class ASTDumpXMLAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); +}; + class ASTViewAction : public ASTFrontendAction { protected: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, @@ -83,16 +89,11 @@ public: static bool ComputeASTConsumerArguments(CompilerInstance &CI, llvm::StringRef InFile, std::string &Sysroot, + std::string &OutputFile, llvm::raw_ostream *&OS, bool &Chaining); }; -class InheritanceViewAction : public ASTFrontendAction { -protected: - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile); -}; - class SyntaxOnlyAction : public ASTFrontendAction { protected: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h index 61ad22cabb0d..2efbc818de1b 100644 --- a/include/clang/Frontend/FrontendDiagnostic.h +++ b/include/clang/Frontend/FrontendDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define FRONTENDSTART #include "clang/Basic/DiagnosticFrontendKinds.inc" #undef DIAG diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 4c16d084fc0d..19d39c3ca1b2 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -21,6 +21,7 @@ namespace clang { namespace frontend { enum ActionKind { ASTDump, ///< Parse ASTs and dump them. + ASTDumpXML, ///< Parse ASTs and dump them in XML. ASTPrint, ///< Parse ASTs and print them. ASTPrintXML, ///< Parse ASTs and print them in XML. ASTView, ///< Parse ASTs and view them in Graphviz. @@ -38,7 +39,6 @@ namespace frontend { FixIt, ///< Parse and apply any fixits to the source. GeneratePCH, ///< Generate pre-compiled header. GeneratePTH, ///< Generate pre-tokenized header. - InheritanceView, ///< View C++ inheritance for a specified class. InitOnly, ///< Only execute frontend initialization. ParseSyntaxOnly, ///< Parse and perform semantic analysis. PluginAction, ///< Run a plugin action, \see ActionName. @@ -56,8 +56,6 @@ namespace frontend { /// FrontendOptions - Options for controlling the behavior of the frontend. class FrontendOptions { public: - unsigned DebugCodeCompletionPrinter : 1; ///< Use the debug printer for code - /// completion results. unsigned DisableFree : 1; ///< Disable memory freeing on exit. unsigned RelocatablePCH : 1; ///< When generating PCH files, /// instruct the AST writer to create @@ -86,9 +84,6 @@ public: /// The output file, if any. std::string OutputFile; - /// If given, the name for a C++ class to view the inheritance of. - std::string ViewClassInheritance; - /// If given, the new suffix for fix-it rewritten files. std::string FixItSuffix; @@ -101,9 +96,15 @@ public: /// The name of the action to run when using a plugin action. std::string ActionName; - /// Arg to pass to the plugin + /// Args to pass to the plugin std::vector<std::string> PluginArgs; + /// The list of plugin actions to run in addition to the normal action. + std::vector<std::string> AddPluginActions; + + /// Args to pass to the additional plugins + std::vector<std::vector<std::string> > AddPluginArgs; + /// The list of plugins to load. std::vector<std::string> Plugins; @@ -119,7 +120,6 @@ public: public: FrontendOptions() { - DebugCodeCompletionPrinter = 1; DisableFree = 0; ProgramAction = frontend::ParseSyntaxOnly; ActionName = ""; diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h index 588d32bf736e..cbb4a57993b7 100644 --- a/include/clang/Frontend/HeaderSearchOptions.h +++ b/include/clang/Frontend/HeaderSearchOptions.h @@ -54,6 +54,9 @@ public: /// User specified include entries. std::vector<Entry> UserEntries; + /// If non-empty, the list of C++ standard include paths to use. + std::vector<std::string> CXXSystemIncludes; + /// A (system-path) delimited list of include paths to be added from the /// environment following the user specified includes (but prior to builtin /// and standard includes). This is parsed in the same manner as the CPATH diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def index 52aa4636084d..d4046b3e5668 100644 --- a/include/clang/Frontend/LangStandards.def +++ b/include/clang/Frontend/LangStandards.def @@ -80,4 +80,9 @@ LANGSTANDARD(opencl, "cl", "OpenCL 1.0", BCPLComment | C99 | Digraphs | HexFloat) +// CUDA +LANGSTANDARD(cuda, "cuda", + "NVIDIA CUDA(tm)", + BCPLComment | CPlusPlus | Digraphs) + #undef LANGSTANDARD diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h new file mode 100644 index 000000000000..560178be9bf8 --- /dev/null +++ b/include/clang/Frontend/MultiplexConsumer.h @@ -0,0 +1,54 @@ +//===-- MultiplexConsumer.h - AST Consumer for PCH Generation ---*- 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 MultiplexConsumer class, which can be used to +// multiplex ASTConsumer and SemaConsumer messages to many consumers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaConsumer.h" +#include "llvm/ADT/OwningPtr.h" +#include <vector> + +namespace clang { + +class MultiplexASTMutationListener; +class MultiplexASTDeserializationListener; + +// Has a list of ASTConsumers and calls each of them. Owns its children. +class MultiplexConsumer : public SemaConsumer { +public: + // Takes ownership of the pointers in C. + MultiplexConsumer(const std::vector<ASTConsumer*>& C); + ~MultiplexConsumer(); + + // ASTConsumer + virtual void Initialize(ASTContext &Context); + virtual void HandleTopLevelDecl(DeclGroupRef D); + virtual void HandleInterestingDecl(DeclGroupRef D); + virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual void HandleTagDeclDefinition(TagDecl *D); + virtual void CompleteTentativeDefinition(VarDecl *D); + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired); + virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTDeserializationListener *GetASTDeserializationListener(); + virtual void PrintStats(); + + // SemaConsumer + virtual void InitializeSema(Sema &S); + virtual void ForgetSema(); + + static bool classof(const MultiplexConsumer *) { return true; } +private: + std::vector<ASTConsumer*> Consumers; // Owns these. + llvm::OwningPtr<MultiplexASTMutationListener> MutationListener; + llvm::OwningPtr<MultiplexASTDeserializationListener> DeserializationListener; +}; + +} // end namespace clang diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index 851c1f0108af..0d52e53ea16a 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -15,6 +15,7 @@ #include <string> #include <utility> #include <vector> +#include <set> namespace llvm { class MemoryBuffer; @@ -46,7 +47,18 @@ public: /// \brief When true, disables most of the normal validation performed on /// precompiled headers. bool DisablePCHValidation; - + + /// \brief When true, disables the use of the stat cache within a + /// precompiled header or AST file. + bool DisableStatCache; + + /// \brief Dump declarations that are deserialized from PCH, for testing. + bool DumpDeserializedPCHDecls; + + /// \brief This is a set of names for decls that we do not want to be + /// deserialized, and we emit an error if they are; for testing purposes. + std::set<std::string> DeserializedPCHDeclsToErrorOn; + /// \brief If non-zero, the implicit PCH include is actually a precompiled /// preamble that covers this number of bytes in the main source file. /// @@ -117,7 +129,8 @@ public: public: PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), - DisablePCHValidation(false), + DisablePCHValidation(false), DisableStatCache(false), + DumpDeserializedPCHDecls(false), PrecompiledPreambleBytes(0, true), RetainRemappedFileBuffers(false) { } diff --git a/include/clang/Frontend/PreprocessorOutputOptions.h b/include/clang/Frontend/PreprocessorOutputOptions.h index 82517c51d1c1..1eda0d40275e 100644 --- a/include/clang/Frontend/PreprocessorOutputOptions.h +++ b/include/clang/Frontend/PreprocessorOutputOptions.h @@ -18,7 +18,6 @@ class PreprocessorOutputOptions { public: unsigned ShowCPP : 1; ///< Print normal preprocessed output. unsigned ShowComments : 1; ///< Show comments. - unsigned ShowHeaderIncludes : 1; ///< Show header inclusions (-H). unsigned ShowLineMarkers : 1; ///< Show #line markers. unsigned ShowMacroComments : 1; ///< Show comments, even in macros. unsigned ShowMacros : 1; ///< Print macro definitions. @@ -27,7 +26,6 @@ public: PreprocessorOutputOptions() { ShowCPP = 1; ShowComments = 0; - ShowHeaderIncludes = 0; ShowLineMarkers = 1; ShowMacroComments = 0; ShowMacros = 0; diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def index c03a5a883569..8a859e6898b1 100644 --- a/include/clang/Frontend/StmtXML.def +++ b/include/clang/Frontend/StmtXML.def @@ -415,13 +415,6 @@ NODE_XML(StmtExpr, "StmtExpr") // StmtExpr contains a s SUB_NODE_XML(CompoundStmt) END_NODE_XML -NODE_XML(TypesCompatibleExpr, "TypesCompatibleExpr") // GNU builtin-in function __builtin_types_compatible_p - ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_XML(getArgType1(), "type1_ref") // id of type1 - ATTRIBUTE_XML(getArgType2(), "type2_ref") // id of type2 -END_NODE_XML - NODE_XML(ChooseExpr, "ChooseExpr") // GNU builtin-in function __builtin_choose_expr(expr1, expr2, expr3) ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def index 1536c924a82f..b78e70f5aa86 100644 --- a/include/clang/Frontend/TypeXML.def +++ b/include/clang/Frontend/TypeXML.def @@ -98,7 +98,8 @@ NODE_XML(BuiltinType, "FundamentalType") ENUM_XML(BuiltinType::Float, "float"); ENUM_XML(BuiltinType::Double, "double"); ENUM_XML(BuiltinType::LongDouble, "long double"); - ENUM_XML(BuiltinType::WChar, "wchar_t"); + ENUM_XML(BuiltinType::WChar_U, "wchar_t"); + ENUM_XML(BuiltinType::WChar_S, "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'. @@ -130,6 +131,13 @@ NODE_XML(FunctionProtoType, "FunctionType") ID_ATTRIBUTE_XML ATTRIBUTE_XML(getResultType(), "result_type") ATTRIBUTE_OPT_XML(isVariadic(), "variadic") + ATTRIBUTE_ENUM_XML(getCallConv(), "call_conv") + ENUM_XML(CC_Default, "") + ENUM_XML(CC_C, "C") + ENUM_XML(CC_X86StdCall, "X86StdCall") + ENUM_XML(CC_X86FastCall, "X86FastCall") + ENUM_XML(CC_X86ThisCall, "X86ThisCall") + END_ENUM_XML END_NODE_XML NODE_XML(TypedefType, "Typedef") diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index fe722db381d0..485161b1bc38 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -73,6 +73,18 @@ bool CheckDiagnostics(Preprocessor &PP); void AttachDependencyFileGen(Preprocessor &PP, const DependencyOutputOptions &Opts); +/// AttachHeaderIncludeGen - Create a header include list generator, and attach +/// it to the given preprocessor. +/// +/// \param ShowAllHeaders - If true, show all header information instead of just +/// headers following the predefines buffer. This is useful for making sure +/// includes mentioned on the command line are also reported, but differs from +/// the default behavior used by -H. +/// \param OutputPath - If non-empty, a path to write the header include +/// information to, instead of writing to stderr. +void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false, + llvm::StringRef OutputPath = ""); + /// CacheTokens - Cache tokens for use with PCH. Note that this requires /// a seekable stream. void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS); diff --git a/include/clang/Frontend/VerifyDiagnosticsClient.h b/include/clang/Frontend/VerifyDiagnosticsClient.h index 6f45e49ec0ef..793cedd8578f 100644 --- a/include/clang/Frontend/VerifyDiagnosticsClient.h +++ b/include/clang/Frontend/VerifyDiagnosticsClient.h @@ -68,7 +68,6 @@ public: llvm::OwningPtr<DiagnosticClient> PrimaryClient; llvm::OwningPtr<TextDiagnosticBuffer> Buffer; Preprocessor *CurrentPreprocessor; - unsigned NumErrors; private: void CheckDiagnostics(); @@ -88,9 +87,6 @@ public: virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info); - - /// HadErrors - Check if there were any mismatches in expected diagnostics. - bool HadErrors(); }; } // end namspace clang diff --git a/include/clang/Lex/CMakeLists.txt b/include/clang/Lex/CMakeLists.txt new file mode 100644 index 000000000000..b823e83f906b --- /dev/null +++ b/include/clang/Lex/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_TARGET_DEFINITIONS ../Basic/Attr.td) +tablegen(AttrSpellings.inc + -gen-clang-attr-spelling-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../) +add_custom_target(ClangAttrSpellings + DEPENDS AttrSpellings.inc) diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h index 791d3fe304ec..dbf738903371 100644 --- a/include/clang/Lex/ExternalPreprocessorSource.h +++ b/include/clang/Lex/ExternalPreprocessorSource.h @@ -27,6 +27,9 @@ public: /// \brief Read the set of macros defined by this external macro source. virtual void ReadDefinedMacros() = 0; + + /// \brief Read the definition for the given macro. + virtual void LoadMacroDefinition(IdentifierInfo *II) = 0; }; } diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h index 9837e296535f..8a5c83ecf495 100644 --- a/include/clang/Lex/HeaderMap.h +++ b/include/clang/Lex/HeaderMap.h @@ -43,7 +43,7 @@ public: /// 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); + static const HeaderMap *Create(const FileEntry *FE, FileManager &FM); /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index 80b38dee06af..30bd4f58549c 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -29,7 +29,7 @@ class IdentifierInfo; /// file that is #included. struct HeaderFileInfo { /// isImport - True if this is a #import'd or #pragma once file. - bool isImport : 1; + unsigned 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 @@ -37,10 +37,24 @@ struct HeaderFileInfo { /// SrcMgr::CharacteristicKind. unsigned DirInfo : 2; + /// \brief Whether this header file info was supplied by an external source. + unsigned External : 1; + + /// \brief Whether this structure is considered to already have been + /// "resolved", meaning that it was loaded from the external source. + unsigned Resolved : 1; + /// NumIncludes - This is the number of times the file has been included /// already. unsigned short NumIncludes; + /// \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; + /// 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,27 +65,40 @@ struct HeaderFileInfo { /// external storage. const IdentifierInfo *ControllingMacro; - /// \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() - : isImport(false), DirInfo(SrcMgr::C_User), - NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {} + : isImport(false), DirInfo(SrcMgr::C_User), External(false), + Resolved(false), NumIncludes(0), ControllingMacroID(0), + ControllingMacro(0) {} /// \brief Retrieve the controlling macro for this header file, if /// any. const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External); + + /// \brief Determine whether this is a non-default header file info, e.g., + /// it corresponds to an actual header we've included or tried to include. + bool isNonDefault() const { + return isImport || NumIncludes || ControllingMacro || ControllingMacroID; + } }; +/// \brief An external source of header file information, which may supply +/// information about header files already included. +class ExternalHeaderFileInfoSource { +public: + virtual ~ExternalHeaderFileInfoSource(); + + /// \brief Retrieve the header file information for the given file entry. + /// + /// \returns Header file information for the given file entry, with the + /// \c External bit set. If the file entry is not known, return a + /// default-constructed \c HeaderFileInfo. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0; +}; + /// HeaderSearch - This class encapsulates the information needed to find the /// 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 @@ -108,6 +135,9 @@ class HeaderSearch { /// macros into IdentifierInfo pointers, as needed. ExternalIdentifierLookup *ExternalLookup; + /// \brief Entity used to look up stored header file information. + ExternalHeaderFileInfoSource *ExternalSource; + // Various statistics we track for performance analysis. unsigned NumIncluded; unsigned NumMultiIncludeFileOptzn; @@ -142,6 +172,15 @@ public: ExternalLookup = EIL; } + ExternalIdentifierLookup *getExternalLookup() const { + return ExternalLookup; + } + + /// \brief Set the external source of header information. + void SetExternalSource(ExternalHeaderFileInfoSource *ES) { + ExternalSource = ES; + } + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// a <> reference. If successful, this returns 'UsedDir', the diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h index 2d941e4cf4fe..5fcb8eb2d1a4 100644 --- a/include/clang/Lex/LexDiagnostic.h +++ b/include/clang/Lex/LexDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define LEXSTART #include "clang/Basic/DiagnosticLexKinds.inc" #undef DIAG diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 9e0fb7ee70ea..fc9a8de43482 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -211,6 +211,32 @@ public: /// and " characters. This does not add surrounding ""'s to the string. static void Stringify(llvm::SmallVectorImpl<char> &Str); + + /// 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 + /// Tok.getLength() bytes long. The length of the actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + static unsigned getSpelling(const Token &Tok, const char *&Buffer, + const SourceManager &SourceMgr, + const LangOptions &Features, + bool *Invalid = 0); + + /// 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. + static std::string getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + const LangOptions &Features, + bool *Invalid = 0); + /// 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 @@ -228,6 +254,33 @@ public: const SourceManager &SM, const LangOptions &LangOpts); + /// AdvanceToTokenCharacter - If the current SourceLocation specifies a + /// location at the start of a token, return a new location that specifies a + /// character within the token. This handles trigraphs and escaped newlines. + static SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Character, + const SourceManager &SM, + const LangOptions &Features); + + /// \brief Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, + const SourceManager &SM, + const LangOptions &Features); + /// \brief Compute the preamble of the given file. /// /// The preamble of a file contains the initial comments, include directives, diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index ba46fb18a68a..bf2c06becdbf 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -15,10 +15,11 @@ #ifndef CLANG_LITERALSUPPORT_H #define CLANG_LITERALSUPPORT_H -#include <string> #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" +#include <cctype> +#include <string> namespace clang { @@ -27,6 +28,8 @@ class Preprocessor; class Token; class SourceLocation; class TargetInfo; +class SourceManager; +class LangOptions; /// NumericLiteralParser - This performs strict semantic analysis of the content /// of a ppnumber, classifying it as either integer, floating, or erroneous, @@ -138,8 +141,11 @@ public: /// wide string analysis and Translation Phase #6 (concatenation of string /// literals) (C99 5.1.1.2p1). class StringLiteralParser { - Preprocessor &PP; - + const SourceManager &SM; + const LangOptions &Features; + const TargetInfo &Target; + Diagnostic *Diags; + unsigned MaxTokenLength; unsigned SizeBound; unsigned wchar_tByteWidth; @@ -148,6 +154,14 @@ class StringLiteralParser { public: StringLiteralParser(const Token *StringToks, unsigned NumStringToks, Preprocessor &PP, bool Complain = true); + StringLiteralParser(const Token *StringToks, unsigned NumStringToks, + const SourceManager &sm, const LangOptions &features, + const TargetInfo &target, Diagnostic *diags = 0) + : SM(sm), Features(features), Target(target), Diags(diags) { + init(StringToks, NumStringToks); + } + + bool hadError; bool AnyWide; bool Pascal; @@ -163,8 +177,13 @@ public: /// 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, bool Complain = true); + /// + /// If the Diagnostics pointer is non-null, then this will do semantic + /// checking of the string literal and emit errors and warnings. + unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const; + +private: + void init(const Token *StringToks, unsigned NumStringToks); }; } // end namespace clang diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 90f95b7acee3..717c3008eca9 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -82,6 +82,9 @@ private: /// AllowRedefinitionsWithoutWarning - True if this macro can be redefined /// without emitting a warning. bool IsAllowRedefinitionsWithoutWarning : 1; + + /// \brief Must warn if the macro is unused at the end of translation unit. + bool IsWarnIfUnused : 1; ~MacroInfo() { assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); @@ -138,6 +141,11 @@ public: IsAllowRedefinitionsWithoutWarning = Val; } + /// \brief Set the value of the IsWarnIfUnused flag. + void setIsWarnIfUnused(bool val) { + IsWarnIfUnused = val; + } + /// setArgumentList - Set the specified list of identifiers as the argument /// list for this macro. void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs, @@ -201,6 +209,11 @@ public: return IsAllowRedefinitionsWithoutWarning; } + /// \brief Return true if we should emit a warning if the macro is unused. + bool isWarnIfUnused() const { + return IsWarnIfUnused; + } + /// getNumTokens - Return the number of tokens that this macro expands to. /// unsigned getNumTokens() const { diff --git a/include/clang/Lex/Makefile b/include/clang/Lex/Makefile new file mode 100644 index 000000000000..9874bcffb3e1 --- /dev/null +++ b/include/clang/Lex/Makefile @@ -0,0 +1,13 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = AttrSpellings.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/AttrSpellings.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute spellings with tblgen" + $(Verb) $(TableGen) -gen-clang-attr-spelling-list -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 782f2d57a5c6..b2a80a62985f 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -54,12 +54,43 @@ public: SrcMgr::CharacteristicKind FileType) { } + /// \brief This callback is invoked whenever an inclusion directive of + /// any kind (\c #include, \c #import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param EndLoc The location of the last token within the inclusion + /// directive. + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + llvm::StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc) { + } + /// EndOfMainFile - This callback is invoked when the end of the main file is /// reach, no subsequent callbacks will be made. virtual void EndOfMainFile() { } /// Ident - This callback is invoked when a #ident or #sccs directive is read. + /// \param Loc The location of the directive. + /// \param str The text of the directive. /// virtual void Ident(SourceLocation Loc, const std::string &str) { } @@ -73,6 +104,8 @@ public: /// PragmaMessage - This callback is invoked when a #pragma message directive /// is read. + /// \param Loc The location of the message directive. + /// \param str The text of the message directive. /// virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) { } @@ -80,17 +113,48 @@ public: /// MacroExpands - This is called by /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is /// found. - virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI) { } /// MacroDefined - This hook is called whenever a macro definition is seen. - virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { } /// MacroUndefined - This hook is called whenever a macro #undef is seen. /// MI is released immediately following this callback. - virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II, - const MacroInfo *MI) { + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + } + + /// If -- This hook is called whenever an #if is seen. + /// \param Range The SourceRange of the expression being tested. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void If(SourceRange Range) { + } + + /// Elif -- This hook is called whenever an #elif is seen. + /// \param Range The SourceRange of the expression being tested. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elif(SourceRange Range) { + } + + /// Ifdef -- This hook is called whenever an #ifdef is seen. + /// \param Loc The location of the token being tested. + /// \param II Information on the token being tested. + virtual void Ifdef(const Token &MacroNameTok) { + } + + /// Ifndef -- This hook is called whenever an #ifndef is seen. + /// \param Loc The location of the token being tested. + /// \param II Information on the token being tested. + virtual void Ifndef(const Token &MacroNameTok) { + } + + /// Else -- This hook is called whenever an #else is seen. + virtual void Else() { + } + + /// Endif -- This hook is called whenever an #endif is seen. + virtual void Endif() { } }; @@ -119,6 +183,18 @@ public: Second->FileSkipped(ParentFile, FilenameTok, FileType); } + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + llvm::StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc) { + First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File, + EndLoc); + Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File, + EndLoc); + } + virtual void EndOfMainFile() { First->EndOfMainFile(); Second->EndOfMainFile(); @@ -140,20 +216,55 @@ public: Second->PragmaMessage(Loc, Str); } - virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { - First->MacroExpands(Id, MI); - Second->MacroExpands(Id, MI); + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI) { + First->MacroExpands(MacroNameTok, MI); + Second->MacroExpands(MacroNameTok, MI); + } + + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + First->MacroDefined(MacroNameTok, MI); + Second->MacroDefined(MacroNameTok, MI); + } + + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + First->MacroUndefined(MacroNameTok, MI); + Second->MacroUndefined(MacroNameTok, MI); + } + + /// If -- This hook is called whenever an #if is seen. + virtual void If(SourceRange Range) { + First->If(Range); + Second->If(Range); + } + + /// Elif -- This hook is called whenever an #if is seen. + virtual void Elif(SourceRange Range) { + First->Elif(Range); + Second->Elif(Range); + } + + /// Ifdef -- This hook is called whenever an #ifdef is seen. + virtual void Ifdef(const Token &MacroNameTok) { + First->Ifdef(MacroNameTok); + Second->Ifdef(MacroNameTok); + } + + /// Ifndef -- This hook is called whenever an #ifndef is seen. + virtual void Ifndef(const Token &MacroNameTok) { + First->Ifndef(MacroNameTok); + Second->Ifndef(MacroNameTok); } - virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { - First->MacroDefined(II, MI); - Second->MacroDefined(II, MI); + /// Else -- This hook is called whenever an #else is seen. + virtual void Else() { + First->Else(); + Second->Else(); } - virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II, - const MacroInfo *MI) { - First->MacroUndefined(Loc, II, MI); - Second->MacroUndefined(Loc, II, MI); + /// Endif -- This hook is called whenever an #endif is seen. + virtual void Endif() { + First->Endif(); + Second->Endif(); } }; diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h index 5e8a4f144c96..094b7ef66798 100644 --- a/include/clang/Lex/PTHManager.h +++ b/include/clang/Lex/PTHManager.h @@ -31,7 +31,7 @@ namespace clang { class FileEntry; class PTHLexer; class Diagnostic; -class StatSysCallCache; +class FileSystemStatCache; class PTHManager : public IdentifierInfoLookup { friend class PTHLexer; @@ -128,11 +128,11 @@ public: /// It is the responsibility of the caller to 'delete' the returned object. PTHLexer *CreateLexer(FileID FID); - /// createStatCache - Returns a StatSysCallCache object for use with + /// createStatCache - Returns a FileSystemStatCache 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(); + FileSystemStatCache *createStatCache(); }; } // end namespace clang diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h index c68555b2f967..8bd22369476e 100644 --- a/include/clang/Lex/Pragma.h +++ b/include/clang/Lex/Pragma.h @@ -25,6 +25,28 @@ namespace clang { class IdentifierInfo; class PragmaNamespace; + /** + * \brief Describes how the pragma was introduced, e.g., with #pragma, + * _Pragma, or __pragma. + */ + enum PragmaIntroducerKind { + /** + * \brief The pragma was introduced via #pragma. + */ + PIK_HashPragma, + + /** + * \brief The pragma was introduced via the C99 _Pragma(string-literal). + */ + PIK__Pragma, + + /** + * \brief The pragma was introduced via the Microsoft + * __pragma(token-string). + */ + PIK___pragma + }; + /// PragmaHandler - Instances of this interface defined to handle the various /// pragmas that the language front-end uses. Each handler optionally has a /// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with @@ -42,7 +64,8 @@ public: virtual ~PragmaHandler(); llvm::StringRef getName() const { return Name; } - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken) = 0; + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) = 0; /// getIfNamespace - If this is a namespace, return it. This is equivalent to /// using a dynamic_cast, but doesn't require RTTI. @@ -55,7 +78,8 @@ class EmptyPragmaHandler : public PragmaHandler { public: EmptyPragmaHandler(); - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; /// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas, @@ -90,7 +114,8 @@ public: return Handlers.empty(); } - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); virtual PragmaNamespace *getIfNamespace() { return this; } }; diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 730f04f2fa09..afd7ae1187cc 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -35,6 +35,7 @@ void operator delete(void* ptr, clang::PreprocessingRecord& PR, namespace clang { class MacroDefinition; + class FileEntry; /// \brief Base class that describes a preprocessed entity, which may be a /// preprocessor directive or macro instantiation. @@ -54,8 +55,12 @@ namespace clang { /// \brief A macro definition. MacroDefinitionKind, + /// \brief An inclusion directive, such as \c #include, \c + /// #import, or \c #include_next. + InclusionDirectiveKind, + FirstPreprocessingDirective = PreprocessingDirectiveKind, - LastPreprocessingDirective = MacroDefinitionKind + LastPreprocessingDirective = InclusionDirectiveKind }; private: @@ -173,6 +178,66 @@ namespace clang { } static bool classof(const MacroDefinition *) { return true; } }; + + /// \brief Record the location of an inclusion directive, such as an + /// \c #include or \c #import statement. + class InclusionDirective : public PreprocessingDirective { + public: + /// \brief The kind of inclusion directives known to the + /// preprocessor. + enum InclusionKind { + /// \brief An \c #include directive. + Include, + /// \brief An Objective-C \c #import directive. + Import, + /// \brief A GNU \c #include_next directive. + IncludeNext, + /// \brief A Clang \c #__include_macros directive. + IncludeMacros + }; + + private: + /// \brief The name of the file that was included, as written in + /// the source. + llvm::StringRef FileName; + + /// \brief Whether the file name was in quotation marks; otherwise, it was + /// in angle brackets. + unsigned InQuotes : 1; + + /// \brief The kind of inclusion directive we have. + /// + /// This is a value of type InclusionKind. + unsigned Kind : 2; + + /// \brief The file that was included. + const FileEntry *File; + + public: + InclusionDirective(PreprocessingRecord &PPRec, + InclusionKind Kind, llvm::StringRef FileName, + bool InQuotes, const FileEntry *File, SourceRange Range); + + /// \brief Determine what kind of inclusion directive this is. + InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); } + + /// \brief Retrieve the included file name as it was written in the source. + llvm::StringRef getFileName() const { return FileName; } + + /// \brief Determine whether the included file name was written in quotes; + /// otherwise, it was written in angle brackets. + bool wasInQuotes() const { return InQuotes; } + + /// \brief Retrieve the file entry for the actual file that was included + /// by this directive. + const FileEntry *getFile() const { return File; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == InclusionDirectiveKind; + } + static bool classof(const InclusionDirective *) { return true; } + }; /// \brief An abstract class that should be subclassed by any external source /// of preprocessing record entries. @@ -183,6 +248,10 @@ namespace clang { /// \brief Read any preallocated preprocessed entities from the external /// source. virtual void ReadPreprocessedEntities() = 0; + + /// \brief Read the preprocessed entity at the given offset. + virtual PreprocessedEntity * + ReadPreprocessedEntityAtOffset(uint64_t Offset) = 0; }; /// \brief A record of the steps taken while preprocessing a source file, @@ -229,13 +298,22 @@ namespace clang { iterator end(bool OnlyLocalEntities = false); const_iterator begin(bool OnlyLocalEntities = false) const; const_iterator end(bool OnlyLocalEntities = false) const; - + /// \brief Add a new preprocessed entity to this record. void addPreprocessedEntity(PreprocessedEntity *Entity); /// \brief Set the external source for preprocessed entities. void SetExternalSource(ExternalPreprocessingRecordSource &Source, unsigned NumPreallocatedEntities); + + /// \brief Retrieve the external source for preprocessed entities. + ExternalPreprocessingRecordSource *getExternalSource() const { + return ExternalSource; + } + + unsigned getNumPreallocatedEntities() const { + return NumPreallocatedEntities; + } /// \brief Set the preallocated entry at the given index to the given /// preprocessed entity. @@ -256,9 +334,14 @@ namespace clang { MacroDefinition *findMacroDefinition(const MacroInfo *MI); virtual void MacroExpands(const Token &Id, const MacroInfo* MI); - virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI); - virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II, - const MacroInfo *MI); + virtual void MacroDefined(const Token &Id, const MacroInfo *MI); + virtual void MacroUndefined(const Token &Id, const MacroInfo *MI); + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + llvm::StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc); }; } // end namespace clang diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 6b9b89ea5eb9..018f7e9c8c02 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_LEX_PREPROCESSOR_H #define LLVM_CLANG_LEX_PREPROCESSOR_H +#include "clang/Lex/MacroInfo.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/PTHLexer.h" #include "clang/Lex/PPCallbacks.h" @@ -24,6 +25,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" @@ -82,6 +84,7 @@ class Preprocessor { IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_attribute; // __has_attribute IdentifierInfo *Ident__has_include; // __has_include IdentifierInfo *Ident__has_include_next; // __has_include_next @@ -194,10 +197,15 @@ class Preprocessor { /// 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. - /// FIXME: why not use a singly linked list? - std::vector<MacroInfo*> MICache; + /// \brief Macros that we want to warn because they are not used at the end + /// of the translation unit; we store just their SourceLocations instead + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + /// We are using SmallPtrSet instead of a vector for faster removal. + typedef llvm::SmallPtrSet<SourceLocation, 32> WarnUnusedMacroLocsTy; + WarnUnusedMacroLocsTy WarnUnusedMacroLocs; /// MacroArgCache - This is a "freelist" of MacroArg objects that can be /// reused for quick allocation. @@ -251,6 +259,22 @@ private: // Cached tokens state. /// invoked (at which point the last position is popped). std::vector<CachedTokensTy::size_type> BacktrackPositions; + struct MacroInfoChain { + MacroInfo MI; + MacroInfoChain *Next; + MacroInfoChain *Prev; + }; + + /// MacroInfos are managed as a chain for easy disposal. This is the head + /// of that list. + MacroInfoChain *MIChainHead; + + /// MICache - A "freelist" of MacroInfo objects that can be reused for quick + /// allocation. + MacroInfoChain *MICache; + + MacroInfo *getInfoForMacro(IdentifierInfo *II) const; + public: Preprocessor(Diagnostic &diags, const LangOptions &opts, const TargetInfo &target, @@ -324,7 +348,10 @@ public: /// 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; + if (!II->hasMacroDefinition()) + return 0; + + return getInfoForMacro(II); } /// setMacroInfo - Specify a macro for this identifier. @@ -591,6 +618,9 @@ public: /// for which we are performing code completion. bool isCodeCompletionFile(SourceLocation FileLoc) const; + /// \brief Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != 0; } + /// \brief Instruct the preprocessor to skip part of the main /// the main source file. /// @@ -607,12 +637,11 @@ public: /// the specified Token's location, translating the token's start /// position in the current buffer into a SourcePosition object for rendering. DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { - return Diags->Report(FullSourceLoc(Loc, getSourceManager()), DiagID); + return Diags->Report(Loc, DiagID); } DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) { - return Diags->Report(FullSourceLoc(Tok.getLocation(), getSourceManager()), - DiagID); + return Diags->Report(Tok.getLocation(), DiagID); } /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a @@ -622,17 +651,9 @@ public: /// UCNs, etc. /// /// \param Invalid If non-NULL, will be set \c true if an error occurs. - std::string getSpelling(const Token &Tok, bool *Invalid = 0) const; - - /// 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. - static std::string getSpelling(const Token &Tok, - const SourceManager &SourceMgr, - const LangOptions &Features, - bool *Invalid = 0); + std::string getSpelling(const Token &Tok, bool *Invalid = 0) const { + return Lexer::getSpelling(Tok, SourceMgr, Features, Invalid); + } /// 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 @@ -645,7 +666,9 @@ public: /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. unsigned getSpelling(const Token &Tok, const char *&Buffer, - bool *Invalid = 0) const; + bool *Invalid = 0) const { + return Lexer::getSpelling(Tok, Buffer, SourceMgr, Features, Invalid); + } /// getSpelling - This method is used to get the spelling of a token into a /// SmallVector. Note that the returned StringRef may not point to the @@ -692,7 +715,9 @@ public: /// location should refer to. The default offset (0) produces a source /// location pointing just past the end of the token; an offset of 1 produces /// a source location pointing to the last character in the token, etc. - SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) { + return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, Features); + } /// DumpToken - Print the token to stderr, used for debugging. /// @@ -702,7 +727,10 @@ public: /// 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); + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Char) const { + return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, Features); + } /// IncrementPasteCounter - Increment the counters for the number of token /// paste operations performed. If fast was specified, this is a 'fast paste' @@ -726,10 +754,10 @@ public: // Preprocessor callback methods. These are invoked by a lexer as various // directives and events are found. - /// LookUpIdentifierInfo - Given a tok::identifier token, look up the - /// identifier information for the token and install it into the token. - IdentifierInfo *LookUpIdentifierInfo(Token &Identifier, - const char *BufPtr = 0) const; + /// LookUpIdentifierInfo - Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; /// HandleIdentifier - This callback is invoked when the lexer reads an /// identifier and has filled in the tokens IdentifierInfo member. This @@ -812,7 +840,12 @@ public: /// This code concatenates and consumes tokens up to the '>' token. It /// returns false if the > was found, otherwise it returns true if it finds /// and consumes the EOM marker. - bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer); + bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer, + SourceLocation &End); + + /// LexOnOffSwitch - Lex an on-off-switch (C99 6.10.6p2) and verify that it is + /// followed by EOM. Return true if the token is not a valid on-off-switch. + bool LexOnOffSwitch(tok::OnOffSwitch &OOS); private: @@ -909,8 +942,8 @@ private: /// is not enclosed within a string literal. void HandleMicrosoft__pragma(Token &Tok); - void Handle_Pragma(const std::string &StrVal, SourceLocation PragmaLoc, - SourceLocation RParenLoc); + void Handle_Pragma(unsigned Introducer, const std::string &StrVal, + SourceLocation PragmaLoc, SourceLocation RParenLoc); /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and /// start lexing tokens from it instead of the current buffer. @@ -961,12 +994,13 @@ private: void HandleIdentSCCSDirective(Token &Tok); // File inclusion. - void HandleIncludeDirective(Token &Tok, + void HandleIncludeDirective(SourceLocation HashLoc, + Token &Tok, const DirectoryLookup *LookupFrom = 0, bool isImport = false); - void HandleIncludeNextDirective(Token &Tok); - void HandleIncludeMacrosDirective(Token &Tok); - void HandleImportDirective(Token &Tok); + void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); + void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); + void HandleImportDirective(SourceLocation HashLoc, Token &Tok); // Macro handling. void HandleDefineDirective(Token &Tok); @@ -981,7 +1015,7 @@ private: void HandleElifDirective(Token &Tok); // Pragmas. - void HandlePragmaDirective(); + void HandlePragmaDirective(unsigned Introducer); public: void HandlePragmaOnce(Token &OnceTok); void HandlePragmaMark(); @@ -997,6 +1031,10 @@ public: // Return true and store the first token only if any CommentHandler // has inserted some tokens and getCommentRetentionState() is false. bool HandleComment(Token &Token, SourceRange Comment); + + /// \brief A macro is used, update information about macros that need unused + /// warnings. + void markMacroAsUsed(MacroInfo *MI); }; /// \brief Abstract base class that describes a handler that will receive diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h index 477a2130cf0e..d8332938a7ed 100644 --- a/include/clang/Lex/PreprocessorLexer.h +++ b/include/clang/Lex/PreprocessorLexer.h @@ -155,6 +155,18 @@ public: /// getFileEntry - Return the FileEntry corresponding to this FileID. Like /// getFileID(), this only works for lexers with attached preprocessors. const FileEntry *getFileEntry() const; + + /// \brief Iterator that traverses the current stack of preprocessor + /// conditional directives (#if/#ifdef/#ifndef). + typedef llvm::SmallVectorImpl<PPConditionalInfo>::const_iterator + conditional_iterator; + + conditional_iterator conditional_begin() const { + return ConditionalStack.begin(); + } + conditional_iterator conditional_end() const { + return ConditionalStack.end(); + } }; } // end namespace clang diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 954b36ec6d11..edcfcc10d2ee 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -76,7 +76,8 @@ public: StartOfLine = 0x01, // At start of line or only after whitespace. LeadingSpace = 0x02, // Whitespace exists before this token. DisableExpand = 0x04, // This identifier may never be macro expanded. - NeedsCleaning = 0x08 // Contained an escaped newline or trigraph. + NeedsCleaning = 0x08, // Contained an escaped newline or trigraph. + LeadingEmptyMacro = 0x10 // Empty macro exists before this token. }; tok::TokenKind getKind() const { return (tok::TokenKind)Kind; } @@ -87,6 +88,12 @@ public: bool is(tok::TokenKind K) const { return Kind == (unsigned) K; } bool isNot(tok::TokenKind K) const { return Kind != (unsigned) K; } + /// isAnyIdentifier - Return true if this is a raw identifier (when lexing + /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). + bool isAnyIdentifier() const { + return is(tok::identifier) || is(tok::raw_identifier); + } + /// isLiteral - Return true if this is a "literal", like a numeric /// constant, string, etc. bool isLiteral() const { @@ -96,9 +103,11 @@ public: } bool isAnnotation() const { - return is(tok::annot_typename) || - is(tok::annot_cxxscope) || - is(tok::annot_template_id); +#define ANNOTATION(NAME) \ + if (is(tok::annot_##NAME)) \ + return true; +#include "clang/Basic/TokenKinds.def" + return false; } /// getLocation - Return a source location identifier for the specified @@ -153,7 +162,10 @@ public: } IdentifierInfo *getIdentifierInfo() const { - assert(!isAnnotation() && "Used IdentInfo on annotation token!"); + assert(isNot(tok::raw_identifier) && + "getIdentifierInfo() on a tok::raw_identifier token!"); + assert(!isAnnotation() && + "getIdentifierInfo() on an annotation token!"); if (isLiteral()) return 0; return (IdentifierInfo*) PtrData; } @@ -161,6 +173,18 @@ public: PtrData = (void*) II; } + /// getRawIdentifierData - For a raw identifier token (i.e., an identifier + /// lexed in raw mode), returns a pointer to the start of it in the text + /// buffer if known, null otherwise. + const char *getRawIdentifierData() const { + assert(is(tok::raw_identifier)); + return reinterpret_cast<const char*>(PtrData); + } + void setRawIdentifierData(const char *Ptr) { + assert(is(tok::raw_identifier)); + PtrData = const_cast<char*>(Ptr); + } + /// 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. @@ -231,7 +255,13 @@ public: /// newlines in it. /// bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; } - + + /// \brief Return true if this token has an empty macro before it. + /// + bool hasLeadingEmptyMacro() const { + return (Flags & LeadingEmptyMacro) ? true : false; + } + }; /// PPConditionalInfo - Information about the conditional stack (#if directives) diff --git a/include/clang/Makefile b/include/clang/Makefile index 030b0720fd81..d6b9844285d2 100644 --- a/include/clang/Makefile +++ b/include/clang/Makefile @@ -1,5 +1,5 @@ CLANG_LEVEL := ../.. -DIRS := AST Basic Driver Serialization +DIRS := AST Basic Driver Lex Serialization include $(CLANG_LEVEL)/Makefile diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h index d7c5eee8d916..f640b37c1982 100644 --- a/include/clang/Parse/ParseDiagnostic.h +++ b/include/clang/Parse/ParseDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define PARSESTART #include "clang/Basic/DiagnosticParseKinds.inc" #undef DIAG diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 41a2fb615791..758792097639 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -25,8 +25,6 @@ #include <list> namespace clang { - class AttributeList; - struct CXX0XAttributeList; class PragmaHandler; class Scope; class DeclGroupRef; @@ -34,7 +32,8 @@ namespace clang { class Parser; class PragmaUnusedHandler; class ColonProtectionRAIIObject; - + class InMessageExpressionRAIIObject; + /// PrettyStackTraceParserEntry - If a crash happens while the parser is active, /// an entry is printed for it. class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { @@ -75,6 +74,7 @@ namespace prec { class Parser : public CodeCompletionHandler { friend class PragmaUnusedHandler; friend class ColonProtectionRAIIObject; + friend class InMessageExpressionRAIIObject; friend class ParenBraceBracketBalancer; PrettyStackTraceParserEntry CrashInfo; @@ -112,12 +112,18 @@ class Parser : public CodeCompletionHandler { IdentifierInfo *Ident_vector; IdentifierInfo *Ident_pixel; + /// C++0x contextual keywords. + mutable IdentifierInfo *Ident_final; + mutable IdentifierInfo *Ident_override; + llvm::OwningPtr<PragmaHandler> AlignHandler; llvm::OwningPtr<PragmaHandler> GCCVisibilityHandler; llvm::OwningPtr<PragmaHandler> OptionsHandler; llvm::OwningPtr<PragmaHandler> PackHandler; llvm::OwningPtr<PragmaHandler> UnusedHandler; llvm::OwningPtr<PragmaHandler> WeakHandler; + llvm::OwningPtr<PragmaHandler> FPContractHandler; + llvm::OwningPtr<PragmaHandler> OpenCLExtensionHandler; /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ @@ -131,8 +137,18 @@ class Parser : public CodeCompletionHandler { /// ColonProtectionRAIIObject RAII object. bool ColonIsSacred; + /// \brief When true, we are directly inside an Ojective-C messsage + /// send expression. + /// + /// This is managed by the \c InMessageExpressionRAIIObject class, and + /// should not be set directly. + bool InMessageExpression; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; + + /// Factory object for creating AttributeList objects. + AttributeList::Factory AttrFactory; public: Parser(Preprocessor &PP, Sema &Actions); @@ -152,7 +168,7 @@ public: typedef Stmt StmtTy; typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; typedef CXXBaseSpecifier BaseTy; - typedef CXXBaseOrMemberInitializer MemInitTy; + typedef CXXCtorInitializer MemInitTy; typedef NestedNameSpecifier CXXScopeTy; typedef TemplateParameterList TemplateParamsTy; typedef OpaquePtr<TemplateName> TemplateTy; @@ -227,6 +243,11 @@ private: Tok.getKind() == tok::wide_string_literal; } + /// \brief Returns true if the current token is a '=' or '==' and + /// false otherwise. If it's '==', we assume that it's a typo and we emit + /// DiagID and a fixit hint to turn '==' -> '='. + bool isTokenEqualOrMistypedEqualEqual(unsigned DiagID); + /// ConsumeToken - Consume the current 'peek token' and lex the next one. /// This does not work with all kinds of tokens: strings and specific other /// tokens must be consumed with custom methods below. This returns the @@ -330,6 +351,9 @@ private: /// based on context. void CodeCompletionRecovery(); + /// \brief Handle the annotation token produced for #pragma unused(...) + void HandlePragmaUnused(); + /// 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. @@ -464,6 +488,13 @@ private: const char *DiagMsg = "", tok::TokenKind SkipToTok = tok::unknown); + /// \brief The parser expects a semicolon and, if present, will consume it. + /// + /// If the next token is not a semicolon, this emits the specified diagnostic, + /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior + /// to the semicolon, consumes that extra token. + bool ExpectAndConsumeSemi(unsigned DiagID); + //===--------------------------------------------------------------------===// // Scope manipulation @@ -531,21 +562,59 @@ private: /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, - bool DontConsume = false) { - return SkipUntil(&T, 1, StopAtSemi, DontConsume); + bool DontConsume = false, bool StopAtCodeCompletion = false) { + return SkipUntil(&T, 1, StopAtSemi, DontConsume, StopAtCodeCompletion); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true, - bool DontConsume = false) { + bool DontConsume = false, bool StopAtCodeCompletion = false) { tok::TokenKind TokArray[] = {T1, T2}; - return SkipUntil(TokArray, 2, StopAtSemi, DontConsume); + return SkipUntil(TokArray, 2, StopAtSemi, DontConsume,StopAtCodeCompletion); } bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi = true, bool DontConsume = false); + bool StopAtSemi = true, bool DontConsume = false, + bool StopAtCodeCompletion = false); //===--------------------------------------------------------------------===// // Lexing and parsing of C++ inline methods. - struct LexedMethod { + struct ParsingClass; + + /// [class.mem]p1: "... the class is regarded as complete within + /// - function bodies + /// - default arguments + /// - exception-specifications (TODO: C++0x) + /// - and brace-or-equal-initializers (TODO: C++0x) + /// for non-static data members (including such things in nested classes)." + /// LateParsedDeclarations build the tree of those elements so they can + /// be parsed after parsing the top-level class. + class LateParsedDeclaration { + public: + virtual ~LateParsedDeclaration(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMethodDefs(); + }; + + /// Inner node of the LateParsedDeclaration tree that parses + /// all its members recursively. + class LateParsedClass : public LateParsedDeclaration { + public: + LateParsedClass(Parser *P, ParsingClass *C); + virtual ~LateParsedClass(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMethodDefs(); + + private: + Parser *Self; + ParsingClass *Class; + }; + + /// Contains the lexed tokens of a member function definition + /// which needs to be parsed at the end of the class declaration + /// after parsing all other member declarations. + struct LexedMethod : public LateParsedDeclaration { + Parser *Self; Decl *D; CachedTokens Toks; @@ -554,7 +623,10 @@ private: /// othewise, it is a member function declaration. bool TemplateScope; - explicit LexedMethod(Decl *MD) : D(MD), TemplateScope(false) {} + explicit LexedMethod(Parser* P, Decl *MD) + : Self(P), D(MD), TemplateScope(false) {} + + virtual void ParseLexedMethodDefs(); }; /// LateParsedDefaultArgument - Keeps track of a parameter that may @@ -580,9 +652,13 @@ private: /// 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(Decl *M) - : Method(M), TemplateScope(false) { } + struct LateParsedMethodDeclaration : public LateParsedDeclaration { + explicit LateParsedMethodDeclaration(Parser *P, Decl *M) + : Self(P), Method(M), TemplateScope(false) { } + + virtual void ParseLexedMethodDeclarations(); + + Parser* Self; /// Method - The method declaration. Decl *Method; @@ -600,17 +676,12 @@ private: llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs; }; - /// LateParsedMethodDecls - During parsing of a top (non-nested) C++ - /// class, its method declarations that contain parts that won't be + /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) + /// C++ class, its method declarations that contain parts that won't be /// parsed until after the definiton is completed (C++ [class.mem]p2), - /// the method declarations will be stored here with the tokens that - /// will be parsed to create those entities. - typedef std::list<LateParsedMethodDeclaration> LateParsedMethodDecls; - - /// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class, - /// its inline method definitions and the inline method definitions of its - /// nested classes are lexed and stored here. - typedef std::list<LexedMethod> LexedMethodsForTopClass; + /// the method declarations and possibly attached inline definitions + /// will be stored here with the tokens that will be parsed to create those entities. + typedef llvm::SmallVector<LateParsedDeclaration*, 2> LateParsedDeclarationsContainer; /// \brief Representation of a class that has been parsed, including /// any member function declarations or definitions that need to be @@ -632,16 +703,10 @@ private: /// \brief The class or class template whose definition we are parsing. Decl *TagOrTemplate; - /// MethodDecls - Method declarations that contain pieces whose - /// parsing will be delayed until the class is fully defined. - LateParsedMethodDecls MethodDecls; - - /// MethodDefs - Methods whose definitions will be parsed once the - /// class has been fully defined. - LexedMethodsForTopClass MethodDefs; - - /// \brief Nested classes inside this class. - llvm::SmallVector<ParsingClass*, 4> NestedClasses; + /// LateParsedDeclarations - Method declarations, inline definitions and + /// nested classes that contain pieces whose parsing will be delayed until + /// the top-level class is fully defined. + LateParsedDeclarationsContainer LateParsedDeclarations; }; /// \brief The stack of classes that is currently being @@ -660,7 +725,7 @@ private: /// class or function definition. class ParsingDeclRAIIObject { Sema &Actions; - Sema::ParsingDeclStackState State; + Sema::ParsingDeclState State; bool Popped; public: @@ -772,23 +837,24 @@ private: class ParsingClassDefinition { Parser &P; bool Popped; + Sema::ParsingClassState State; public: ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass) - : P(P), Popped(false) { - P.PushParsingClass(TagOrTemplate, TopLevelClass); + : P(P), Popped(false), + State(P.PushParsingClass(TagOrTemplate, TopLevelClass)) { } /// \brief Pop this class of the stack. void Pop() { assert(!Popped && "Nested class has already been popped"); Popped = true; - P.PopParsingClass(); + P.PopParsingClass(State); } ~ParsingClassDefinition() { if (!Popped) - P.PopParsingClass(); + P.PopParsingClass(State); } }; @@ -838,16 +904,22 @@ private: /// \brief Whether the last template parameter list was empty. bool LastParameterListWasEmpty; + + SourceRange getSourceRange() const; }; - void PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass); + Sema::ParsingClassState + PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass); void DeallocateParsedClasses(ParsingClass *Class); - void PopParsingClass(); + void PopParsingClass(Sema::ParsingClassState); - Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, - const ParsedTemplateInfo &TemplateInfo); + Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS); void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); void ParseLexedMethodDefs(ParsingClass &Class); + void ParseLexedMethodDef(LexedMethod &LM); bool ConsumeAndStoreUntil(tok::TokenKind T1, CachedTokens &Toks, bool StopAtSemi = true, @@ -861,14 +933,17 @@ private: //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. - DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr, + struct ParsedAttributesWithRange : ParsedAttributes { + SourceRange Range; + }; + + DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS = 0); bool isDeclarationAfterDeclarator() const; bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); - DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr, - AccessSpecifier AS = AS_none); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, + AccessSpecifier AS = AS_none); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, - AttributeList *Attr, AccessSpecifier AS = AS_none); Decl *ParseFunctionDefinition(ParsingDeclarator &D, @@ -883,7 +958,7 @@ private: Decl *ParseObjCAtDirectives(); Decl *ParseObjCAtClassDeclaration(SourceLocation atLoc); Decl *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, - AttributeList *prefixAttrs = 0); + ParsedAttributes &prefixAttrs); void ParseObjCClassInstanceVariables(Decl *interfaceDecl, tok::ObjCKeywordKind visibility, SourceLocation atLoc); @@ -892,10 +967,11 @@ private: bool WarnOnDeclarations, SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); + bool ParseObjCProtocolQualifiers(DeclSpec &DS); void ParseObjCInterfaceDeclList(Decl *interfaceDecl, tok::ObjCKeywordKind contextKey); Decl *ParseObjCAtProtocolDeclaration(SourceLocation atLoc, - AttributeList *prefixAttrs = 0); + ParsedAttributes &prefixAttrs); Decl *ObjCImpDecl; llvm::SmallVector<Decl *, 4> PendingObjCImpDecl; @@ -923,8 +999,7 @@ private: Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, Decl *classDecl, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); - void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl, - Decl **Methods, unsigned NumMethods); + void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl); Decl *ParseObjCMethodDefinition(); @@ -1022,6 +1097,10 @@ private: ExprResult ParseCXXTypeid(); //===--------------------------------------------------------------------===// + // C++ : Microsoft __uuidof Expression + ExprResult ParseCXXUuidof(); + + //===--------------------------------------------------------------------===// // C++ 5.2.4: C++ Pseudo-Destructor Expressions ExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -1042,6 +1121,10 @@ private: bool &hasAnyExceptionSpec); //===--------------------------------------------------------------------===// + // C++0x 8: Function declaration trailing-return-type + TypeResult ParseTrailingReturnType(); + + //===--------------------------------------------------------------------===// // C++ 2.13.5: C++ Boolean Literals ExprResult ParseCXXBoolLiteral(); @@ -1117,30 +1200,32 @@ private: // C99 6.8: Statements and Blocks. StmtResult ParseStatement() { - return ParseStatementOrDeclaration(true); + StmtVector Stmts(Actions); + return ParseStatementOrDeclaration(Stmts, true); } - StmtResult ParseStatementOrDeclaration(bool OnlyStatement = false); - StmtResult ParseLabeledStatement(AttributeList *Attr); - StmtResult ParseCaseStatement(AttributeList *Attr); - StmtResult ParseDefaultStatement(AttributeList *Attr); - StmtResult ParseCompoundStatement(AttributeList *Attr, + StmtResult ParseStatementOrDeclaration(StmtVector& Stmts, + bool OnlyStatement = false); + StmtResult ParseLabeledStatement(ParsedAttributes &Attr); + StmtResult ParseCaseStatement(ParsedAttributes &Attr); + StmtResult ParseDefaultStatement(ParsedAttributes &Attr); + StmtResult ParseCompoundStatement(ParsedAttributes &Attr, bool isStmtExpr = false); StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean); - StmtResult ParseIfStatement(AttributeList *Attr); - StmtResult ParseSwitchStatement(AttributeList *Attr); - StmtResult ParseWhileStatement(AttributeList *Attr); - StmtResult ParseDoStatement(AttributeList *Attr); - StmtResult ParseForStatement(AttributeList *Attr); - StmtResult ParseGotoStatement(AttributeList *Attr); - StmtResult ParseContinueStatement(AttributeList *Attr); - StmtResult ParseBreakStatement(AttributeList *Attr); - StmtResult ParseReturnStatement(AttributeList *Attr); + StmtResult ParseIfStatement(ParsedAttributes &Attr); + StmtResult ParseSwitchStatement(ParsedAttributes &Attr); + StmtResult ParseWhileStatement(ParsedAttributes &Attr); + StmtResult ParseDoStatement(ParsedAttributes &Attr); + StmtResult ParseForStatement(ParsedAttributes &Attr); + StmtResult ParseGotoStatement(ParsedAttributes &Attr); + StmtResult ParseContinueStatement(ParsedAttributes &Attr); + StmtResult ParseBreakStatement(ParsedAttributes &Attr); + StmtResult ParseReturnStatement(ParsedAttributes &Attr); StmtResult ParseAsmStatement(bool &msAsm); - StmtResult FuzzyParseMicrosoftAsmStatement(); + StmtResult FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc); bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, llvm::SmallVectorImpl<ExprTy *> &Constraints, llvm::SmallVectorImpl<ExprTy *> &Exprs); @@ -1148,7 +1233,7 @@ private: //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks - StmtResult ParseCXXTryBlock(AttributeList *Attr); + StmtResult ParseCXXTryBlock(ParsedAttributes &Attr); StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); StmtResult ParseCXXCatchBlock(); @@ -1173,11 +1258,13 @@ private: DSC_top_level // top-level/namespace declaration context }; - DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd, - CXX0XAttributeList Attr); - DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, + DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts, + unsigned Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs); + DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts, + unsigned Context, SourceLocation &DeclEnd, - AttributeList *Attr, + ParsedAttributes &attrs, bool RequireSemi); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, @@ -1187,6 +1274,12 @@ private: Decl *ParseFunctionStatementBody(Decl *Decl); Decl *ParseFunctionTryBlock(Decl *Decl); + /// \brief When in code-completion, skip parsing of the function/method body + /// unless the body contains the code-completion point. + /// + /// \returns true if the function body was skipped. + bool trySkippingFunctionBodyForCodeCompletion(); + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS); @@ -1206,7 +1299,8 @@ private: void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter); void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none); + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + AccessSpecifier AS = AS_none); void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, Decl *TagDecl); @@ -1222,7 +1316,7 @@ private: void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback); - bool isDeclarationSpecifier(); + bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false); bool isTypeSpecifierQualifier(); bool isTypeQualifier() const; @@ -1237,7 +1331,7 @@ private: bool isDeclarationStatement() { if (getLang().CPlusPlus) return isCXXDeclarationStatement(); - return isDeclarationSpecifier(); + return isDeclarationSpecifier(true); } /// isSimpleDeclaration - Disambiguates between a declaration or an @@ -1247,9 +1341,13 @@ private: bool isSimpleDeclaration() { if (getLang().CPlusPlus) return isCXXSimpleDeclaration(); - return isDeclarationSpecifier(); + return isDeclarationSpecifier(true); } + /// \brief Determine whether we are currently at the start of an Objective-C + /// class message that appears to be missing the open bracket '['. + bool isStartOfObjCClassMessageMissingOpenBracket(); + /// \brief Starting with a scope specifier, identifier, or /// template-id that refers to the current class, determine whether /// this is a constructor declarator. @@ -1333,6 +1431,18 @@ private: bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; } }; + /// \brief Based only on the given token kind, determine whether we know that + /// we're at the start of an expression or a type-specifier-seq (which may + /// be an expression, in C++). + /// + /// This routine does not attempt to resolve any of the trick cases, e.g., + /// those involving lookup of identifiers. + /// + /// \returns \c TPR_true if this token starts an expression, \c TPR_false if + /// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot + /// tell. + TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind); + /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a /// declaration specifier, TPResult::False() if it is not, /// TPResult::Ambiguous() if it could be either a decl-specifier or a @@ -1340,7 +1450,7 @@ private: /// encountered. /// Doesn't consume tokens. TPResult isCXXDeclarationSpecifier(); - + // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error(). // Returning TPResult::True()/False() indicates that the ambiguity was @@ -1351,26 +1461,87 @@ private: TPResult TryParseDeclarationSpecifier(); TPResult TryParseSimpleDeclaration(); TPResult TryParseTypeofSpecifier(); + TPResult TryParseProtocolQualifiers(); TPResult TryParseInitDeclaratorList(); TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); TPResult TryParseParameterDeclarationClause(); TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); - TypeResult ParseTypeName(SourceRange *Range = 0); + TypeResult ParseTypeName(SourceRange *Range = 0, + Declarator::TheContext Context + = Declarator::TypeNameContext); void ParseBlockId(); - // EndLoc, if non-NULL, is filled with the location of the last token of - // the attribute list. - CXX0XAttributeList ParseCXX0XAttributes(SourceLocation *EndLoc = 0); - AttributeList *ParseGNUAttributes(SourceLocation *EndLoc = 0); - AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0); - AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0); - AttributeList *ParseBorlandTypeAttributes(AttributeList* CurrAttr = 0); + + void ProhibitAttributes(ParsedAttributesWithRange &attrs) { + if (!attrs.Range.isValid()) return; + DiagnoseProhibitedAttributes(attrs); + } + void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); + + void MaybeParseGNUAttributes(Declarator &D) { + if (Tok.is(tok::kw___attribute)) { + ParsedAttributes attrs; + SourceLocation endLoc; + ParseGNUAttributes(attrs, &endLoc); + D.addAttributes(attrs.getList(), endLoc); + } + } + void MaybeParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0) { + if (Tok.is(tok::kw___attribute)) + ParseGNUAttributes(attrs, endLoc); + } + void ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0); + + void MaybeParseCXX0XAttributes(Declarator &D) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + ParsedAttributesWithRange attrs; + SourceLocation endLoc; + ParseCXX0XAttributes(attrs, &endLoc); + D.addAttributes(attrs.getList(), endLoc); + } + } + void MaybeParseCXX0XAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + ParsedAttributesWithRange attrsWithRange; + ParseCXX0XAttributes(attrsWithRange, endLoc); + attrs.append(attrsWithRange.getList()); + } + } + void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc = 0) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + ParseCXX0XAttributes(attrs, endLoc); + } + void ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *EndLoc = 0); + + void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0) { + if (getLang().Microsoft && Tok.is(tok::l_square)) + ParseMicrosoftAttributes(attrs, endLoc); + } + void ParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0); + void ParseMicrosoftDeclSpec(ParsedAttributes &attrs); + void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); + void ParseBorlandTypeAttributes(ParsedAttributes &attrs); + void ParseOpenCLAttributes(ParsedAttributes &attrs); + void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); ExprResult ParseCXX0XAlignArgument(SourceLocation Start); + VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const; + void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); + + ClassVirtSpecifiers::Specifier isCXX0XClassVirtSpecifier() const; + void ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS); + /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is /// finished. @@ -1410,12 +1581,13 @@ private: typedef void (Parser::*DirectDeclParseFunction)(Declarator&); void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); + void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, bool CXX0XAttributesAllowed = true); void ParseDirectDeclarator(Declarator &D); void ParseParenDeclarator(Declarator &D); void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, - AttributeList *AttrList = 0, + ParsedAttributes &attrs, bool RequiresArg = false); void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, IdentifierInfo *FirstIdent, @@ -1433,11 +1605,16 @@ private: SourceLocation InlineLoc = SourceLocation()); Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context); Decl *ParseUsingDirectiveOrDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, - CXX0XAttributeList Attrs); - Decl *ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd, AttributeList *Attr); - Decl *ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, + ParsedAttributesWithRange &attrs); + Decl *ParseUsingDirective(unsigned Context, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + ParsedAttributes &attrs); + Decl *ParseUsingDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); @@ -1542,6 +1719,7 @@ private: //===--------------------------------------------------------------------===// // GNU G++: Type Traits [Type-Traits.html in the GCC manual] ExprResult ParseUnaryTypeTrait(); + ExprResult ParseBinaryTypeTrait(); //===--------------------------------------------------------------------===// // Preprocessor code-completion pass-through diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/ASTConsumers.h index 5fb107ccbe0b..b7f642764b22 100644 --- a/include/clang/Rewrite/ASTConsumers.h +++ b/include/clang/Rewrite/ASTConsumers.h @@ -26,7 +26,7 @@ class Diagnostic; class LangOptions; class Preprocessor; -// ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code. +// ObjC rewriter: attempts to 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, diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h index 9b2e0160c5d6..26a0d72baa2a 100644 --- a/include/clang/Rewrite/FixItRewriter.h +++ b/include/clang/Rewrite/FixItRewriter.h @@ -99,7 +99,7 @@ public: const DiagnosticInfo &Info); /// \brief Emit a diagnostic via the adapted diagnostic client. - void Diag(FullSourceLoc Loc, unsigned DiagID); + void Diag(SourceLocation Loc, unsigned DiagID); }; } diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 53316477e1c5..45ee579a02d3 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_SEMA_ATTRLIST_H #define LLVM_CLANG_SEMA_ATTRLIST_H +#include "llvm/Support/Allocator.h" #include "clang/Sema/Ownership.h" #include "clang/Basic/SourceLocation.h" #include <cassert> @@ -32,6 +33,9 @@ namespace clang { /// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. /// class AttributeList { +public: + class Factory; +private: IdentifierInfo *AttrName; SourceLocation AttrLoc; IdentifierInfo *ScopeName; @@ -42,17 +46,38 @@ class AttributeList { unsigned NumArgs; AttributeList *Next; bool DeclspecAttribute, CXX0XAttribute; - mutable bool Invalid; /// True if already diagnosed as invalid. + + /// True if already diagnosed as invalid. + mutable bool Invalid; + AttributeList(const AttributeList &); // DO NOT IMPLEMENT void operator=(const AttributeList &); // DO NOT IMPLEMENT -public: - AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc, + void operator delete(void *); // DO NOT IMPLEMENT + ~AttributeList(); // DO NOT IMPLEMENT + AttributeList(llvm::BumpPtrAllocator &Alloc, + IdentifierInfo *AttrName, SourceLocation AttrLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, IdentifierInfo *ParmName, SourceLocation ParmLoc, Expr **args, unsigned numargs, - AttributeList *Next, bool declspec = false, bool cxx0x = false); - ~AttributeList(); - + bool declspec, bool cxx0x); +public: + class Factory { + llvm::BumpPtrAllocator Alloc; + public: + Factory() {} + ~Factory() {} + AttributeList *Create(IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + IdentifierInfo *ParmName, SourceLocation ParmLoc, + Expr **args, unsigned numargs, bool declspec = false, bool cxx0x = false) { + AttributeList *Mem = Alloc.Allocate<AttributeList>(); + new (Mem) AttributeList(Alloc, AttrName, AttrLoc, ScopeName, ScopeLoc, + ParmName, ParmLoc, args, numargs, + declspec, cxx0x); + return Mem; + } + }; + enum Kind { // Please keep this list alphabetized. AT_IBAction, // Clang-specific. AT_IBOutlet, // Clang-specific. @@ -68,35 +93,48 @@ public: AT_carries_dependency, AT_cdecl, AT_cleanup, + AT_common, AT_const, + AT_constant, AT_constructor, AT_deprecated, AT_destructor, + AT_device, AT_dllexport, AT_dllimport, AT_ext_vector_type, AT_fastcall, - AT_final, AT_format, AT_format_arg, + AT_global, AT_gnu_inline, - AT_hiding, + AT_host, + AT_launch_bounds, AT_malloc, + AT_may_alias, AT_mode, + AT_neon_polyvector_type, // Clang-specific. + AT_neon_vector_type, // Clang-specific. + AT_naked, AT_nodebug, AT_noinline, AT_no_instrument_function, + AT_nocommon, AT_nonnull, AT_noreturn, AT_nothrow, AT_nsobject, AT_objc_exception, - AT_override, AT_cf_returns_not_retained, // Clang-specific. AT_cf_returns_retained, // Clang-specific. AT_ns_returns_not_retained, // Clang-specific. AT_ns_returns_retained, // Clang-specific. + AT_ns_returns_autoreleased, // Clang-specific. + AT_cf_consumed, // Clang-specific. + AT_ns_consumed, // Clang-specific. + AT_ns_consumes_self, // Clang-specific. AT_objc_gc, + AT_opencl_kernel_function, // OpenCL-specific. AT_overloadable, // Clang-specific. AT_ownership_holds, // Clang-specific. AT_ownership_returns, // Clang-specific. @@ -107,12 +145,14 @@ public: AT_regparm, AT_section, AT_sentinel, + AT_shared, AT_stdcall, AT_thiscall, AT_transparent_union, AT_unavailable, AT_unused, AT_used, + AT_uuid, AT_vecreturn, // PS3 PPU-specific. AT_vector_size, AT_visibility, @@ -134,6 +174,7 @@ public: SourceLocation getScopeLoc() const { return ScopeLoc; } IdentifierInfo *getParameterName() const { return ParmName; } + SourceLocation getParameterLoc() const { return ParmLoc; } bool isDeclspecAttribute() const { return DeclspecAttribute; } bool isCXX0XAttribute() const { return CXX0XAttribute; } @@ -199,8 +240,8 @@ public: /// 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) { +inline AttributeList *addAttributeLists(AttributeList *Left, + AttributeList *Right) { if (!Left) return Right; @@ -229,6 +270,51 @@ struct CXX0XAttributeList { } }; +/// ParsedAttributes - A collection of parsed attributes. Currently +/// we don't differentiate between the various attribute syntaxes, +/// which is basically silly. +/// +/// Right now this is a very lightweight container, but the expectation +/// is that this will become significantly more serious. +class ParsedAttributes { +public: + ParsedAttributes() : list(0) {} + + bool empty() const { return list == 0; } + + void add(AttributeList *newAttr) { + assert(newAttr); + assert(newAttr->getNext() == 0); + newAttr->setNext(list); + list = newAttr; + } + + void append(AttributeList *newList) { + if (!newList) return; + + AttributeList *lastInNewList = newList; + while (AttributeList *next = lastInNewList->getNext()) + lastInNewList = next; + + lastInNewList->setNext(list); + list = newList; + } + + void set(AttributeList *newList) { + list = newList; + } + + void clear() { list = 0; } + AttributeList *getList() const { return list; } + + /// Returns a reference to the attribute list. Try not to introduce + /// dependencies on this method, it may not be long-lived. + AttributeList *&getListRef() { return list; } + +private: + AttributeList *list; +}; + } // end namespace clang #endif diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 6c1ecbf2cc29..882440b78c7c 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -17,12 +17,13 @@ #include "clang/AST/CanonicalType.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "clang-c/Index.h" -#include <memory> #include <string> namespace llvm { class raw_ostream; + class Twine; } namespace clang { @@ -35,31 +36,37 @@ enum { /// \brief Priority for the next initialization in a constructor initializer /// list. CCP_NextInitializer = 7, + /// \brief Priority for an enumeration constant inside a switch whose + /// condition is of the enumeration type. + CCP_EnumInCase = 7, /// \brief Priority for a send-to-super completion. - CCP_SuperCompletion = 8, + CCP_SuperCompletion = 20, /// \brief Priority for a declaration that is in the local scope. - CCP_LocalDeclaration = 8, + CCP_LocalDeclaration = 34, /// \brief Priority for a member declaration found from the current /// method or member function. - CCP_MemberDeclaration = 20, + CCP_MemberDeclaration = 35, /// \brief Priority for a language keyword (that isn't any of the other /// categories). - CCP_Keyword = 30, + CCP_Keyword = 40, /// \brief Priority for a code pattern. - CCP_CodePattern = 30, + CCP_CodePattern = 40, /// \brief Priority for a non-type declaration. CCP_Declaration = 50, - /// \brief Priority for a constant value (e.g., enumerator). - CCP_Constant = 60, /// \brief Priority for a type. - CCP_Type = 65, + CCP_Type = CCP_Declaration, + /// \brief Priority for a constant value (e.g., enumerator). + CCP_Constant = 65, /// \brief Priority for a preprocessor macro. CCP_Macro = 70, /// \brief Priority for a nested-name-specifier. CCP_NestedNameSpecifier = 75, /// \brief Priority for a result that isn't likely to be what the user wants, /// but is included for completeness. - CCP_Unlikely = 80 + CCP_Unlikely = 80, + + /// \brief Priority for the Objective-C "_cmd" implicit parameter. + CCP_ObjC_cmd = CCP_Unlikely }; /// \brief Priority value deltas that are added to code-completion results @@ -67,18 +74,21 @@ enum { enum { /// \brief The result is in a base class. CCD_InBaseClass = 2, - /// \brief The result is a type match against void. - /// - /// Since everything converts to "void", we don't give as drastic an - /// adjustment for matching void. - CCD_VoidMatch = -5, /// \brief The result is a C++ non-static member function whose qualifiers /// exactly match the object type on which the member function can be called. CCD_ObjectQualifierMatch = -1, /// \brief The selector of the given message exactly matches the selector /// of the current method, which might imply that some kind of delegation /// is occurring. - CCD_SelectorMatch = -3 + CCD_SelectorMatch = -3, + + /// \brief Adjustment to the "bool" type in Objective-C, where the typedef + /// "BOOL" is preferred. + CCD_bool_in_ObjC = 1, + + /// \brief Adjustment for KVC code pattern priorities when it doesn't look + /// like the + CCD_ProbablyNotObjCCollection = 15 }; /// \brief Priority value factors by which we will divide or multiply the @@ -119,9 +129,12 @@ QualType getDeclUsageType(ASTContext &C, NamedDecl *ND); /// /// \param MacroName The name of the macro. /// +/// \param LangOpts Options describing the current language dialect. +/// /// \param PreferredTypeIsPointer Whether the preferred type for the context /// of this macro is a pointer type. unsigned getMacroUsagePriority(llvm::StringRef MacroName, + const LangOptions &LangOpts, bool PreferredTypeIsPointer = false); /// \brief Determine the libclang cursor kind associated with the given @@ -143,6 +156,9 @@ public: enum Kind { /// \brief An unspecified code-completion context. CCC_Other, + /// \brief An unspecified code-completion context where we should also add + /// macro completions. + CCC_OtherWithMacros, /// \brief Code completion occurred within a "top-level" completion context, /// e.g., at namespace or global scope. CCC_TopLevel, @@ -212,7 +228,13 @@ public: /// \brief Code completion for a selector, as in an @selector expression. CCC_SelectorName, /// \brief Code completion within a type-qualifier list. - CCC_TypeQualifiers + CCC_TypeQualifiers, + /// \brief Code completion in a parenthesized expression, which means that + /// we may also have types here in C and Objective-C (as well as in C++). + CCC_ParenthesizedExpression, + /// \brief An unknown context, in which we are recovering from a parsing + /// error and don't know which completions we should give. + CCC_Recovery }; private: @@ -248,6 +270,10 @@ public: /// \brief Retrieve the type of the base object in a member-access /// expression. QualType getBaseType() const { return BaseType; } + + /// \brief Determines whether we want C++ constructors as results within this + /// context. + bool wantConstructorResults() const; }; @@ -339,127 +365,163 @@ public: Chunk() : Kind(CK_Text), Text(0) { } - Chunk(ChunkKind Kind, llvm::StringRef Text = ""); + Chunk(ChunkKind Kind, const char *Text = ""); /// \brief Create a new text chunk. - static Chunk CreateText(llvm::StringRef Text); + static Chunk CreateText(const char *Text); /// \brief Create a new optional chunk. - static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional); + static Chunk CreateOptional(CodeCompletionString *Optional); /// \brief Create a new placeholder chunk. - static Chunk CreatePlaceholder(llvm::StringRef Placeholder); + static Chunk CreatePlaceholder(const char *Placeholder); /// \brief Create a new informative chunk. - static Chunk CreateInformative(llvm::StringRef Informative); + static Chunk CreateInformative(const char *Informative); /// \brief Create a new result type chunk. - static Chunk CreateResultType(llvm::StringRef ResultType); + static Chunk CreateResultType(const char *ResultType); /// \brief Create a new current-parameter chunk. - static Chunk CreateCurrentParameter(llvm::StringRef CurrentParameter); - - /// \brief Clone the given chunk. - Chunk Clone() const; - - /// \brief Destroy this chunk, deallocating any memory it owns. - void Destroy(); + static Chunk CreateCurrentParameter(const char *CurrentParameter); }; private: - /// \brief The chunks stored in this string. - llvm::SmallVector<Chunk, 4> Chunks; + /// \brief The number of chunks stored in this string. + unsigned NumChunks; + + /// \brief The priority of this code-completion string. + unsigned Priority : 30; + + /// \brief The availability of this code-completion result. + unsigned Availability : 2; CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT CodeCompletionString &operator=(const CodeCompletionString &); // DITTO -public: - CodeCompletionString() { } - ~CodeCompletionString() { clear(); } + CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, + unsigned Priority, CXAvailabilityKind Availability); + ~CodeCompletionString() { } - typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator; - iterator begin() const { return Chunks.begin(); } - iterator end() const { return Chunks.end(); } - bool empty() const { return Chunks.empty(); } - unsigned size() const { return Chunks.size(); } - void clear(); + friend class CodeCompletionBuilder; + friend class CodeCompletionResult; - Chunk &operator[](unsigned I) { +public: + typedef const Chunk *iterator; + iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); } + iterator end() const { return begin() + NumChunks; } + bool empty() const { return NumChunks == 0; } + unsigned size() const { return NumChunks; } + + const Chunk &operator[](unsigned I) const { assert(I < size() && "Chunk index out-of-range"); - return Chunks[I]; + return begin()[I]; } + + /// \brief Returns the text in the TypedText chunk. + const char *getTypedText() const; - const Chunk &operator[](unsigned I) const { - assert(I < size() && "Chunk index out-of-range"); - return Chunks[I]; + /// \brief Retrieve the priority of this code completion result. + unsigned getPriority() const { return Priority; } + + /// \brief Reteirve the availability of this code completion result. + unsigned getAvailability() const { return Availability; } + + /// \brief Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// \brief An allocator used specifically for the purpose of code completion. +class CodeCompletionAllocator : public llvm::BumpPtrAllocator { +public: + /// \brief Copy the given string into this allocator. + const char *CopyString(llvm::StringRef String); + + /// \brief Copy the given string into this allocator. + const char *CopyString(llvm::Twine String); + + // \brief Copy the given string into this allocator. + const char *CopyString(const char *String) { + return CopyString(llvm::StringRef(String)); + } + + /// \brief Copy the given string into this allocator. + const char *CopyString(const std::string &String) { + return CopyString(llvm::StringRef(String)); + } +}; + +/// \brief A builder class used to construct new code-completion strings. +class CodeCompletionBuilder { +public: + typedef CodeCompletionString::Chunk Chunk; + +private: + CodeCompletionAllocator &Allocator; + unsigned Priority; + CXAvailabilityKind Availability; + + /// \brief The chunks stored in this string. + llvm::SmallVector<Chunk, 4> Chunks; + +public: + CodeCompletionBuilder(CodeCompletionAllocator &Allocator) + : Allocator(Allocator), Priority(0), Availability(CXAvailability_Available){ } + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + unsigned Priority, CXAvailabilityKind Availability) + : Allocator(Allocator), Priority(Priority), Availability(Availability) { } + + /// \brief Retrieve the allocator into which the code completion + /// strings should be allocated. + CodeCompletionAllocator &getAllocator() const { return Allocator; } + + /// \brief Take the resulting completion string. + /// + /// This operation can only be performed once. + CodeCompletionString *TakeString(); + /// \brief Add a new typed-text chunk. - /// The text string will be copied. - void AddTypedTextChunk(llvm::StringRef Text) { - Chunks.push_back(Chunk(CK_TypedText, Text)); + void AddTypedTextChunk(const char *Text) { + Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text)); } /// \brief Add a new text chunk. - /// The text string will be copied. - void AddTextChunk(llvm::StringRef Text) { + void AddTextChunk(const char *Text) { Chunks.push_back(Chunk::CreateText(Text)); } - + /// \brief Add a new optional chunk. - void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) { + void AddOptionalChunk(CodeCompletionString *Optional) { Chunks.push_back(Chunk::CreateOptional(Optional)); } /// \brief Add a new placeholder chunk. - /// The placeholder text will be copied. - void AddPlaceholderChunk(llvm::StringRef Placeholder) { + void AddPlaceholderChunk(const char *Placeholder) { Chunks.push_back(Chunk::CreatePlaceholder(Placeholder)); } - + /// \brief Add a new informative chunk. - /// The text will be copied. - void AddInformativeChunk(llvm::StringRef Text) { + void AddInformativeChunk(const char *Text) { Chunks.push_back(Chunk::CreateInformative(Text)); } - + /// \brief Add a new result-type chunk. - /// The text will be copied. - void AddResultTypeChunk(llvm::StringRef ResultType) { + void AddResultTypeChunk(const char *ResultType) { Chunks.push_back(Chunk::CreateResultType(ResultType)); } /// \brief Add a new current-parameter chunk. - /// The text will be copied. - void AddCurrentParameterChunk(llvm::StringRef CurrentParameter) { + void AddCurrentParameterChunk(const char *CurrentParameter) { Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter)); } /// \brief Add a new chunk. void AddChunk(Chunk C) { Chunks.push_back(C); } - - /// \brief Returns the text in the TypedText chunk. - const char *getTypedText() const; - - /// \brief Retrieve a string representation of the code completion string, - /// which is mainly useful for debugging. - std::string getAsString() const; - - /// \brief Clone this code-completion string. - /// - /// \param Result If non-NULL, points to an empty code-completion - /// result that will be given a cloned copy of - CodeCompletionString *Clone(CodeCompletionString *Result = 0) const; - - /// \brief Serialize this code-completion string to the given stream. - void Serialize(llvm::raw_ostream &OS) const; - - /// \brief Deserialize a code-completion string from the given string. - /// - /// \returns true if successful, false otherwise. - bool Deserialize(const char *&Str, const char *StrEnd); }; - + /// \brief Captures a result of code completion. class CodeCompletionResult { public: @@ -590,15 +652,12 @@ public: /// /// \param S The semantic analysis that created the result. /// - /// \param Result If non-NULL, the already-allocated, empty - /// code-completion string that will be populated with the - /// appropriate code completion string for this result. + /// \param Allocator The allocator that will be used to allocate the + /// string itself. CodeCompletionString *CreateCodeCompletionString(Sema &S, - CodeCompletionString *Result = 0); - - void Destroy(); + CodeCompletionAllocator &Allocator); - /// brief Determine a base priority for the given declaration. + /// \brief Determine a base priority for the given declaration. static unsigned getPriorityFromDecl(NamedDecl *ND); private: @@ -682,7 +741,7 @@ public: : Kind(CK_Function), Function(Function) { } OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl) - : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplate) { } + : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplateDecl) { } OverloadCandidate(const FunctionType *Type) : Kind(CK_FunctionType), Type(Type) { } @@ -707,7 +766,8 @@ public: /// \brief Create a new code-completion string that describes the function /// signature of this overload candidate. CodeCompletionString *CreateSignatureString(unsigned CurrentArg, - Sema &S) const; + Sema &S, + CodeCompletionAllocator &Allocator) const; }; CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false), @@ -753,6 +813,10 @@ public: OverloadCandidate *Candidates, unsigned NumCandidates) { } //@} + + /// \brief Retrieve the allocator that will be used to allocate + /// code completion strings. + virtual CodeCompletionAllocator &getAllocator() = 0; }; /// \brief A simple code-completion consumer that prints the results it @@ -761,6 +825,8 @@ class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { /// \brief The raw output stream. llvm::raw_ostream &OS; + CodeCompletionAllocator Allocator; + public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. @@ -779,34 +845,10 @@ public: virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates); -}; - -/// \brief A code-completion consumer that prints the results it receives -/// in a format that is parsable by the CIndex library. -class CIndexCodeCompleteConsumer : public CodeCompleteConsumer { - /// \brief The raw output stream. - llvm::raw_ostream &OS; - -public: - /// \brief Create a new CIndex code-completion consumer that prints its - /// results to the given raw output stream in a format readable to the CIndex - /// library. - CIndexCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, - bool IncludeGlobals, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, - true), OS(OS) {} - /// \brief Prints the finalized code-completion results. - virtual void ProcessCodeCompleteResults(Sema &S, - CodeCompletionContext Context, - CodeCompletionResult *Results, - unsigned NumResults); - - virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, - OverloadCandidate *Candidates, - unsigned NumCandidates); + virtual CodeCompletionAllocator &getAllocator() { return Allocator; } }; - + } // end namespace clang #endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 0893ae7e4958..9c4bb646949b 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -26,6 +26,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorHandling.h" namespace clang { class LangOptions; @@ -169,32 +170,32 @@ private: // storage-class-specifier /*SCS*/unsigned StorageClassSpec : 3; - bool SCS_thread_specified : 1; - bool SCS_extern_in_linkage_spec : 1; + unsigned SCS_thread_specified : 1; + unsigned SCS_extern_in_linkage_spec : 1; // type-specifier /*TSW*/unsigned TypeSpecWidth : 2; /*TSC*/unsigned TypeSpecComplex : 2; /*TSS*/unsigned TypeSpecSign : 2; /*TST*/unsigned TypeSpecType : 5; - bool TypeAltiVecVector : 1; - bool TypeAltiVecPixel : 1; - bool TypeAltiVecBool : 1; - bool TypeSpecOwned : 1; + unsigned TypeAltiVecVector : 1; + unsigned TypeAltiVecPixel : 1; + unsigned TypeAltiVecBool : 1; + unsigned TypeSpecOwned : 1; // 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; + unsigned FS_inline_specified : 1; + unsigned FS_virtual_specified : 1; + unsigned FS_explicit_specified : 1; // friend-specifier - bool Friend_specified : 1; + unsigned Friend_specified : 1; // constexpr-specifier - bool Constexpr_specified : 1; + unsigned Constexpr_specified : 1; /*SCS*/unsigned StorageClassSpecAsWritten : 3; @@ -205,7 +206,7 @@ private: }; // attributes. - AttributeList *AttrList; + ParsedAttributes Attrs; // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; @@ -267,14 +268,12 @@ public: Friend_specified(false), Constexpr_specified(false), StorageClassSpecAsWritten(SCS_unspecified), - AttrList(0), ProtocolQualifiers(0), NumProtocolQualifiers(0), ProtocolLocs(0), writtenBS() { } ~DeclSpec() { - delete AttrList; delete [] ProtocolQualifiers; delete [] ProtocolLocs; } @@ -404,7 +403,7 @@ public: /// 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); + unsigned &DiagID, const LangOptions &Lang); bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, @@ -473,19 +472,29 @@ public: /// short __attribute__((unused)) __attribute__((deprecated)) /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; /// - void AddAttributes(AttributeList *alist) { - AttrList = addAttributeLists(AttrList, alist); + void addAttributes(AttributeList *AL) { + Attrs.append(AL); + } + void aetAttributes(AttributeList *AL) { + Attrs.set(AL); } - void SetAttributes(AttributeList *AL) { AttrList = AL; } - const AttributeList *getAttributes() const { return AttrList; } - AttributeList *getAttributes() { return AttrList; } + + bool hasAttributes() const { return !Attrs.empty(); } + + ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getAttributes() const { return Attrs; } /// TakeAttributes - Return the current attribute list and remove them from /// the DeclSpec so that it doesn't own them. - AttributeList *TakeAttributes() { - AttributeList *AL = AttrList; - AttrList = 0; - return AL; + ParsedAttributes takeAttributes() { + ParsedAttributes saved = Attrs; + Attrs.clear(); + return saved; + } + + void takeAttributesFrom(ParsedAttributes &attrs) { + Attrs.append(attrs.getList()); + attrs.clear(); } typedef Decl * const *ProtocolQualifierListTy; @@ -539,7 +548,8 @@ public: DQ_PR_retain = 0x10, DQ_PR_copy = 0x20, DQ_PR_nonatomic = 0x40, - DQ_PR_setter = 0x80 + DQ_PR_setter = 0x80, + DQ_PR_atomic = 0x100 }; @@ -573,7 +583,7 @@ private: ObjCDeclQualifier objcDeclQualifier : 6; // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind - unsigned PropertyAttributes : 8; + unsigned PropertyAttributes : 9; IdentifierInfo *GetterName; // getter name of NULL if no getter IdentifierInfo *SetterName; // setter name of NULL if no setter }; @@ -800,7 +810,7 @@ typedef llvm::SmallVector<Token, 4> CachedTokens; /// This is intended to be a small value object. struct DeclaratorChunk { enum { - Pointer, Reference, Array, Function, BlockPointer, MemberPointer + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren } Kind; /// Loc - The place where this type was defined. @@ -808,27 +818,27 @@ struct DeclaratorChunk { /// EndLoc - If valid, the place where this chunck ends. SourceLocation EndLoc; - struct PointerTypeInfo { + struct TypeInfoCommon { + AttributeList *AttrList; + }; + + struct PointerTypeInfo : TypeInfoCommon { /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; - AttributeList *AttrList; void destroy() { - delete AttrList; } }; - struct ReferenceTypeInfo { + struct ReferenceTypeInfo : TypeInfoCommon { /// The type qualifier: restrict. [GNU] C++ extension bool HasRestrict : 1; /// True if this is an lvalue reference, false if it's an rvalue reference. bool LValueRef : 1; - AttributeList *AttrList; void destroy() { - delete AttrList; } }; - struct ArrayTypeInfo { + struct ArrayTypeInfo : TypeInfoCommon { /// The type qualifiers for the array: const/volatile/restrict. unsigned TypeQuals : 3; @@ -842,6 +852,7 @@ struct DeclaratorChunk { /// Since the parser is multi-purpose, and we don't want to impose a root /// expression class on all clients, NumElts is untyped. Expr *NumElts; + void destroy() {} }; @@ -876,29 +887,33 @@ struct DeclaratorChunk { SourceRange Range; }; - struct FunctionTypeInfo { + struct FunctionTypeInfo : TypeInfoCommon { /// hasPrototype - This is true if the function had at least one typed /// argument. If the function is () or (a,b,c), then it has no prototype, /// and is treated as a K&R-style function. - bool hasPrototype : 1; + unsigned hasPrototype : 1; /// isVariadic - If this function has a prototype, and if that /// proto ends with ',...)', this is true. When true, EllipsisLoc /// contains the location of the ellipsis. - bool isVariadic : 1; + unsigned isVariadic : 1; + /// \brief Whether the ref-qualifier (if any) is an lvalue reference. + /// Otherwise, it's an rvalue reference. + unsigned RefQualifierIsLValueRef : 1; + /// The type qualifiers: const/volatile/restrict. /// The qualifier bitmask values are the same as in QualType. unsigned TypeQuals : 3; /// hasExceptionSpec - True if the function has an exception specification. - bool hasExceptionSpec : 1; + unsigned hasExceptionSpec : 1; /// hasAnyExceptionSpec - True if the function has a throw(...) specifier. - bool hasAnyExceptionSpec : 1; + unsigned hasAnyExceptionSpec : 1; /// DeleteArgInfo - If this is true, we need to delete[] ArgInfo. - bool DeleteArgInfo : 1; + unsigned DeleteArgInfo : 1; /// When isVariadic is true, the location of the ellipsis in the source. unsigned EllipsisLoc; @@ -911,6 +926,11 @@ struct DeclaratorChunk { /// the function has one. unsigned NumExceptions; + /// \brief The location of the ref-qualifier, if any. + /// + /// If this is an invalid location, there is no ref-qualifier. + unsigned RefQualifierLoc; + /// ThrowLoc - When hasExceptionSpec is true, the location of the throw /// keyword introducing the spec. unsigned ThrowLoc; @@ -925,6 +945,11 @@ struct DeclaratorChunk { /// specification and their locations. TypeAndRange *Exceptions; + /// TrailingReturnType - If this isn't null, it's the trailing return type + /// specified. This is actually a ParsedType, but stored as void* to + /// allow union storage. + void *TrailingReturnType; + /// freeArgs - reset the argument list to having zero arguments. This is /// used in various places for error recovery. void freeArgs() { @@ -954,22 +979,29 @@ struct DeclaratorChunk { SourceLocation getThrowLoc() const { return SourceLocation::getFromRawEncoding(ThrowLoc); } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getRefQualifierLoc() const { + return SourceLocation::getFromRawEncoding(RefQualifierLoc); + } + + /// \brief Determine whether this function declaration contains a + /// ref-qualifier. + bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } }; - struct BlockPointerTypeInfo { + struct BlockPointerTypeInfo : TypeInfoCommon { /// For now, sema will catch these as invalid. /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; - AttributeList *AttrList; + void destroy() { - delete AttrList; } }; - struct MemberPointerTypeInfo { + struct MemberPointerTypeInfo : TypeInfoCommon { /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; - AttributeList *AttrList; // CXXScopeSpec has a constructor, so it can't be a direct member. // So we need some pointer-aligned storage and a bit of trickery. union { @@ -983,12 +1015,12 @@ struct DeclaratorChunk { return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem); } void destroy() { - delete AttrList; Scope().~CXXScopeSpec(); } }; union { + TypeInfoCommon Common; PointerTypeInfo Ptr; ReferenceTypeInfo Ref; ArrayTypeInfo Arr; @@ -1006,58 +1038,57 @@ struct DeclaratorChunk { case DeclaratorChunk::Reference: return Ref.destroy(); case DeclaratorChunk::Array: return Arr.destroy(); case DeclaratorChunk::MemberPointer: return Mem.destroy(); + case DeclaratorChunk::Paren: return; } } /// getAttrs - If there are attributes applied to this declaratorchunk, return /// them. const AttributeList *getAttrs() const { - switch (Kind) { - default: assert(0 && "Unknown declarator kind!"); - case Pointer: return Ptr.AttrList; - case Reference: return Ref.AttrList; - case MemberPointer: return Mem.AttrList; - case Array: return 0; - case Function: return 0; - case BlockPointer: return Cls.AttrList; - } + return Common.AttrList; } + AttributeList *&getAttrListRef() { + return Common.AttrList; + } /// getPointer - Return a DeclaratorChunk for a pointer. /// static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, - AttributeList *AL) { + const ParsedAttributes &attrs) { DeclaratorChunk I; I.Kind = Pointer; I.Loc = Loc; I.Ptr.TypeQuals = TypeQuals; - I.Ptr.AttrList = AL; + I.Ptr.AttrList = attrs.getList(); return I; } /// getReference - Return a DeclaratorChunk for a reference. /// static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, - AttributeList *AL, bool lvalue) { + const ParsedAttributes &attrs, + bool lvalue) { DeclaratorChunk I; I.Kind = Reference; I.Loc = Loc; I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0; I.Ref.LValueRef = lvalue; - I.Ref.AttrList = AL; + I.Ref.AttrList = attrs.getList(); return I; } /// getArray - Return a DeclaratorChunk for an array. /// - static DeclaratorChunk getArray(unsigned TypeQuals, bool isStatic, - bool isStar, Expr *NumElts, + static DeclaratorChunk getArray(unsigned TypeQuals, + const ParsedAttributes &attrs, + bool isStatic, bool isStar, Expr *NumElts, SourceLocation LBLoc, SourceLocation RBLoc) { DeclaratorChunk I; I.Kind = Array; I.Loc = LBLoc; I.EndLoc = RBLoc; + I.Arr.AttrList = attrs.getList(); I.Arr.TypeQuals = TypeQuals; I.Arr.hasStatic = isStatic; I.Arr.isStar = isStar; @@ -1067,42 +1098,60 @@ struct DeclaratorChunk { /// 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, + static DeclaratorChunk getFunction(const ParsedAttributes &attrs, + bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, - unsigned TypeQuals, bool hasExceptionSpec, + unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, + bool hasExceptionSpec, SourceLocation ThrowLoc, bool hasAnyExceptionSpec, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, SourceLocation LPLoc, SourceLocation RPLoc, - Declarator &TheDeclarator); + Declarator &TheDeclarator, + ParsedType TrailingReturnType = ParsedType()); /// getBlockPointer - Return a DeclaratorChunk for a block. /// static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc, - AttributeList *AL) { + const ParsedAttributes &attrs) { DeclaratorChunk I; I.Kind = BlockPointer; I.Loc = Loc; I.Cls.TypeQuals = TypeQuals; - I.Cls.AttrList = AL; + I.Cls.AttrList = attrs.getList(); return I; } static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, unsigned TypeQuals, SourceLocation Loc, - AttributeList *AL) { + const ParsedAttributes &attrs) { DeclaratorChunk I; I.Kind = MemberPointer; I.Loc = Loc; I.Mem.TypeQuals = TypeQuals; - I.Mem.AttrList = AL; + I.Mem.AttrList = attrs.getList(); new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS); return I; } + + /// getParen - Return a DeclaratorChunk for a paren. + /// + static DeclaratorChunk getParen(SourceLocation LParenLoc, + SourceLocation RParenLoc) { + DeclaratorChunk I; + I.Kind = Paren; + I.Loc = LParenLoc; + I.EndLoc = RParenLoc; + I.Common.AttrList = 0; + return I; + } + }; /// Declarator - Information about one declarator, including the parsed type @@ -1128,7 +1177,8 @@ public: ConditionContext, // Condition declaration in a C++ if/switch/while/for. TemplateParamContext,// Within a template parameter list. CXXCatchContext, // C++ catch exception-declaration - BlockLiteralContext // Block literal declarator. + BlockLiteralContext, // Block literal declarator. + TemplateTypeArgContext // Template type argument. }; private: @@ -1168,6 +1218,10 @@ private: /// Extension - true if the declaration is preceded by __extension__. bool Extension : 1; + /// \brief If provided, the source location of the ellipsis used to describe + /// this declarator as a parameter pack. + SourceLocation EllipsisLoc; + friend struct DeclaratorChunk; public: @@ -1238,7 +1292,6 @@ public: for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) DeclTypeInfo[i].destroy(); DeclTypeInfo.clear(); - delete AttrList; AttrList = 0; AsmLabel = 0; InlineParamsUsed = false; @@ -1250,14 +1303,15 @@ public: bool mayOmitIdentifier() const { return Context == TypeNameContext || Context == PrototypeContext || Context == TemplateParamContext || Context == CXXCatchContext || - Context == BlockLiteralContext; + Context == BlockLiteralContext || Context == TemplateTypeArgContext; } /// mayHaveIdentifier - Return true if the identifier is either optional or /// required. This is true for normal declarators and prototypes, but not /// typenames. bool mayHaveIdentifier() const { - return Context != TypeNameContext && Context != BlockLiteralContext; + return Context != TypeNameContext && Context != BlockLiteralContext && + Context != TemplateTypeArgContext; } /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be @@ -1301,6 +1355,11 @@ public: SetRangeEnd(EndLoc); } + /// AddInnermostTypeInfo - Add a new innermost chunk to this declarator. + void AddInnermostTypeInfo(const DeclaratorChunk &TI) { + DeclTypeInfo.insert(DeclTypeInfo.begin(), TI); + } + /// getNumTypeObjects() - Return the number of types applied to this /// declarator. unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } @@ -1323,11 +1382,52 @@ public: DeclTypeInfo.erase(DeclTypeInfo.begin()); } + /// isFunctionDeclarator - This method returns true if the declarator + /// is a function declarator (looking through parentheses). + /// If true is returned, then the reference type parameter idx is + /// assigned with the index of the declaration chunk. + bool isFunctionDeclarator(unsigned& idx) const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Function: + idx = i; + return true; + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return false; + } + llvm_unreachable("Invalid type chunk"); + return false; + } + return false; + } + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, - /// this method returns true if the identifier is a function declarator. + /// this method returns true if the identifier is a function declarator + /// (looking through parentheses). bool isFunctionDeclarator() const { - return !DeclTypeInfo.empty() && - DeclTypeInfo[0].Kind == DeclaratorChunk::Function; + unsigned index; + return isFunctionDeclarator(index); + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() { + assert(isFunctionDeclarator() && "Not a function declarator!"); + unsigned index = 0; + isFunctionDeclarator(index); + return DeclTypeInfo[index].Fun; + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + const DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() const { + return const_cast<Declarator*>(this)->getFunctionTypeInfo(); } /// AddAttributes - simply adds the attribute list to the Declarator. @@ -1337,19 +1437,25 @@ public: /// __attribute__((common,deprecated)); /// /// Also extends the range of the declarator. - void AddAttributes(AttributeList *alist, SourceLocation LastLoc) { + void addAttributes(AttributeList *alist, SourceLocation LastLoc) { AttrList = addAttributeLists(AttrList, alist); if (!LastLoc.isInvalid()) SetRangeEnd(LastLoc); } + void addAttributes(const ParsedAttributes &attrs) { + addAttributes(attrs.getList(), SourceLocation()); + } + const AttributeList *getAttributes() const { return AttrList; } AttributeList *getAttributes() { return AttrList; } + AttributeList *&getAttrListRef() { return AttrList; } + /// hasAttributes - do we contain any attributes? bool hasAttributes() const { - if (getAttributes() || getDeclSpec().getAttributes()) return true; + if (getAttributes() || getDeclSpec().hasAttributes()) return true; for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) if (getTypeObject(i).getAttrs()) return true; @@ -1369,6 +1475,10 @@ public: void setGroupingParens(bool flag) { GroupingParens = flag; } bool hasGroupingParens() const { return GroupingParens; } + + bool hasEllipsis() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; } }; /// FieldDeclarator - This little struct is used to capture information about @@ -1380,7 +1490,69 @@ struct FieldDeclarator { BitfieldSize = 0; } }; - + +/// VirtSpecifiers - Represents a C++0x virt-specifier-seq. +class VirtSpecifiers { +public: + enum Specifier { + VS_None = 0, + VS_Override = 1, + VS_Final = 2, + VS_New = 4 + }; + + VirtSpecifiers() : Specifiers(0) { } + + bool SetSpecifier(Specifier VS, SourceLocation Loc, + const char *&PrevSpec); + + bool isOverrideSpecified() const { return Specifiers & VS_Override; } + SourceLocation getOverrideLoc() const { return VS_overrideLoc; } + + bool isFinalSpecified() const { return Specifiers & VS_Final; } + SourceLocation getFinalLoc() const { return VS_finalLoc; } + + bool isNewSpecified() const { return Specifiers & VS_New; } + SourceLocation getNewLoc() const { return VS_newLoc; } + + void clear() { Specifiers = 0; } + + static const char *getSpecifierName(Specifier VS); + +private: + unsigned Specifiers; + + SourceLocation VS_overrideLoc, VS_finalLoc, VS_newLoc; +}; + +/// ClassVirtSpecifiers - Represents a C++0x class-virt-specifier-seq. +class ClassVirtSpecifiers { +public: + enum Specifier { + CVS_None = 0, + CVS_Final = 1, + CVS_Explicit = 2 + }; + + ClassVirtSpecifiers() : Specifiers(0) { } + + bool SetSpecifier(Specifier CVS, SourceLocation Loc, + const char *&PrevSpec); + + bool isFinalSpecified() const { return Specifiers & CVS_Final; } + SourceLocation getFinalLoc() const { return CVS_finalLoc; } + + bool isExplicitSpecified() const { return Specifiers & CVS_Explicit; } + SourceLocation getExplicitLoc() const { return CVS_explicitLoc; } + + static const char *getSpecifierName(Specifier CVS); + +private: + unsigned Specifiers; + + SourceLocation CVS_finalLoc, CVS_explicitLoc; +}; + } // end namespace clang #endif diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h index 6a9a1bf5b608..6e808de9a147 100644 --- a/include/clang/Sema/DelayedDiagnostic.h +++ b/include/clang/Sema/DelayedDiagnostic.h @@ -101,7 +101,7 @@ public: private: unsigned Access : 2; - bool IsMember; + unsigned IsMember : 1; NamedDecl *Target; CXXRecordDecl *NamingClass; QualType BaseObjectType; @@ -119,14 +119,6 @@ public: SourceLocation Loc; - union { - /// Deprecation. - struct { NamedDecl *Decl; } DeprecationData; - - /// Access control. - char AccessData[sizeof(AccessedEntity)]; - }; - void destroy() { switch (Kind) { case Access: getAccessData().~AccessedEntity(); break; @@ -135,12 +127,15 @@ public: } static DelayedDiagnostic makeDeprecation(SourceLocation Loc, - NamedDecl *D) { + const NamedDecl *D, + llvm::StringRef Msg) { DelayedDiagnostic DD; DD.Kind = Deprecation; DD.Triggered = false; DD.Loc = Loc; DD.DeprecationData.Decl = D; + DD.DeprecationData.Message = Msg.data(); + DD.DeprecationData.MessageLen = Msg.size(); return DD; } @@ -155,11 +150,37 @@ public: } AccessedEntity &getAccessData() { + assert(Kind == Access && "Not an access diagnostic."); return *reinterpret_cast<AccessedEntity*>(AccessData); } const AccessedEntity &getAccessData() const { + assert(Kind == Access && "Not an access diagnostic."); return *reinterpret_cast<const AccessedEntity*>(AccessData); } + + const NamedDecl *getDeprecationDecl() const { + assert(Kind == Deprecation && "Not a deprecation diagnostic."); + return DeprecationData.Decl; + } + + llvm::StringRef getDeprecationMessage() const { + assert(Kind == Deprecation && "Not a deprecation diagnostic."); + return llvm::StringRef(DeprecationData.Message, + DeprecationData.MessageLen); + } + +private: + union { + /// Deprecation. + struct { + const NamedDecl *Decl; + const char *Message; + size_t MessageLen; + } DeprecationData; + + /// Access control. + char AccessData[sizeof(AccessedEntity)]; + }; }; } diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 7be003390b10..6d7bc6316bd2 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -14,10 +14,11 @@ #define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H #include "clang/AST/ExternalASTSource.h" -#include "clang/Sema/ObjCMethodList.h" +#include <utility> namespace clang { +struct ObjCMethodList; class Sema; /// \brief An abstract interface that should be implemented by @@ -44,10 +45,7 @@ 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) { - return std::pair<ObjCMethodList, ObjCMethodList>(); - } + virtual std::pair<ObjCMethodList,ObjCMethodList> ReadMethodPool(Selector Sel); // isa/cast/dyn_cast support static bool classof(const ExternalASTSource *Source) { diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 0062b3a29adc..c1915659905b 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -88,6 +88,10 @@ private: /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. DeclaratorDecl *VariableOrMember; + /// \brief When Kind == EK_Temporary, the type source information for + /// the temporary. + TypeSourceInfo *TypeInfo; + struct { /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the /// location of the 'return', 'throw', or 'new' keyword, @@ -114,12 +118,12 @@ private: /// \brief Create the initialization entity for a variable. InitializedEntity(VarDecl *Var) : Kind(EK_Variable), Parent(0), Type(Var->getType()), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) { } + VariableOrMember(Var) { } /// \brief Create the initialization entity for a parameter. InitializedEntity(ParmVarDecl *Parm) : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) { } + VariableOrMember(Parm) { } /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or @@ -135,7 +139,7 @@ private: /// \brief Create the initialization entity for a member subobject. InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) : Kind(EK_Member), Parent(Parent), Type(Member->getType()), - VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) { } + VariableOrMember(Member) { } /// \brief Create the initialization entity for an array element. InitializedEntity(ASTContext &Context, unsigned Index, @@ -148,16 +152,20 @@ public: } /// \brief Create the initialization entity for a parameter. - static InitializedEntity InitializeParameter(ParmVarDecl *Parm) { - return InitializedEntity(Parm); + static InitializedEntity InitializeParameter(ASTContext &Context, + ParmVarDecl *Parm) { + InitializedEntity Res(Parm); + Res.Type = Context.getVariableArrayDecayedType(Res.Type); + return Res; } /// \brief Create the initialization entity for a parameter that is /// only known by its type. - static InitializedEntity InitializeParameter(QualType Type) { + static InitializedEntity InitializeParameter(ASTContext &Context, + QualType Type) { InitializedEntity Entity; Entity.Kind = EK_Parameter; - Entity.Type = Type; + Entity.Type = Context.getVariableArrayDecayedType(Type); Entity.Parent = 0; Entity.VariableOrMember = 0; return Entity; @@ -189,7 +197,15 @@ public: static InitializedEntity InitializeTemporary(QualType Type) { return InitializedEntity(EK_Temporary, SourceLocation(), Type); } - + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) { + InitializedEntity Result(EK_Temporary, SourceLocation(), + TypeInfo->getType()); + Result.TypeInfo = TypeInfo; + return Result; + } + /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base, @@ -201,6 +217,12 @@ public: return InitializedEntity(Member, Parent); } + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity InitializeMember(IndirectFieldDecl *Member, + const InitializedEntity *Parent = 0) { + return InitializedEntity(Member->getAnonField(), Parent); + } + /// \brief Create the initialization entity for an array element. static InitializedEntity InitializeElement(ASTContext &Context, unsigned Index, @@ -219,6 +241,15 @@ public: /// \brief Retrieve type being initialized. QualType getType() const { return Type; } + /// \brief Retrieve complete type-source information for the object being + /// constructed, if known. + TypeSourceInfo *getTypeSourceInfo() const { + if (Kind == EK_Temporary) + return TypeInfo; + + return 0; + } + /// \brief Retrieve the name of the entity being initialized. DeclarationName getName() const; @@ -760,12 +791,18 @@ public: return FailedCandidateSet; } + /// brief Get the overloading result, for when the initialization + /// sequence failed due to a bad overload. + OverloadingResult getFailedOverloadResult() const { + return FailedOverloadResult; + } + /// \brief Determine why initialization failed. FailureKind getFailureKind() const { assert(getKind() == FailedSequence && "Not an initialization failure!"); return Failure; } - + /// \brief Dump a representation of this initialization sequence to /// the given stream, for debugging purposes. void dump(llvm::raw_ostream &OS) const; diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index 1c7720abb1e1..aa58d14fac73 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -365,6 +365,11 @@ public: if (Decls.empty()) { if (ResultKind != NotFoundInCurrentInstantiation) ResultKind = NotFound; + + if (Paths) { + deletePaths(Paths); + Paths = 0; + } } else { AmbiguityKind SavedAK = Ambiguity; ResultKind = Found; @@ -492,25 +497,18 @@ public: LookupResult &Results; LookupResult::iterator I; bool Changed; -#ifndef NDEBUG bool CalledDone; -#endif friend class LookupResult; Filter(LookupResult &Results) - : Results(Results), I(Results.begin()), Changed(false) -#ifndef NDEBUG - , CalledDone(false) -#endif + : Results(Results), I(Results.begin()), Changed(false), CalledDone(false) {} public: -#ifndef NDEBUG ~Filter() { assert(CalledDone && "LookupResult::Filter destroyed without done() call"); } -#endif bool hasNext() const { return I != Results.end(); @@ -541,10 +539,8 @@ public: } void done() { -#ifndef NDEBUG assert(!CalledDone && "done() called twice"); CalledDone = true; -#endif if (Changed) Results.resolveKindAfterFilter(); @@ -573,11 +569,7 @@ private: void configure(); // Sanity checks. -#ifndef NDEBUG void sanity() const; -#else - void sanity() const {} -#endif bool sanityCheckUnresolved() const { for (iterator I = begin(), E = end(); I != E; ++I) diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 851d68ac4d79..3ce3513c21ae 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -75,6 +75,7 @@ namespace clang { ICK_Vector_Conversion, ///< Vector conversions ICK_Vector_Splat, ///< A vector splat from an arithmetic type ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) + ICK_Block_Pointer_Conversion, ///< Block Pointer conversions ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -130,27 +131,37 @@ namespace clang { /// Third - The third conversion can be a qualification conversion. ImplicitConversionKind Third : 8; - /// Deprecated - Whether this the deprecated conversion of a + /// \brief Whether this is the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - bool DeprecatedStringLiteralToCharPtr : 1; + unsigned DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). - bool IncompatibleObjC : 1; + unsigned IncompatibleObjC : 1; /// ReferenceBinding - True when this is a reference binding /// (C++ [over.ics.ref]). - bool ReferenceBinding : 1; + unsigned ReferenceBinding : 1; /// DirectBinding - True when this is a reference binding that is a /// direct binding (C++ [dcl.init.ref]). - bool DirectBinding : 1; - - /// RRefBinding - True when this is a reference binding of an rvalue - /// reference to an rvalue (C++0x [over.ics.rank]p3b4). - bool RRefBinding : 1; + unsigned DirectBinding : 1; + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + + /// \brief Whether this binds an implicit object argument to a + /// non-static member function without a ref-qualifier. + unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + /// FromType - The type that this conversion is converting /// from. This is an opaque pointer that can be translated into a /// QualType. @@ -231,6 +242,11 @@ namespace clang { /// user-defined conversion. FunctionDecl* ConversionFunction; + /// \brief The declaration that we found via name lookup, which might be + /// the same as \c ConversionFunction or it might be a using declaration + /// that refers to \c ConversionFunction. + NamedDecl *FoundConversionFunction; + void DebugPrint() const; }; @@ -283,7 +299,9 @@ namespace clang { no_conversion, unrelated_class, suppressed_user, - bad_qualifiers + bad_qualifiers, + lvalue_ref_to_rvalue, + rvalue_ref_to_lvalue }; // This can be null, e.g. for implicit object arguments. @@ -549,6 +567,10 @@ namespace clang { /// Actually an OverloadFailureKind. unsigned char FailureKind; + /// \brief The number of call arguments that were explicitly provided, + /// to be used while performing partial ordering of function templates. + unsigned ExplicitCallArguments; + /// A structure used to record information about a failed /// template argument deduction. struct DeductionFailureInfo { @@ -630,7 +652,8 @@ namespace clang { /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator& Best); + OverloadCandidateSet::iterator& Best, + bool UserDefinedConversion = false); void NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, @@ -642,7 +665,8 @@ namespace clang { bool isBetterOverloadCandidate(Sema &S, const OverloadCandidate& Cand1, const OverloadCandidate& Cand2, - SourceLocation Loc); + SourceLocation Loc, + bool UserDefinedConversion = false); } // end namespace clang #endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h index 7739f3a5d229..5f2f0eba7124 100644 --- a/include/clang/Sema/Ownership.h +++ b/include/clang/Sema/Ownership.h @@ -23,7 +23,7 @@ namespace clang { class Attr; - class CXXBaseOrMemberInitializer; + class CXXCtorInitializer; class CXXBaseSpecifier; class Decl; class DeclGroupRef; @@ -106,6 +106,9 @@ namespace llvm { } enum { NumLowBitsAvailable = 0 }; }; + + template <class T> + struct isPodLike<clang::OpaquePtr<T> > { static const bool value = true; }; } @@ -414,7 +417,7 @@ namespace clang { template<> struct IsResultPtrLowBitFree<CXXBaseSpecifier*> { static const bool value = true; }; - template<> struct IsResultPtrLowBitFree<CXXBaseOrMemberInitializer*> { + template<> struct IsResultPtrLowBitFree<CXXCtorInitializer*> { static const bool value = true; }; @@ -427,7 +430,7 @@ namespace clang { typedef ActionResult<Stmt*> StmtResult; typedef ActionResult<ParsedType> TypeResult; typedef ActionResult<CXXBaseSpecifier*> BaseResult; - typedef ActionResult<CXXBaseOrMemberInitializer*> MemInitResult; + typedef ActionResult<CXXCtorInitializer*> MemInitResult; typedef ActionResult<Decl*> DeclResult; typedef OpaquePtr<TemplateName> ParsedTemplateTy; diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h index da68a494bf7b..5aa6f47425aa 100644 --- a/include/clang/Sema/ParsedTemplate.h +++ b/include/clang/Sema/ParsedTemplate.h @@ -32,7 +32,9 @@ namespace clang { Template }; - /// \brief Build an empty template argument. This template argument + /// \brief Build an empty template argument. + /// + /// This template argument is invalid. ParsedTemplateArgument() : Kind(Type), Arg(0) { } /// \brief Create a template type argument or non-type template argument. @@ -56,7 +58,7 @@ namespace clang { SourceLocation TemplateLoc) : Kind(ParsedTemplateArgument::Template), Arg(Template.getAsOpaquePtr()), - Loc(TemplateLoc), SS(SS) { } + Loc(TemplateLoc), SS(SS), EllipsisLoc() { } /// \brief Determine whether the given template argument is invalid. bool isInvalid() const { return Arg == 0; } @@ -93,6 +95,21 @@ namespace clang { return SS; } + /// \brief Retrieve the location of the ellipsis that makes a template + /// template argument into a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(Kind == Template && + "Only template template arguments can have an ellipsis"); + return EllipsisLoc; + } + + /// \brief Retrieve a pack expansion of the given template template + /// argument. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument getTemplatePackExpansion( + SourceLocation EllipsisLoc) const; + private: KindType Kind; @@ -107,6 +124,10 @@ namespace clang { /// \brief The nested-name-specifier that can accompany a template template /// argument. CXXScopeSpec SS; + + /// \brief The ellipsis location that can accompany a template template + /// argument (turning it into a template template argument expansion). + SourceLocation EllipsisLoc; }; /// \brief Information about a template-id annotation @@ -161,7 +182,10 @@ namespace clang { void Destroy() { free(this); } }; - + + /// Retrieves the range of the given template parameter lists. + SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params, + unsigned NumParams); inline const ParsedTemplateArgument & ASTTemplateArgsPtr::operator[](unsigned Arg) const { diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index 4229c6c62748..d7fda35cdb87 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SEMA_SCOPE_H #define LLVM_CLANG_SEMA_SCOPE_H +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { @@ -52,7 +53,7 @@ public: /// ClassScope - The scope of a struct/union/class definition. ClassScope = 0x20, - /// BlockScope - This is a scope that corresponds to a block object. + /// BlockScope - This is a scope that corresponds to a block/closure object. /// Blocks serve as top-level scopes for some objects like labels, they /// also prevent things like break and continue. BlockScopes always have /// the FnScope, BreakScope, ContinueScope, and DeclScope flags set as well. @@ -131,11 +132,12 @@ private: typedef llvm::SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy; UsingDirectivesTy UsingDirectives; - /// \brief The number of errors at the start of the given scope. - unsigned NumErrorsAtStart; + /// \brief Used to determine if errors occurred in this scope. + DiagnosticErrorTrap ErrorTrap; public: - Scope(Scope *Parent, unsigned ScopeFlags) { + Scope(Scope *Parent, unsigned ScopeFlags, Diagnostic &Diag) + : ErrorTrap(Diag) { Init(Parent, ScopeFlags); } @@ -144,8 +146,7 @@ public: unsigned getFlags() const { return Flags; } void setFlags(unsigned F) { Flags = F; } - /// isBlockScope - Return true if this scope does not correspond to a - /// closure. + /// isBlockScope - Return true if this scope correspond to a closure. bool isBlockScope() const { return Flags & BlockScope; } /// getParent - Return the scope that this is nested in. @@ -214,13 +215,7 @@ public: void* getEntity() const { return Entity; } void setEntity(void *E) { Entity = E; } - /// \brief Retrieve the number of errors that had been emitted when we - /// entered this scope. - unsigned getNumErrorsAtStart() const { return NumErrorsAtStart; } - - void setNumErrorsAtStart(unsigned NumErrors) { - NumErrorsAtStart = NumErrors; - } + bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); } /// isClassScope - Return true if this scope is a class/struct/union scope. bool isClassScope() const { @@ -318,7 +313,7 @@ public: DeclsInScope.clear(); UsingDirectives.clear(); Entity = 0; - NumErrorsAtStart = 0; + ErrorTrap.reset(); } }; diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 50cfa9bb5672..b0bb95509a91 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -17,12 +17,13 @@ #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SetVector.h" namespace clang { class BlockDecl; class IdentifierInfo; -class LabelStmt; +class LabelDecl; class ReturnStmt; class Scope; class SwitchStmt; @@ -48,14 +49,8 @@ public: /// \brief Whether this function contains any indirect gotos. bool HasIndirectGoto; - /// \brief The number of errors that had occurred before starting this - /// function or block. - unsigned NumErrorsAtStartOfFunction; - - /// LabelMap - This is a mapping from label identifiers to the LabelStmt for - /// it (which acts like the label decl in some ways). Forward referenced - /// labels have a LabelStmt created for them with a null location & SubStmt. - llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; + /// \brief Used to determine if errors occurred in this function or block. + DiagnosticErrorTrap ErrorTrap; /// SwitchStack - This is the current set of active switch statements in the /// block. @@ -64,7 +59,7 @@ public: /// \brief The list of return statements that occur within the function or /// block, if there is any chance of applying the named return value /// optimization. - llvm::SmallVector<ReturnStmt *, 4> Returns; + llvm::SmallVector<ReturnStmt*, 4> Returns; void setHasBranchIntoScope() { HasBranchIntoScope = true; @@ -83,18 +78,18 @@ public: (HasBranchProtectedScope && HasBranchIntoScope); } - FunctionScopeInfo(unsigned NumErrors) + FunctionScopeInfo(Diagnostic &Diag) : IsBlockInfo(false), HasBranchProtectedScope(false), HasBranchIntoScope(false), HasIndirectGoto(false), - NumErrorsAtStartOfFunction(NumErrors) { } + ErrorTrap(Diag) { } virtual ~FunctionScopeInfo(); /// \brief Clear out the information in this function scope, making it /// suitable for reuse. - void Clear(unsigned NumErrors); + void Clear(); static bool classof(const FunctionScopeInfo *FSI) { return true; } }; @@ -102,8 +97,6 @@ public: /// \brief Retains information about a block that is currently being parsed. class BlockScopeInfo : public FunctionScopeInfo { public: - bool hasBlockDeclRefExprs; - BlockDecl *TheDecl; /// TheScope - This is the scope for the block itself, which contains @@ -118,9 +111,18 @@ public: /// Its return type may be BuiltinType::Dependent. QualType FunctionType; - BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(NumErrors), hasBlockDeclRefExprs(false), - TheDecl(Block), TheScope(BlockScope) + /// CaptureMap - A map of captured variables to (index+1) into Captures. + llvm::DenseMap<VarDecl*, unsigned> CaptureMap; + + /// Captures - The captured variables. + llvm::SmallVector<BlockDecl::Capture, 4> Captures; + + /// CapturesCXXThis - Whether this block captures 'this'. + bool CapturesCXXThis; + + BlockScopeInfo(Diagnostic &Diag, Scope *BlockScope, BlockDecl *Block) + : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope), + CapturesCXXThis(false) { IsBlockInfo = true; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4741028cb0c9..91d6914f24e3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -20,9 +20,10 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/DeclSpec.h" -#include "clang/AST/OperationKinds.h" +#include "clang/AST/Expr.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" @@ -62,6 +63,7 @@ namespace clang { class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class CodeCompleteConsumer; + class CodeCompletionAllocator; class CodeCompletionResult; class Decl; class DeclAccessPair; @@ -78,7 +80,6 @@ namespace clang { class ExternalSemaSource; class FormatAttr; class FriendDecl; - class FullExpr; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; @@ -121,7 +122,6 @@ namespace clang { class TargetAttributesSema; class TemplateArgument; class TemplateArgumentList; - class TemplateArgumentListBuilder; class TemplateArgumentLoc; class TemplateDecl; class TemplateParameterList; @@ -129,6 +129,7 @@ namespace clang { class TemplateTemplateParmDecl; class Token; class TypedefDecl; + class TypeLoc; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; @@ -140,7 +141,8 @@ namespace clang { class VarDecl; class VisibilityAttr; class VisibleDeclConsumer; - + class IndirectFieldDecl; + namespace sema { class AccessedEntity; class BlockScopeInfo; @@ -165,7 +167,10 @@ class LocInfoType : public Type { TypeSourceInfo *DeclInfo; LocInfoType(QualType ty, TypeSourceInfo *TInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) { + : Type((TypeClass)LocInfo, ty, ty->isDependentType(), + ty->isVariablyModifiedType(), + ty->containsUnexpandedParameterPack()), + DeclInfo(TInfo) { assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); } friend class Sema; @@ -183,6 +188,11 @@ public: static bool classof(const LocInfoType *) { return true; } }; +// FIXME: No way to easily map from TemplateTypeParmTypes to +// TemplateTypeParmDecls, so we have this horrible PointerUnion. +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, + SourceLocation> UnexpandedParameterPack; + /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema&); // DO NOT IMPLEMENT @@ -194,12 +204,15 @@ public: typedef OpaquePtr<QualType> TypeTy; typedef Attr AttrTy; typedef CXXBaseSpecifier BaseTy; - typedef CXXBaseOrMemberInitializer MemInitTy; + typedef CXXCtorInitializer MemInitTy; typedef Expr ExprTy; typedef Stmt StmtTy; typedef TemplateParameterList TemplateParamsTy; typedef NestedNameSpecifier CXXScopeTy; + OpenCLOptions OpenCLFeatures; + FPOptions FPFeatures; + const LangOptions &LangOpts; Preprocessor &PP; ASTContext &Context; @@ -220,30 +233,6 @@ public: /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; - /// A RAII object to temporarily push a declaration context. - class ContextRAII { - private: - Sema &S; - DeclContext *SavedContext; - - public: - ContextRAII(Sema &S, DeclContext *ContextToPush) - : S(S), SavedContext(S.CurContext) { - assert(ContextToPush && "pushing null context"); - S.CurContext = ContextToPush; - } - - void pop() { - if (!SavedContext) return; - S.CurContext = SavedContext; - SavedContext = 0; - } - - ~ContextRAII() { - pop(); - } - }; - /// PackContext - Manages the stack for #pragma pack. An alignment /// of 0 indicates default alignment. void *PackContext; // Really a "PragmaPackStack*" @@ -312,14 +301,125 @@ public: /// and must warn if not used. Only contains the first declaration. llvm::SmallVector<const DeclaratorDecl*, 4> UnusedFileScopedDecls; - /// \brief The stack of diagnostics that were delayed due to being - /// produced during the parsing of a declaration. - llvm::SmallVector<sema::DelayedDiagnostic, 0> DelayedDiagnostics; + class DelayedDiagnostics; + + class ParsingDeclState { + unsigned SavedStackSize; + friend class Sema::DelayedDiagnostics; + }; + + class ProcessingContextState { + unsigned SavedParsingDepth; + unsigned SavedActiveStackBase; + friend class Sema::DelayedDiagnostics; + }; + + /// A class which encapsulates the logic for delaying diagnostics + /// during parsing and other processing. + class DelayedDiagnostics { + /// \brief The stack of diagnostics that were delayed due to being + /// produced during the parsing of a declaration. + sema::DelayedDiagnostic *Stack; + + /// \brief The number of objects on the delayed-diagnostics stack. + unsigned StackSize; + + /// \brief The current capacity of the delayed-diagnostics stack. + unsigned StackCapacity; + + /// \brief The index of the first "active" delayed diagnostic in + /// the stack. When parsing class definitions, we ignore active + /// delayed diagnostics from the surrounding context. + unsigned ActiveStackBase; + + /// \brief The depth of the declarations we're currently parsing. + /// This gets saved and reset whenever we enter a class definition. + unsigned ParsingDepth; + + public: + DelayedDiagnostics() : Stack(0), StackSize(0), StackCapacity(0), + ActiveStackBase(0), ParsingDepth(0) {} + + ~DelayedDiagnostics() { + delete[] reinterpret_cast<char*>(Stack); + } - /// \brief The depth of the current ParsingDeclaration stack. - /// If nonzero, we are currently parsing a declaration (and - /// hence should delay deprecation warnings). - unsigned ParsingDeclDepth; + /// Adds a delayed diagnostic. + void add(const sema::DelayedDiagnostic &diag); + + /// Determines whether diagnostics should be delayed. + bool shouldDelayDiagnostics() { return ParsingDepth > 0; } + + /// Observe that we've started parsing a declaration. Access and + /// deprecation diagnostics will be delayed; when the declaration + /// is completed, all active delayed diagnostics will be evaluated + /// in its context, and then active diagnostics stack will be + /// popped down to the saved depth. + ParsingDeclState pushParsingDecl() { + ParsingDepth++; + + ParsingDeclState state; + state.SavedStackSize = StackSize; + return state; + } + + /// Observe that we're completed parsing a declaration. + static void popParsingDecl(Sema &S, ParsingDeclState state, Decl *decl); + + /// Observe that we've started processing a different context, the + /// contents of which are semantically separate from the + /// declarations it may lexically appear in. This sets aside the + /// current stack of active diagnostics and starts afresh. + ProcessingContextState pushContext() { + assert(StackSize >= ActiveStackBase); + + ProcessingContextState state; + state.SavedParsingDepth = ParsingDepth; + state.SavedActiveStackBase = ActiveStackBase; + + ActiveStackBase = StackSize; + ParsingDepth = 0; + + return state; + } + + /// Observe that we've stopped processing a context. This + /// restores the previous stack of active diagnostics. + void popContext(ProcessingContextState state) { + assert(ActiveStackBase == StackSize); + assert(ParsingDepth == 0); + ActiveStackBase = state.SavedActiveStackBase; + ParsingDepth = state.SavedParsingDepth; + } + } DelayedDiagnostics; + + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + ProcessingContextState SavedContextState; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush) + : S(S), SavedContext(S.CurContext), + SavedContextState(S.DelayedDiagnostics.pushContext()) + { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + S.DelayedDiagnostics.popContext(SavedContextState); + SavedContext = 0; + } + + ~ContextRAII() { + pop(); + } + }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// #pragma weak before declared. rare. may alias another @@ -365,6 +465,12 @@ public: /// standard library. LazyDeclPtr StdBadAlloc; + /// \brief The C++ "type_info" declaration, which is defined in <typeinfo>. + RecordDecl *CXXTypeInfoDecl; + + /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. + RecordDecl *MSVCGuidDecl; + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; @@ -398,7 +504,17 @@ public: /// This evaluation context is used primary for the operand of the C++ /// \c typeid expression, whose argument is potentially evaluated only when /// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2). - PotentiallyPotentiallyEvaluated + PotentiallyPotentiallyEvaluated, + + /// \brief The current expression is potentially evaluated, but any + /// declarations referenced inside that expression are only used if + /// in fact the current expression is used. + /// + /// This value is used when parsing default function arguments, for which + /// we would like to provide diagnostics (e.g., passing non-POD arguments + /// through varargs) but do not want to mark declarations as "referenced" + /// until the default argument is used. + PotentiallyEvaluatedIfUsed }; /// \brief Data structure used to record current or nested @@ -468,6 +584,26 @@ public: /// \brief The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; + typedef llvm::DenseMap<ParmVarDecl *, llvm::SmallVector<ParmVarDecl *, 1> > + UnparsedDefaultArgInstantiationsMap; + + /// \brief A mapping from parameters with unparsed default arguments to the + /// set of instantiations of each parameter. + /// + /// This mapping is a temporary data structure used when parsing + /// nested class templates or nested classes of class templates, + /// where we might end up instantiating an inner class before the + /// default arguments of its methods have been parsed. + UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; + + // Contains the locations of the beginning of unparsed default + // argument locations. + llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs; + + /// UndefinedInternals - all the used, undefined objects with + /// internal linkage in this translation unit. + llvm::DenseMap<NamedDecl*, SourceLocation> UndefinedInternals; + typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods; typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool; @@ -481,7 +617,6 @@ public: /// of -Wselector. llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors; - GlobalMethodPool::iterator ReadMethodPool(Selector Sel); /// Private Helper predicate to check for 'self'. @@ -497,6 +632,9 @@ public: void Initialize(); const LangOptions &getLangOptions() const { return LangOpts; } + OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } + FPOptions &getFPOptions() { return FPFeatures; } + Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } const TargetAttributesSema &getTargetAttributesSema() const; @@ -580,16 +718,20 @@ public: SourceLocation AttrLoc); QualType BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, - bool Variadic, unsigned Quals, + bool Variadic, unsigned Quals, + RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, - const FunctionType::ExtInfo &Info); + FunctionType::ExtInfo Info); QualType BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); + QualType BuildParenType(QualType T); + TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl = 0); + TagDecl **OwnedDecl = 0, + bool AllowAutoInTypeName = false); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); /// \brief Package the given type and TSI into a ParsedType. @@ -630,8 +772,8 @@ public: QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); - QualType BuildTypeofExprType(Expr *E); - QualType BuildDecltypeType(Expr *E); + QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + QualType BuildDecltypeType(Expr *E, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. @@ -644,6 +786,7 @@ public: ParsedType getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = 0, bool isClassName = false, + bool HasTrailingDot = false, ParsedType ObjectType = ParsedType()); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool DiagnoseUnknownTypeName(const IdentifierInfo &II, @@ -674,18 +817,19 @@ public: bool &Redeclaration); void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous, bool &Redeclaration); + void CheckCompleteVariableDeclaration(VarDecl *var); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration); - void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); void CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired); + bool &Redeclaration); void CheckMain(FunctionDecl *FD); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, @@ -707,14 +851,9 @@ public: bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); - - // Contains the locations of the beginning of unparsed default - // argument locations. - llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs; - - void AddInitializerToDecl(Decl *dcl, Expr *init); - void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); - void ActOnUninitializedDecl(Decl *dcl, bool TypeContainsUndeducedAuto); + void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit, + bool TypeMayContainAuto); + void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, @@ -734,6 +873,14 @@ public: void DiagnoseUnusedParameters(ParmVarDecl * const *Begin, ParmVarDecl * const *End); + /// \brief Diagnose whether the size of parameters or return value of a + /// function or obj-c method definition is pass-by-value and larger than a + /// specified threshold. + void DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Begin, + ParmVarDecl * const *End, + QualType ReturnTy, + NamedDecl *D); + void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr); @@ -745,11 +892,16 @@ public: /// no declarator (e.g. "struct foo;") is parsed. Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS); + + StmtResult ActOnVlaStmt(const DeclSpec &DS); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record); + Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record); + bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, SourceLocation NewTagLoc, @@ -767,7 +919,15 @@ public: IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent); + bool &OwnedDecl, bool &IsDependent, bool ScopedEnum, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType); + + Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, + unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, @@ -826,6 +986,7 @@ public: /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, + ClassVirtSpecifiers &CVS, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing @@ -845,6 +1006,7 @@ public: Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, + AttributeList *Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDecl, @@ -897,6 +1059,7 @@ public: void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); + void MergeVarDeclTypes(VarDecl *New, VarDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); @@ -927,7 +1090,7 @@ public: Ovl_NonFunction }; OverloadKind CheckOverload(Scope *S, - FunctionDecl *New, + FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, bool IsForUsingDecl); @@ -938,7 +1101,8 @@ public: Expr *From, bool SuppressUserConversions, bool AllowExplicit, - bool InOverloadResolution); + bool InOverloadResolution, + bool CStyle); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); @@ -948,8 +1112,10 @@ public: QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); - bool FunctionArgTypesAreEqual (FunctionProtoType* OldType, - FunctionProtoType* NewType); + bool IsBlockPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType); + bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType, + const FunctionProtoType *NewType); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, @@ -962,10 +1128,16 @@ public: CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); - bool IsQualificationConversion(QualType FromType, QualType ToType); + bool IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); + ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, + Expr *Value); + ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init); @@ -1014,12 +1186,14 @@ public: bool SuppressUserConversions = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -1028,6 +1202,7 @@ public: CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -1051,7 +1226,7 @@ public: DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - QualType ObjectTy, Expr **Args, unsigned NumArgs, + Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, @@ -1074,12 +1249,28 @@ public: OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); + // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(FunctionDecl *Fn); - - FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, + + // Emit as a series of 'note's all template and non-templates + // identified by the expression Expr + void NoteAllOverloadCandidates(Expr* E); + + // [PossiblyAFunctionType] --> [Return] + // NonFunctionType --> NonFunctionType + // R (A) --> R(A) + // R (*)(A) --> R (A) + // R (&)(A) --> R (A) + // R (S::*)(A) --> R (A) + QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); + + FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found); - FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); + + FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From, + bool Complain = false, + DeclAccessPair* Found = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, @@ -1097,8 +1288,8 @@ public: UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + Expr *ExecConfig); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, @@ -1117,12 +1308,10 @@ public: ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, - unsigned NumArgs, SourceLocation *CommaLocs, - SourceLocation RParenLoc); + unsigned NumArgs, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, @@ -1135,7 +1324,8 @@ public: CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. - bool CheckParmsForFunctionDef(FunctionDecl *FD); + bool CheckParmsForFunctionDef(ParmVarDecl **Param, ParmVarDecl **ParamEnd, + bool CheckParameterNames); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); Scope *getNonFieldDeclScope(Scope *S); @@ -1176,13 +1366,14 @@ public: /// Tag name lookup, which finds the names of enums, classes, /// structs, and unions. LookupTagName, + /// Label name lookup. + LookupLabel, /// Member name lookup, which finds the names of /// class/struct/union members. LookupMemberName, - // Look up of an operator name (e.g., operator+) for use with - // operator overloading. This lookup is similar to ordinary name - // lookup, but will ignore any declarations that are class - // members. + /// Look up of an operator name (e.g., operator+) for use with + /// operator overloading. This lookup is similar to ordinary name + /// lookup, but will ignore any declarations that are class members. LookupOperatorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, @@ -1245,6 +1436,9 @@ public: QualType T1, QualType T2, UnresolvedSetImpl &Functions); + LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, + bool isLocalLabel = false); + DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); @@ -1277,6 +1471,10 @@ public: CTC_CXXCasts, /// \brief A member lookup context. CTC_MemberLookup, + /// \brief An Objective-C ivar lookup context (e.g., self->ivar). + CTC_ObjCIvarLookup, + /// \brief An Objective-C property lookup context (e.g., self.prop). + CTC_ObjCPropertyLookup, /// \brief The receiver of an Objective-C message send within an /// Objective-C method where 'super' is a valid keyword. CTC_ObjCMessageReceiver @@ -1308,8 +1506,14 @@ public: // More parsing and symbol table subroutines. // Decl attributes - this routine is the top level dispatcher. - void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); - void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL); + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + bool NonInheritable = true, bool Inheritable = true); + void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, + bool NonInheritable = true, bool Inheritable = true); + + bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); + bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC); + bool CheckNoReturnAttr(const AttributeList &attr); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID); @@ -1338,6 +1542,14 @@ public: ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); + /// \brief Determine whether we can synthesize a provisional ivar for the + /// given name. + ObjCPropertyDecl *canSynthesizeProvisionalIvar(IdentifierInfo *II); + + /// \brief Determine whether we can synthesize a provisional ivar for the + /// given property. + bool canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property); + /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category @implementation. void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, @@ -1484,7 +1696,7 @@ 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 // emulation code from Ownership.h). - FullExprArg(const FullExprArg& Other): E(Other.E) {} + FullExprArg(const FullExprArg& Other) : E(Other.E) {} ExprResult release() { return move(E); @@ -1498,7 +1710,7 @@ public: private: // FIXME: No need to make the entire Sema class a friend when it's just - // Sema::FullExpr that needs access to the constructor below. + // Sema::MakeFullExpr that needs access to the constructor below. friend class Sema; explicit FullExprArg(Expr *expr) : E(expr) {} @@ -1512,7 +1724,8 @@ public: StmtResult ActOnExprStmt(FullExprArg Expr); - StmtResult ActOnNullStmt(SourceLocation SemiLoc); + StmtResult ActOnNullStmt(SourceLocation SemiLoc, + bool LeadingEmptyMacro = false); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, MultiStmtArg Elts, bool isStmtExpr); @@ -1520,6 +1733,7 @@ public: SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + StmtResult ActOnForEachLValueExpr(Expr *E); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, SourceLocation DotDotDotLoc, Expr *RHSVal, SourceLocation ColonLoc); @@ -1528,22 +1742,21 @@ public: StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); - StmtResult ActOnLabelStmt(SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation ColonLoc, - Stmt *SubStmt); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, + SourceLocation ColonLoc, Stmt *SubStmt); + StmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, Decl *CondVar, - Stmt *ThenVal, - SourceLocation ElseLoc, Stmt *ElseVal); + FullExprArg CondVal, Decl *CondVar, + Stmt *ThenVal, + SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, Decl *CondVar); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, - Decl *CondVar, Stmt *Body); + FullExprArg Cond, + Decl *CondVar, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, @@ -1563,13 +1776,16 @@ public: StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, - IdentifierInfo *LabelII); + LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope); + const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowFunctionParameters); + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); @@ -1606,11 +1822,10 @@ public: Expr *SynchExpr, Stmt *SynchBody); - VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, IdentifierInfo *Name, - SourceLocation Loc, - SourceRange Range); + SourceLocation Loc); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, @@ -1630,18 +1845,31 @@ public: void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedDecl(const NamedDecl *ND); - typedef uintptr_t ParsingDeclStackState; + ParsingDeclState PushParsingDeclaration() { + return DelayedDiagnostics.pushParsingDecl(); + } + void PopParsingDeclaration(ParsingDeclState state, Decl *decl) { + DelayedDiagnostics::popParsingDecl(*this, state, decl); + } + + typedef ProcessingContextState ParsingClassState; + ParsingClassState PushParsingClass() { + return DelayedDiagnostics.pushContext(); + } + void PopParsingClass(ParsingClassState state) { + DelayedDiagnostics.popContext(state); + } - ParsingDeclStackState PushParsingDeclaration(); - void PopParsingDeclaration(ParsingDeclStackState S, Decl *D); - void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); + void EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, + SourceLocation Loc, bool UnknownObjCClass=false); void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. - bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + bool UnknownObjCClass=false); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); @@ -1654,6 +1882,7 @@ public: void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); + void MarkDeclarationsReferencedInExpr(Expr *E); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); // Primary Expressions. @@ -1674,18 +1903,19 @@ public: const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, + ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = 0); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, + ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = 0); - VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, - llvm::SmallVectorImpl<FieldDecl *> &Path); ExprResult - BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - FieldDecl *Field, - Expr *BaseObjectExpr = 0, - SourceLocation OpLoc = SourceLocation()); + BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, + SourceLocation nameLoc, + IndirectFieldDecl *indirectField, + Expr *baseObjectExpr = 0, + SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); @@ -1724,7 +1954,7 @@ public: ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks); // Binary/Unary Operators. 'Tok' is the token for the operator. - ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, unsigned OpcIn, + ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputArg); ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *input); @@ -1740,10 +1970,15 @@ public: ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, void *TyOrEx, const SourceRange &ArgRange); - bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); - bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, - const SourceRange &R, bool isSizeof); + ExprResult CheckPlaceholderExpr(Expr *E, SourceLocation Loc); + bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, + SourceRange R, bool isSizeof); + ExprResult ActOnSizeofParameterPackExpr(Scope *S, + SourceLocation OpLoc, + IdentifierInfo &Name, + SourceLocation NameLoc, + SourceLocation RParenLoc); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); @@ -1803,12 +2038,16 @@ public: /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, - MultiExprArg Args, SourceLocation *CommaLocs, - SourceLocation RParenLoc); + MultiExprArg Args, SourceLocation RParenLoc, + Expr *ExecConfig = 0); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + Expr *ExecConfig = 0); + + ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, @@ -1851,7 +2090,7 @@ public: ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *lhs, Expr *rhs); ExprResult CreateBuiltinBinOp(SourceLocation TokLoc, - unsigned Opc, Expr *lhs, Expr *rhs); + BinaryOperatorKind Opc, Expr *lhs, Expr *rhs); /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. @@ -1860,10 +2099,9 @@ public: Expr *Cond, Expr *LHS, Expr *RHS); /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". - ExprResult ActOnAddrLabel(SourceLocation OpLoc, - SourceLocation LabLoc, - IdentifierInfo *LabelII); - + ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + LabelDecl *LD); + ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc); // "({..})" @@ -1891,16 +2129,6 @@ public: unsigned NumComponents, SourceLocation RParenLoc); - // __builtin_types_compatible_p(type1, type2) - ExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - ParsedType arg1, - ParsedType arg2, - SourceLocation RPLoc); - ExprResult BuildTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeSourceInfo *argTInfo1, - TypeSourceInfo *argTInfo2, - SourceLocation RPLoc); - // __builtin_choose_expr(constExpr, expr1, expr2) ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *cond, Expr *expr1, @@ -1993,6 +2221,8 @@ public: bool IsTypeName, SourceLocation TypenameLoc); + bool CheckInheritedConstructorUsingDecl(UsingDecl *UD); + Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, @@ -2009,8 +2239,8 @@ public: void AddCXXDirectInitializerToDecl(Decl *Dcl, SourceLocation LParenLoc, MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool TypeMayContainAuto); /// InitializeVarWithConstructor - Creates an CXXConstructExpr /// and sets it as the initializer for the the passed in VarDecl. @@ -2025,7 +2255,8 @@ public: ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg Exprs, - bool RequiresZeroInit, unsigned ConstructKind); + bool RequiresZeroInit, unsigned ConstructKind, + SourceRange ParenRange); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? @@ -2033,7 +2264,8 @@ public: BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool RequiresZeroInit, - unsigned ConstructKind); + unsigned ConstructKind, + SourceRange ParenRange); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. @@ -2072,6 +2304,12 @@ public: void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); + /// \brief Declare all inherited constructors for the given class. + /// + /// \param ClassDecl The class declaration into which the inherited + /// constructors will be added. + void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl); + /// \brief Declare the implicit copy constructor for the given class. /// /// \param S The scope of the class, which may be NULL if this is a @@ -2156,8 +2394,29 @@ public: void *TyOrExpr, SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXUuidof - Parse __uuidof( something ). + ExprResult ActOnCXXUuidof(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + //// ActOnCXXThis - Parse 'this' pointer. - ExprResult ActOnCXXThis(SourceLocation ThisLoc); + ExprResult ActOnCXXThis(SourceLocation loc); + + /// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a + /// pointer to an instance method whose 'this' pointer is + /// capturable, or null if this is not possible. + CXXMethodDecl *tryCaptureCXXThis(); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); @@ -2173,11 +2432,14 @@ public: /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). - ExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, - ParsedType TypeRep, + ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc); + + ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, - SourceLocation *CommaLocs, SourceLocation RParenLoc); /// ActOnCXXNew - Parsed a C++ 'new' expression. @@ -2195,12 +2457,12 @@ public: SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, - SourceLocation TypeLoc, - SourceRange TypeRange, + TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen); + SourceLocation ConstructorRParen, + bool TypeMayContainAuto = true); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); @@ -2231,14 +2493,37 @@ public: SourceLocation StmtLoc, bool ConvertToBoolean); + ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, + Expr *Operand, SourceLocation RParen); + ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen); + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation KWLoc, - SourceLocation LParen, ParsedType Ty, SourceLocation RParen); + ExprResult BuildUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + TypeSourceInfo *T, + SourceLocation RParen); + + /// ActOnBinaryTypeTrait - Parsed one of the bianry type trait support + /// pseudo-functions. + ExprResult ActOnBinaryTypeTrait(BinaryTypeTrait OTT, + SourceLocation KWLoc, + ParsedType LhsTy, + ParsedType RhsTy, + SourceLocation RParen); + + ExprResult BuildBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + TypeSourceInfo *LhsT, + TypeSourceInfo *RhsT, + SourceLocation RParen); + ExprResult ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, @@ -2268,14 +2553,15 @@ public: UnqualifiedId &SecondTypeName, bool HasTrailingLParen); - /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is - /// non-empty, will create a new CXXExprWithTemporaries expression. - /// Otherwise, just returs the passed in expression. - Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr); - ExprResult MaybeCreateCXXExprWithTemporaries(ExprResult SubExpr); - FullExpr CreateFullExpr(Expr *SubExpr); + /// MaybeCreateExprWithCleanups - If the current full-expression + /// requires any cleanups, surround it with a ExprWithCleanups node. + /// Otherwise, just returns the passed-in expression. + Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); + Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); + ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); ExprResult ActOnFinishFullExpr(Expr *Expr); + StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); @@ -2373,9 +2659,8 @@ public: Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); - CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, - NamedDecl *FoundDecl, - CXXMethodDecl *Method); + ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXMethodDecl *Method); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, @@ -2423,7 +2708,7 @@ public: Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - Expr *BitfieldWidth, + Expr *BitfieldWidth, const VirtSpecifiers &VS, Expr *Init, bool IsDefinition, bool Deleted = false); @@ -2435,10 +2720,10 @@ public: SourceLocation IdLoc, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + SourceLocation EllipsisLoc); - MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, + MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); @@ -2448,11 +2733,19 @@ public: Expr **Args, unsigned NumArgs, SourceLocation LParenLoc, SourceLocation RParenLoc, - CXXRecordDecl *ClassDecl); - - bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, bool AnyErrors); + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc); + + MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + SourceLocation LParenLoc, + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc); + + bool SetCtorInitializers(CXXConstructorDecl *Constructor, + CXXCtorInitializer **Initializers, + unsigned NumInitializers, bool AnyErrors); void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); @@ -2466,8 +2759,11 @@ public: /// \brief The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. - llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16> - VTableUses; + typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse; + + /// \brief The list of vtables that are required but have not yet been + /// materialized. + llvm::SmallVector<VTableUse, 16> VTableUses; /// \brief The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is @@ -2546,20 +2842,15 @@ public: CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeSourceInfo *TInfo); - - /// SetClassDeclAttributesFromBase - Copies class decl traits - /// (such as whether the class has a trivial constructor, - /// trivial destructor etc) from the given base class. - void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool BaseIsVirtual); + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - ParsedType basetype, SourceLocation - BaseLoc); + ParsedType basetype, + SourceLocation BaseLoc, + SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumBases); @@ -2596,13 +2887,18 @@ public: bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); - /// CheckOverridingFunctionAttributes - Checks whether attributes are - /// incompatible or prevent overriding. - bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, - const CXXMethodDecl *Old); - bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); + /// CheckOverrideControl - Check C++0x override control semantics. + void CheckOverrideControl(const Decl *D); + + /// CheckForFunctionMarkedFinal - Checks whether a virtual member function + /// overrides a virtual member function marked 'final', according to + /// C++0x [class.virtual]p3. + bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + //===--------------------------------------------------------------------===// // C++ Access Control // @@ -2661,6 +2957,10 @@ public: /// A flag to suppress access checking. bool SuppressAccessChecking; + /// \brief When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + void ActOnStartSuppressingAccessChecks(); void ActOnStopSuppressingAccessChecks(); @@ -2732,12 +3032,13 @@ public: Decl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParamsTy *Params, + SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, - const ParsedTemplateArgument &DefaultArg); + ParsedTemplateArgument DefaultArg); TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, @@ -2753,7 +3054,8 @@ public: TPC_ClassTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, - TPC_FriendFunctionTemplate + TPC_FriendFunctionTemplate, + TPC_FriendFunctionTemplateDefinition }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, @@ -2788,10 +3090,11 @@ public: ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); - TypeResult ActOnTagTemplateIdType(TypeResult Type, - TagUseKind TUK, - TypeSpecifierType TagSpec, - SourceLocation TagLoc); + TypeResult ActOnTagTemplateIdType(CXXScopeSpec &SS, + TypeResult Type, + TagUseKind TUK, + TypeSpecifierType TagSpec, + SourceLocation TagLoc); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, LookupResult &R, @@ -2809,11 +3112,6 @@ public: bool EnteringContext, TemplateTy &Template); - bool CheckClassTemplatePartialSpecializationArgs( - TemplateParameterList *TemplateParams, - const TemplateArgumentListBuilder &TemplateArgs, - bool &MirrorsPrimaryTemplate); - DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, @@ -2886,7 +3184,7 @@ public: SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, - TemplateArgumentListBuilder &Converted); + llvm::SmallVectorImpl<TemplateArgument> &Converted); /// \brief Specifies the context in which a particular template /// argument is being checked. @@ -2906,21 +3204,22 @@ public: bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, - TemplateDecl *Template, + NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted, + unsigned ArgumentPackIndex, + llvm::SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - TemplateArgumentListBuilder &Converted); + llvm::SmallVectorImpl<TemplateArgument> &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgumentLoc &Arg, - TemplateArgumentListBuilder &Converted); + llvm::SmallVectorImpl<TemplateArgument> &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); @@ -3034,6 +3333,289 @@ public: const TemplateArgument *Args, unsigned NumArgs); + //===--------------------------------------------------------------------===// + // C++ Variadic Templates (C++0x [temp.variadic]) + //===--------------------------------------------------------------------===// + + /// \brief The context in which an unexpanded parameter pack is + /// being diagnosed. + /// + /// Note that the values of this enumeration line up with the first + /// argument to the \c err_unexpanded_parameter_pack diagnostic. + enum UnexpandedParameterPackContext { + /// \brief An arbitrary expression. + UPPC_Expression = 0, + + /// \brief The base type of a class type. + UPPC_BaseType, + + /// \brief The type of an arbitrary declaration. + UPPC_DeclarationType, + + /// \brief The type of a data member. + UPPC_DataMemberType, + + /// \brief The size of a bit-field. + UPPC_BitFieldWidth, + + /// \brief The expression in a static assertion. + UPPC_StaticAssertExpression, + + /// \brief The fixed underlying type of an enumeration. + UPPC_FixedUnderlyingType, + + /// \brief The enumerator value. + UPPC_EnumeratorValue, + + /// \brief A using declaration. + UPPC_UsingDeclaration, + + /// \brief A friend declaration. + UPPC_FriendDeclaration, + + /// \brief A declaration qualifier. + UPPC_DeclarationQualifier, + + /// \brief An initializer. + UPPC_Initializer, + + /// \brief A default argument. + UPPC_DefaultArgument, + + /// \brief The type of a non-type template parameter. + UPPC_NonTypeTemplateParameterType, + + /// \brief The type of an exception. + UPPC_ExceptionType, + + /// \brief Partial specialization. + UPPC_PartialSpecialization + }; + + /// \brief If the given type contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The source location where a diagnostc should be emitted. + /// + /// \param T The type that is being checked for unexpanded parameter + /// packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given expression contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param E The expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(Expr *E, + UnexpandedParameterPackContext UPPC = UPPC_Expression); + + /// \brief If the given nested-name-specifier contains an unexpanded + /// parameter pack, diagnose the error. + /// + /// \param SS The nested-name-specifier that is being checked for + /// unexpanded parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param NameInfo The name (with source location information) that + /// is being checked for unexpanded parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The location of the template name. + /// + /// \param Template The template name that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template argument contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param Arg The template argument that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, + UnexpandedParameterPackContext UPPC); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgument Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param T The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(QualType T, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param TL The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TypeLoc TL, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Invoked when parsing a template argument followed by an + /// ellipsis, which creates a pack expansion. + /// + /// \param Arg The template argument preceding the ellipsis, which + /// may already be invalid. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing a type followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Type The type preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + QualType CheckPackExpansion(QualType Pattern, + SourceRange PatternRange, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Determine whether we could expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param NumUnexpanded The number of unexpanded parameter packs in + /// \p Unexpanded. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param RetainExpansion Whether the caller should add an unexpanded + /// pack expansion after all of the expanded arguments. This is used + /// when extending explicitly-specified template argument packs per + /// C++0x [temp.arg.explicit]p9. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. This is both an + /// input and an output parameter, which can be set by the caller if the + /// number of expansions is known a priori (e.g., due to a prior substitution) + /// and will be set by the callee when the number of expansions is known. + /// The callee must set this value when \c ShouldExpand is \c true; it may + /// set this value in other cases. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + bool &RetainExpansion, + llvm::Optional<unsigned> &NumExpansions); + + /// \brief Determine the number of arguments in the given pack expansion + /// type. + /// + /// This routine already assumes that the pack expansion type can be + /// expanded and that the number of arguments in the expansion is + /// consistent across all of the unexpanded parameter packs in its pattern. + unsigned getNumArgumentsInExpansion(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Determine whether the given declarator contains any unexpanded + /// parameter packs. + /// + /// This routine is used by the parser to disambiguate function declarators + /// with an ellipsis prior to the ')', e.g., + /// + /// \code + /// void f(T...); + /// \endcode + /// + /// To determine whether we have an (unnamed) function parameter pack or + /// a variadic function. + /// + /// \returns true if the declarator contains any unexpanded parameter packs, + /// false otherwise. + bool containsUnexpandedParameterPacks(Declarator &D); + + //===--------------------------------------------------------------------===// + // C++ Template Argument Deduction (C++ [temp.deduct]) + //===--------------------------------------------------------------------===// + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of @@ -3128,17 +3710,22 @@ public: FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); + bool DeduceAutoType(QualType AutoType, Expr *Initializer, QualType &Result); + FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, - TemplatePartialOrderingContext TPOC); + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag); + const PartialDiagnostic &CandidateDiag, + bool Complain = true); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( @@ -3206,9 +3793,10 @@ public: /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; - /// \brief The template in which we are performing the instantiation, - /// for substitutions of prior template arguments. - TemplateDecl *Template; + /// \brief The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; /// \brief The entity that is being instantiated. uintptr_t Entity; @@ -3220,6 +3808,10 @@ public: /// \brief The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; + /// \brief The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + /// \brief The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. @@ -3227,7 +3819,7 @@ public: ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), - NumTemplateArgs(0) {} + NumTemplateArgs(0), DeductionInfo(0) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. @@ -3278,6 +3870,13 @@ public: llvm::SmallVector<ActiveTemplateInstantiation, 16> ActiveTemplateInstantiations; + /// \brief Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + /// \brief The number of ActiveTemplateInstantiation entries in /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. @@ -3292,12 +3891,49 @@ public: /// to implement it anywhere else. ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + /// \brief The current index into pack expansion arguments that will be + /// used for substitution of parameter packs. + /// + /// The pack expansion index will be -1 to indicate that parameter packs + /// should be instantiated as themselves. Otherwise, the index specifies + /// which argument within the parameter pack will be used for substitution. + int ArgumentPackSubstitutionIndex; + + /// \brief RAII object used to change the argument pack substitution index + /// within a \c Sema object. + /// + /// See \c ArgumentPackSubstitutionIndex for more information. + class ArgumentPackSubstitutionIndexRAII { + Sema &Self; + int OldSubstitutionIndex; + + public: + ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) + : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { + Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; + } + + ~ArgumentPackSubstitutionIndexRAII() { + Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; + } + }; + + friend class ArgumentPackSubstitutionRAII; + /// \brief The stack of calls expression undergoing template instantiation. /// /// The top of this stack is used by a fixit instantiating unresolved /// function calls to fix the AST to match the textual change it prints. llvm::SmallVector<CallExpr *, 8> CallsUndergoingInstantiation; - + + /// \brief For each declaration that involved template argument deduction, the + /// set of diagnostics that were suppressed during that template argument + /// deduction. + /// + /// FIXME: Serialize this structure to the AST file. + llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> > + SuppressedDiagnostics; + /// \brief A stack object to be created when performing template /// instantiation. /// @@ -3331,6 +3967,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template @@ -3340,6 +3977,7 @@ public: ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -3351,14 +3989,14 @@ public: /// \brief Note that we are substituting prior template arguments into a /// non-type or template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, @@ -3386,7 +4024,7 @@ public: private: Sema &SemaRef; bool Invalid; - + bool SavedInNonInstantiationSFINAEContext; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); @@ -3402,21 +4040,39 @@ public: /// template argument substitution failures are not considered /// errors. /// - /// When this routine returns true, the emission of most diagnostics - /// will be suppressed and there will be no local error recovery. - bool isSFINAEContext() const; + /// \returns An empty \c llvm::Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + llvm::Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument - /// deduction. + /// deduction.` class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + public: - explicit SFINAETrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { } + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } - ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + } /// \brief Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { @@ -3424,24 +4080,6 @@ public: } }; - /// \brief RAII class that determines when any errors have occurred - /// between the time the instance was created and the time it was - /// queried. - class ErrorTrap { - Sema &SemaRef; - unsigned PrevErrors; - - public: - explicit ErrorTrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {} - - /// \brief Determine whether any errors have occurred since this - /// object instance was created. - bool hasErrorOccurred() const { - return SemaRef.getDiagnostics().getNumErrors() > PrevErrors; - } - }; - /// \brief The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; @@ -3449,6 +4087,17 @@ public: /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; + typedef llvm::DenseMap<IdentifierInfo *, std::pair<llvm::StringRef, bool> > + UnqualifiedTyposCorrectedMap; + + /// \brief A cache containing the results of typo correction for unqualified + /// name lookup. + /// + /// The string is the string that we corrected to (which may be empty, if + /// there was no correction), while the boolean will be true when the + /// string represents a keyword. + UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected; + /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; @@ -3485,14 +4134,43 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); + TypeSourceInfo *SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, - const MultiLevelTemplateArgumentList &TemplateArgs); + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::Optional<unsigned> NumExpansions); + bool SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<QualType> &ParamTypes, + llvm::SmallVectorImpl<ParmVarDecl *> *OutParams = 0); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Substitute the given template arguments into a list of + /// expressions, expanding pack expansions if required. + /// + /// \param Exprs The list of expressions to substitute into. + /// + /// \param NumExprs The number of expressions in \p Exprs. + /// + /// \param IsCall Whether this is some form of call, in which case + /// default arguments will be dropped. + /// + /// \param TemplateArgs The set of template arguments to substitute. + /// + /// \param Outputs Will receive all of the substituted arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<Expr *> &Outputs); StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -3541,7 +4219,8 @@ public: TemplateName SubstTemplateName(TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); - bool Subst(const TemplateArgumentLoc &Arg, TemplateArgumentLoc &Result, + bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, + TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, @@ -3636,7 +4315,19 @@ public: void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes); - void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); + + /// Process the specified property declaration and create decls for the + /// setters and getters as needed. + /// \param property The property declaration being processed + /// \param DC The semantic container for the property + /// \param redeclaredProperty Declaration for property if redeclared + /// in class extension. + /// \param lexicalDC Container for redeclaredProperty. + void ProcessPropertyDecl(ObjCPropertyDecl *property, + ObjCContainerDecl *DC, + ObjCPropertyDecl *redeclaredProperty = 0, + ObjCContainerDecl *lexicalDC = 0); + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name); @@ -3664,14 +4355,16 @@ public: Selector GetterSel, Selector SetterSel, Decl *ClassCategory, bool *OverridingProperty, - tok::ObjCKeywordKind MethodImplKind); + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind,Decl *ClassImplDecl, IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar); + IdentifierInfo *PropertyIvar, + SourceLocation PropertyIvarLoc); struct ObjCArgInfo { IdentifierInfo *Name; @@ -3686,6 +4379,7 @@ public: }; Decl *ActOnMethodDeclaration( + Scope *S, SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. tok::TokenKind MethodType, @@ -3711,7 +4405,9 @@ public: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, DeclarationName MemberName, - SourceLocation MemberLoc); + SourceLocation MemberLoc, + SourceLocation SuperLoc, QualType SuperType, + bool Super); ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, @@ -3719,6 +4415,8 @@ public: SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); + ObjCMethodDecl *tryCaptureObjCSelf(); + /// \brief Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { @@ -3751,6 +4449,7 @@ public: Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, + SourceLocation SelectorLoc, SourceLocation RBracLoc, MultiExprArg Args); @@ -3768,6 +4467,7 @@ public: Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, + SourceLocation SelectorLoc, SourceLocation RBracLoc, MultiExprArg Args); @@ -3810,11 +4510,9 @@ public: SourceLocation RParenLoc); /// ActOnPragmaUnused - Called on well-formed '#pragma unused'. - void ActOnPragmaUnused(const Token *Identifiers, - unsigned NumIdentifiers, Scope *curScope, - SourceLocation PragmaLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); + void ActOnPragmaUnused(const Token &Identifier, + Scope *curScope, + SourceLocation PragmaLoc); /// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... . void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType, @@ -3835,6 +4533,10 @@ public: SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); + /// ActOnPragmaFPContract - Called on well formed + /// #pragma {STDC,OPENCL} FP_CONTRACT + void ActOnPragmaFPContract(tok::OnOffSwitch OOS); + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '#pragma pack' and '#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); @@ -3842,9 +4544,9 @@ public: /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); - /// PushVisibilityAttr - Note that we've entered a context with a - /// visibility attribute. - void PushVisibilityAttr(const VisibilityAttr *Attr); + /// PushNamespaceVisibilityAttr - Note that we've entered a + /// namespace with a visibility attribute. + void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr); /// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used, /// add an appropriate visibility attribute. @@ -3872,6 +4574,11 @@ public: ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = 0); + /// IgnoredValueConversions - Given that an expression's result is + /// syntactically ignored, perform any conversions that are + /// required. + void IgnoredValueConversions(Expr *&expr); + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). Expr *UsualUnaryConversions(Expr *&expr); @@ -3885,6 +4592,12 @@ public: // lvalue-to-rvalue conversion. void DefaultFunctionArrayLvalueConversion(Expr *&expr); + // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on + // the operand. This is DefaultFunctionArrayLvalueConversion, + // except that it assumes the operand isn't of function or array + // type. + void DefaultLvalueConversion(Expr *&expr); + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. @@ -3957,6 +4670,11 @@ public: /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an @@ -3996,8 +4714,14 @@ public: /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. - /// This routine is only used by the following two methods. C99 6.5.16. - AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); + /// C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, + QualType lhs, QualType rhs); + + /// Check assignment constraints and prepare for a conversion of the + /// RHS to the LHS type. + AssignConvertType CheckAssignmentConstraints(QualType lhs, Expr *&rhs, + CastKind &Kind); // CheckSingleAssignmentConstraints - Currently used by // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, @@ -4010,18 +4734,6 @@ public: AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs, Expr *&rExpr); - // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) - AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - AssignConvertType CheckObjCPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - // Helper function for CheckAssignmentConstraints involving two - // block pointer types. - AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); @@ -4036,10 +4748,11 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, - bool IgnoreBaseAccess = false); + bool CStyle = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action,bool IgnoreBaseAccess); + AssignmentAction Action, + bool CStyle); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -4047,7 +4760,8 @@ public: /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); QualType CheckPointerToMemberOperands( // C++ 5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); + Expr *&lex, Expr *&rex, ExprValueKind &VK, + SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign, bool isDivide); @@ -4071,36 +4785,30 @@ public: // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); - QualType CheckCommaOperands( // C99 6.5.17 - Expr *lex, Expr *&rex, SourceLocation OpLoc); + + void ConvertPropertyForRValue(Expr *&E); + void ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType& LHSTy); + QualType CheckConditionalOperands( // C99 6.5.15 - Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); + Expr *&cond, Expr *&lhs, Expr *&rhs, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 - Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); + Expr *&cond, Expr *&lhs, Expr *&rhs, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType = 0); QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation questionLoc); + bool DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, + SourceLocation QuestionLoc); + /// type checking for vector binary operators. QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, SourceLocation l, bool isRel); - /// type checking unary operators (subroutines of ActOnUnaryOp). - /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 - QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, - bool isInc, bool isPrefix); - QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); - QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); - QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); - - /// type checking primary expressions. - QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - const IdentifierInfo *Comp, - SourceLocation CmpLoc); - /// type checking declaration initializers (C99 6.7.8) bool CheckInitList(const InitializedEntity &Entity, InitListExpr *&InitList, QualType &DeclType); @@ -4137,7 +4845,7 @@ public: /// CheckCastTypes - Check type constraints for casting between types under /// C semantics, or forward to CXXCheckCStyleCast in C++. bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr, - CastKind &Kind, CXXCastPath &BasePath, + CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath, bool FunctionalStyle = false); // CheckVectorCast - check type constraints for vectors. @@ -4157,9 +4865,9 @@ public: /// CXXCheckCStyleCast - Check constraints of a C-style or function-style /// cast under C++ semantics. - bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastKind &Kind, CXXCastPath &BasePath, - bool FunctionalStyle); + bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, + Expr *&CastExpr, CastKind &Kind, + CXXCastPath &BasePath, bool FunctionalStyle); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. @@ -4168,7 +4876,7 @@ public: bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, SourceLocation lbrac, SourceLocation rbrac, - QualType &ReturnType); + QualType &ReturnType, ExprValueKind &VK); /// CheckBooleanCondition - Diagnose problems involving the use of /// the given expression as a boolean condition (e.g. in an if @@ -4187,6 +4895,10 @@ public: /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); + /// \brief Redundant parentheses over an equality comparison can indicate + /// that the user intended an assignment used as condition. + void DiagnoseEqualityWithExtraParens(ParenExpr *parenE); + /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. bool CheckCXXBooleanCondition(Expr *&CondExpr); @@ -4202,8 +4914,6 @@ public: /// in the global scope. bool CheckObjCDeclScope(Decl *D); - void InitBuiltinVaListType(); - /// VerifyIntegerConstantExpression - verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. @@ -4256,14 +4966,20 @@ public: /// in the grammar. PCC_RecoveryInFunction, /// \brief Code completion occurs where only a type is permitted. - PCC_Type + PCC_Type, + /// \brief Code completion occurs in a parenthesized expression, which + /// might also be a type cast. + PCC_ParenthesizedExpression, + /// \brief Code completion occurs within a sequence of declaration + /// specifiers within a function, method, or block. + PCC_LocalDeclarationSpecifiers }; void CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext); - void CodeCompleteDeclarator(Scope *S, - bool AllowNonIdentifiers, - bool AllowNestedNameSpecifiers); + void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers); struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, @@ -4271,6 +4987,7 @@ public: void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool IsArrow); + void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteCase(Scope *S); @@ -4287,7 +5004,7 @@ public: void CodeCompleteNamespaceAliasDecl(Scope *S); void CodeCompleteOperatorName(Scope *S); void CodeCompleteConstructorInitializer(Decl *Constructor, - CXXBaseOrMemberInitializer** Initializers, + CXXCtorInitializer** Initializers, unsigned NumInitializers); void CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, @@ -4296,31 +5013,25 @@ public: void CodeCompleteObjCAtStatement(Scope *S); void CodeCompleteObjCAtExpression(Scope *S); void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); - void CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl, - Decl **Methods, - unsigned NumMethods); - void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl, - Decl **Methods, - unsigned NumMethods); - void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS); + void CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl); + void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl); + void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, + bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, IdentifierInfo **SelIdents, - unsigned NumSelIdents); - void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents); + unsigned NumSelIdents, + bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents, - bool IsSuper); + bool AtArgumentExpression, + bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, - unsigned NumSelIdents); - void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents, - bool IsSuper); + unsigned NumSelIdents, + bool AtArgumentExpression, + ObjCInterfaceDecl *Super = 0); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, @@ -4363,7 +5074,7 @@ public: MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteNaturalLanguage(); - void GatherGlobalCodeCompletions( + void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, llvm::SmallVectorImpl<CodeCompletionResult> &Results); //@} @@ -4376,7 +5087,8 @@ public: SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; -private: +private: + void CheckArrayAccess(const ArraySubscriptExpr *E); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); @@ -4385,7 +5097,6 @@ private: ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); @@ -4422,7 +5133,10 @@ private: void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); - void CheckImplicitConversions(Expr *E); + void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); + + void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, + Expr *Init); /// \brief The parser's current scope. /// @@ -4431,6 +5145,7 @@ private: protected: friend class Parser; + friend class InitializationSequence; /// \brief Retrieve the parser's current scope. Scope *getCurScope() const { return CurScope; } diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h index a5a136427fb9..ae5aa33db766 100644 --- a/include/clang/Sema/SemaDiagnostic.h +++ b/include/clang/Sema/SemaDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM, #define SEMASTART #include "clang/Basic/DiagnosticSemaKinds.inc" #undef DIAG diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index a7b3b8461854..53f4a9d8c8fa 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -13,8 +13,10 @@ #define LLVM_CLANG_SEMA_TEMPLATE_H #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" #include "llvm/ADT/SmallVector.h" #include <cassert> +#include <utility> namespace clang { /// \brief Data structure that captures multiple levels of template argument @@ -79,12 +81,21 @@ namespace clang { return !(*this)(Depth, Index).isNull(); } + /// \brief Clear out a specific template argument. + void setArgument(unsigned Depth, unsigned Index, + TemplateArgument Arg) { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second); + const_cast<TemplateArgument&>( + TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index]) + = Arg; + } + /// \brief Add a new outermost level to the multi-level template argument /// list. void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { - TemplateArgumentLists.push_back( - ArgList(TemplateArgs->getFlatArgumentList(), - TemplateArgs->flat_size())); + TemplateArgumentLists.push_back(ArgList(TemplateArgs->data(), + TemplateArgs->size())); } /// \brief Add a new outmost level to the multi-level template argument @@ -140,7 +151,7 @@ namespace clang { : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } /// \brief Construct an integral non-type template argument that - /// has been deduced, possible from an array bound. + /// has been deduced, possibly from an array bound. DeducedTemplateArgument(const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound) @@ -165,10 +176,19 @@ namespace clang { /// instantiate a new function declaration, which will have its own /// set of parameter declarations. class LocalInstantiationScope { + public: + /// \brief A set of declarations. + typedef llvm::SmallVector<Decl *, 4> DeclArgumentPack; + + private: /// \brief Reference to the semantic analysis that is performing /// this template instantiation. Sema &SemaRef; + typedef llvm::DenseMap<const Decl *, + llvm::PointerUnion<Decl *, DeclArgumentPack *> > + LocalDeclsMap; + /// \brief A mapping from local declarations that occur /// within a template to their instantiations. /// @@ -183,8 +203,15 @@ namespace clang { /// when we instantiate add<int>, we will introduce a mapping from /// the ParmVarDecl for 'x' that occurs in the template to the /// instantiated ParmVarDecl for 'x'. - llvm::DenseMap<const Decl *, Decl *> LocalDecls; + /// + /// For a parameter pack, the local instantiation scope may contain a + /// set of instantiated parameters. This is stored as a DeclArgumentPack + /// pointer. + LocalDeclsMap LocalDecls; + /// \brief The set of argument packs we've allocated. + llvm::SmallVector<DeclArgumentPack *, 1> ArgumentPacks; + /// \brief The outer scope, which contains local variable /// definitions from some other instantiation (that may not be /// relevant to this particular scope). @@ -197,6 +224,19 @@ namespace clang { /// lookup will search our outer scope. bool CombineWithOuterScope; + /// \brief If non-NULL, the template parameter pack that has been + /// partially substituted per C++0x [temp.arg.explicit]p9. + NamedDecl *PartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack is non-null, the set of + /// explicitly-specified template arguments in that pack. + const TemplateArgument *ArgsInPartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack, the number of + /// explicitly-specified template arguments in + /// ArgsInPartiallySubstitutedPack. + unsigned NumArgsInPartiallySubstitutedPack; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); @@ -204,7 +244,8 @@ namespace clang { public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false), CombineWithOuterScope(CombineWithOuterScope) + Exited(false), CombineWithOuterScope(CombineWithOuterScope), + PartiallySubstitutedPack(0) { SemaRef.CurrentInstantiationScope = this; } @@ -212,33 +253,171 @@ namespace clang { ~LocalInstantiationScope() { Exit(); } + + const Sema &getSema() const { return SemaRef; } /// \brief Exit this local instantiation scope early. void Exit() { if (Exited) return; + for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) + delete ArgumentPacks[I]; + SemaRef.CurrentInstantiationScope = Outer; Exited = true; } - Decl *getInstantiationOf(const Decl *D); + /// \brief Find the instantiation of the declaration D within the current + /// instantiation scope. + /// + /// \param D The declaration whose instantiation we are searching for. + /// + /// \returns A pointer to the declaration or argument pack of declarations + /// to which the declaration \c D is instantiataed, if found. Otherwise, + /// returns NULL. + llvm::PointerUnion<Decl *, DeclArgumentPack *> * + findInstantiationOf(const Decl *D); + + void InstantiatedLocal(const Decl *D, Decl *Inst); + void InstantiatedLocalPackArg(const Decl *D, Decl *Inst); + void MakeInstantiatedLocalArgPack(const Decl *D); + + /// \brief Note that the given parameter pack has been partially substituted + /// via explicit specification of template arguments + /// (C++0x [temp.arg.explicit]p9). + /// + /// \param Pack The parameter pack, which will always be a template + /// parameter pack. + /// + /// \param ExplicitArgs The explicitly-specified template arguments provided + /// for this parameter pack. + /// + /// \param NumExplicitArgs The number of explicitly-specified template + /// arguments provided for this parameter pack. + void SetPartiallySubstitutedPack(NamedDecl *Pack, + const TemplateArgument *ExplicitArgs, + unsigned NumExplicitArgs); + + /// \brief Retrieve the partially-substitued template parameter pack. + /// + /// If there is no partially-substituted parameter pack, returns NULL. + NamedDecl *getPartiallySubstitutedPack( + const TemplateArgument **ExplicitArgs = 0, + unsigned *NumExplicitArgs = 0) const; + }; + + class TemplateDeclInstantiator + : public DeclVisitor<TemplateDeclInstantiator, Decl *> + { + Sema &SemaRef; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; + DeclContext *Owner; + const MultiLevelTemplateArgumentList &TemplateArgs; - VarDecl *getInstantiationOf(const VarDecl *Var) { - return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var))); + /// \brief A list of out-of-line class template partial + /// specializations that will need to be instantiated after the + /// enclosing class's instantiation is complete. + llvm::SmallVector<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>, 4> + OutOfLinePartialSpecs; + + public: + TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner), + TemplateArgs(TemplateArgs) { } + + // FIXME: Once we get closer to completion, replace these manually-written + // declarations with automatically-generated ones from + // clang/AST/DeclNodes.inc. + Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); + Decl *VisitLabelDecl(LabelDecl *D); + Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitAccessSpecDecl(AccessSpecDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); + Decl *VisitStaticAssertDecl(StaticAssertDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFriendDecl(FriendDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams = 0); + Decl *VisitCXXRecordDecl(CXXRecordDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams = 0); + Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); + Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); + Decl *VisitCXXConversionDecl(CXXConversionDecl *D); + ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); + Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + + // Base case. FIXME: Remove once we can instantiate everything. + Decl *VisitDecl(Decl *D) { + unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID( + Diagnostic::Error, + "cannot instantiate %0 yet"); + SemaRef.Diag(D->getLocation(), DiagID) + << D->getDeclKindName(); + + return 0; } + + typedef + llvm::SmallVectorImpl<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> > + ::iterator + delayed_partial_spec_iterator; - ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { - return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); + /// \brief Return an iterator to the beginning of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_begin() { + return OutOfLinePartialSpecs.begin(); } - NonTypeTemplateParmDecl *getInstantiationOf( - const NonTypeTemplateParmDecl *Var) { - return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); + /// \brief Return an iterator to the end of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_end() { + return OutOfLinePartialSpecs.end(); } - void InstantiatedLocal(const Decl *D, Decl *Inst); - }; + // Helper functions for instantiating methods. + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl<ParmVarDecl *> &Params); + bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); + bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); + + ClassTemplatePartialSpecializationDecl * + InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); + }; } #endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h index ac32e9c24f6d..7cc35713aace 100644 --- a/include/clang/Sema/TemplateDeduction.h +++ b/include/clang/Sema/TemplateDeduction.h @@ -13,7 +13,9 @@ #ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H #define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H +#include "clang/Basic/PartialDiagnostic.h" #include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/SmallVector.h" namespace clang { @@ -21,7 +23,7 @@ class ASTContext; class TemplateArgumentList; namespace sema { - + /// \brief Provides information about an attempted template argument /// deduction, whose success or failure was described by a /// TemplateDeductionResult value. @@ -37,6 +39,10 @@ class TemplateDeductionInfo { /// deduction is occurring. SourceLocation Loc; + /// \brief Warnings (and follow-on notes) that were suppressed due to + /// SFINAE while performing template argument deduction. + llvm::SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics; + // do not implement these TemplateDeductionInfo(const TemplateDeductionInfo&); TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); @@ -69,6 +75,23 @@ public: Deduced = NewDeduced; } + /// \brief Add a new diagnostic to the set of diagnostics + void addSuppressedDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) { + SuppressedDiagnostics.push_back(std::make_pair(Loc, PD)); + } + + /// \brief Iterator over the set of suppressed diagnostics. + typedef llvm::SmallVectorImpl<PartialDiagnosticAt>::const_iterator + diag_iterator; + + /// \brief Returns an iterator at the beginning of the sequence of suppressed + /// diagnostics. + diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } + + /// \brief Returns an iterator at the end of the sequence of suppressed + /// diagnostics. + diag_iterator diag_end() const { return SuppressedDiagnostics.end(); } + /// \brief The template parameter to which a template argument /// deduction failure refers. /// diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 0fa446dd34de..68fd91d4c069 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -19,7 +19,7 @@ #include "clang/AST/Type.h" #include "llvm/Bitcode/BitCodes.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" namespace clang { @@ -54,6 +54,9 @@ namespace clang { /// reserved for the translation unit declaration. typedef uint32_t DeclID; + /// \brief a Decl::Kind/DeclID pair. + typedef std::pair<uint32_t, DeclID> KindDeclIDPair; + /// \brief An ID number that refers to a type in an AST file. /// /// The ID of a type is partitioned into two parts: the lower @@ -112,12 +115,19 @@ namespace clang { typedef llvm::DenseMap<QualType, TypeIdx, UnsafeQualTypeDenseMapInfo> TypeIdxMap; - /// \brief An ID number that refers to an identifier in an AST - /// file. + /// \brief An ID number that refers to an identifier in an AST file. typedef uint32_t IdentID; + /// \brief An ID number that refers to a macro in an AST file. + typedef uint32_t MacroID; + + /// \brief An ID number that refers to an ObjC selctor in an AST file. typedef uint32_t SelectorID; + /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an + /// AST file. + typedef uint32_t CXXBaseSpecifiersID; + /// \brief Describes the various kinds of blocks that occur within /// an AST file. enum BlockIDs { @@ -135,7 +145,13 @@ namespace clang { /// \brief The block containing the definitions of all of the /// types and decls used within the AST file. - DECLTYPES_BLOCK_ID + DECLTYPES_BLOCK_ID, + + /// \brief The block containing DECL_UPDATES records. + DECL_UPDATES_BLOCK_ID, + + /// \brief The block containing the detailed preprocessing record. + PREPROCESSOR_DETAIL_BLOCK_ID }; /// \brief Record types that occur within the AST block itself. @@ -318,9 +334,35 @@ namespace clang { /// In practice, this should only be used for the TU and namespaces. UPDATE_VISIBLE = 34, - /// \brief Record code for template specializations introduced after - /// serializations of the original template decl. - ADDITIONAL_TEMPLATE_SPECIALIZATIONS = 35 + /// \brief Record for offsets of DECL_UPDATES records for declarations + /// that were modified after being deserialized and need updates. + DECL_UPDATE_OFFSETS = 35, + + /// \brief Record of updates for a declaration that was modified after + /// being deserialized. + DECL_UPDATES = 36, + + /// \brief Record code for the table of offsets to CXXBaseSpecifier + /// sets. + CXX_BASE_SPECIFIER_OFFSETS = 37, + + /// \brief Record code for #pragma diagnostic mappings. + DIAG_PRAGMA_MAPPINGS = 38, + + /// \brief Record code for special CUDA declarations. + CUDA_SPECIAL_DECL_REFS = 39, + + /// \brief Record code for header search information. + HEADER_SEARCH_TABLE = 40, + + /// \brief The directory that the PCH was originally created in. + ORIGINAL_PCH_DIR = 41, + + /// \brief Record code for floating point #pragma options. + FP_PRAGMA_OPTIONS = 42, + + /// \brief Record code for enabled OpenCL extensions. + OPENCL_EXTENSIONS = 43 }; /// \brief Record types used within a source manager block. @@ -359,16 +401,23 @@ namespace clang { /// \brief Describes one token. /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] - PP_TOKEN = 3, + PP_TOKEN = 3 + }; + /// \brief Record types used within a preprocessor detail block. + enum PreprocessorDetailRecordTypes { /// \brief Describes a macro instantiation within the preprocessing /// record. - PP_MACRO_INSTANTIATION = 4, + PPD_MACRO_INSTANTIATION = 0, /// \brief Describes a macro definition within the preprocessing record. - PP_MACRO_DEFINITION = 5 + PPD_MACRO_DEFINITION = 1, + + /// \brief Describes an inclusion directive within the preprocessing + /// record. + PPD_INCLUSION_DIRECTIVE = 2 }; - + /// \defgroup ASTAST AST file AST constants /// /// The constants in this group describe various components of the @@ -521,7 +570,17 @@ namespace clang { /// \brief A DependentTemplateSpecializationType record. TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, /// \brief A DependentSizedArrayType record. - TYPE_DEPENDENT_SIZED_ARRAY = 33 + TYPE_DEPENDENT_SIZED_ARRAY = 33, + /// \brief A ParenType record. + TYPE_PAREN = 34, + /// \brief A PackExpansionType record. + TYPE_PACK_EXPANSION = 35, + /// \brief An AttributedType record. + TYPE_ATTRIBUTED = 36, + /// \brief A SubstTemplateTypeParmPackType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, + /// \brief A AutoType record. + TYPE_AUTO = 38 }; /// \brief The type IDs for special types constructed by semantic @@ -573,10 +632,8 @@ namespace clang { /// constant describes a record for a specific declaration class /// in the AST. enum DeclCode { - /// \brief Attributes attached to a declaration. - DECL_ATTR = 50, /// \brief A TranslationUnitDecl record. - DECL_TRANSLATION_UNIT, + DECL_TRANSLATION_UNIT = 50, /// \brief A TypedefDecl record. DECL_TYPEDEF, /// \brief An EnumDecl record. @@ -642,7 +699,9 @@ namespace clang { /// IDs. This data is used when performing qualified name lookup /// into a DeclContext via DeclContext::lookup. DECL_CONTEXT_VISIBLE, - /// \brief A NamespaceDecl rcord. + /// \brief A LabelDecl record. + DECL_LABEL, + /// \brief A NamespaceDecl record. DECL_NAMESPACE, /// \brief A NamespaceAliasDecl record. DECL_NAMESPACE_ALIAS, @@ -690,7 +749,14 @@ namespace clang { /// \brief A TemplateTemplateParmDecl record. DECL_TEMPLATE_TEMPLATE_PARM, /// \brief A StaticAssertDecl record. - DECL_STATIC_ASSERT + DECL_STATIC_ASSERT, + /// \brief A record containing CXXBaseSpecifiers. + DECL_CXX_BASE_SPECIFIERS, + /// \brief A IndirectFieldDecl record. + DECL_INDIRECTFIELD, + /// \brief A NonTypeTemplateParmDecl record that stores an expanded + /// non-type template parameter pack. + DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK }; /// \brief Record codes for each kind of statement or expression. @@ -796,8 +862,6 @@ namespace clang { EXPR_ADDR_LABEL, /// \brief A StmtExpr record. EXPR_STMT, - /// \brief A TypesCompatibleExpr record. - EXPR_TYPES_COMPATIBLE, /// \brief A ChooseExpr record. EXPR_CHOOSE, /// \brief A GNUNullExpr record. @@ -823,12 +887,10 @@ namespace clang { EXPR_OBJC_IVAR_REF_EXPR, /// \brief An ObjCPropertyRefExpr record. EXPR_OBJC_PROPERTY_REF_EXPR, - /// \brief An ObjCImplicitSetterGetterRefExpr record. + /// \brief UNUSED 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, @@ -875,6 +937,8 @@ namespace clang { EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). EXPR_CXX_THIS, // CXXThisExpr EXPR_CXX_THROW, // CXXThrowExpr EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr @@ -885,15 +949,28 @@ namespace clang { EXPR_CXX_DELETE, // CXXDeleteExpr EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr - EXPR_CXX_EXPR_WITH_TEMPORARIES, // CXXExprWithTemporaries + EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups - EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr - EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr - EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr - EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr - EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr + EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr + EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr + EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr + EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr + EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr + + EXPR_CXX_UNARY_TYPE_TRAIT, // UnaryTypeTraitExpr + EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr + + EXPR_OPAQUE_VALUE, // OpaqueValueExpr + EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator + EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr + + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr + + // CUDA - EXPR_CXX_UNARY_TYPE_TRAIT // UnaryTypeTraitExpr + EXPR_CUDA_KERNEL_CALL // CUDAKernelCallExpr }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h index f8114de5f15a..f8cdebe5a913 100644 --- a/include/clang/Serialization/ASTDeserializationListener.h +++ b/include/clang/Serialization/ASTDeserializationListener.h @@ -22,26 +22,31 @@ namespace clang { class Decl; class ASTReader; class QualType; - +class MacroDefinition; + class ASTDeserializationListener { protected: - virtual ~ASTDeserializationListener() {} + virtual ~ASTDeserializationListener(); public: - /// \brief Tell the listener about the reader. - virtual void SetReader(ASTReader *Reader) = 0; + + /// \brief The ASTReader was initialized. + virtual void ReaderInitialized(ASTReader *Reader) { } /// \brief An identifier was deserialized from the AST file. virtual void IdentifierRead(serialization::IdentID ID, - IdentifierInfo *II) = 0; + IdentifierInfo *II) { } /// \brief A type was deserialized from the AST file. The ID here has the /// qualifier bits already removed, and T is guaranteed to be locally /// unqualified. - virtual void TypeRead(serialization::TypeIdx Idx, QualType T) = 0; + virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } /// \brief A decl was deserialized from the AST file. - virtual void DeclRead(serialization::DeclID ID, const Decl *D) = 0; + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { } /// \brief A selector was read from the AST file. - virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) = 0; + virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) { } + /// \brief A macro definition was read from the AST file. + virtual void MacroDefinitionRead(serialization::MacroID, + MacroDefinition *MD) { } }; } diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index d31be88a3e3d..9799b8d852c2 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -20,6 +20,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/TemplateBase.h" #include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" @@ -31,7 +32,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <deque> #include <map> #include <string> @@ -47,22 +48,26 @@ namespace clang { class AddrLabelExpr; class ASTConsumer; class ASTContext; +class ASTIdentifierIterator; class Attr; class Decl; class DeclContext; class NestedNameSpecifier; class CXXBaseSpecifier; -class CXXBaseOrMemberInitializer; +class CXXCtorInitializer; class GotoStmt; -class LabelStmt; class MacroDefinition; class NamedDecl; -class ASTDeserializationListener; +class OpaqueValueExpr; class Preprocessor; class Sema; class SwitchCase; +class ASTDeserializationListener; class ASTReader; class ASTDeclReader; +class ASTStmtReader; +class ASTIdentifierLookupTrait; +class TypeLocReader; struct HeaderFileInfo; struct PCHPredefinesBlock { @@ -161,14 +166,27 @@ private: class ASTReader : public ExternalPreprocessorSource, public ExternalPreprocessingRecordSource, + public ExternalHeaderFileInfoSource, public ExternalSemaSource, public IdentifierInfoLookup, public ExternalIdentifierLookup, - public ExternalSLocEntrySource { + public ExternalSLocEntrySource +{ public: enum ASTReadResult { Success, Failure, IgnorePCH }; + /// \brief Types of AST files. + enum ASTFileType { + Module, ///< File is a module proper. + PCH, ///< File is a PCH file treated as such. + Preamble, ///< File is a PCH file treated as the preamble. + MainFile ///< File is a PCH file treated as the actual main file. + }; friend class PCHValidator; friend class ASTDeclReader; + friend class ASTStmtReader; + friend class ASTIdentifierIterator; + friend class ASTIdentifierLookupTrait; + friend class TypeLocReader; private: /// \brief The receiver of some callbacks invoked by ASTReader. llvm::OwningPtr<ASTReaderListener> Listener; @@ -193,31 +211,15 @@ private: /// \brief The AST consumer. ASTConsumer *Consumer; - /// \brief Information that is needed for every file in the chain. + /// \brief Information that is needed for every module. struct PerFileData { - PerFileData(); + PerFileData(ASTFileType Ty); ~PerFileData(); - /// \brief The AST stat cache installed for this file, if any. - /// - /// The dynamic type of this stat cache is always ASTStatCache - void *StatCache; - - /// \brief The bitstream reader from which we'll read the AST file. - llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; - - /// \brief The size of this file, in bits. - uint64_t SizeInBits; + // === General information === - /// \brief The cursor to the start of the preprocessor block, which stores - /// all of the macro definitions. - llvm::BitstreamCursor MacroCursor; - - /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It - /// has read all the abbreviations at the start of the block and is ready to - /// jump around with these in context. - llvm::BitstreamCursor DeclsCursor; + /// \brief The type of this AST file. + ASTFileType Type; /// \brief The file name of the AST file. std::string FileName; @@ -226,6 +228,17 @@ private: /// this AST file. llvm::OwningPtr<llvm::MemoryBuffer> Buffer; + /// \brief The size of this file, in bits. + uint64_t SizeInBits; + + /// \brief The bitstream reader from which we'll read the AST file. + llvm::BitstreamReader StreamFile; + + /// \brief The main bitstream cursor for the main block. + llvm::BitstreamCursor Stream; + + // === Source Locations === + /// \brief Cursor used to read source location entries. llvm::BitstreamCursor SLocEntryCursor; @@ -236,19 +249,10 @@ private: /// AST file. const uint32_t *SLocOffsets; - /// \brief The number of types in this AST file. - unsigned LocalNumTypes; - - /// \brief Offset of each type within the bitstream, indexed by the - /// type ID, or the representation of a Type*. - const uint32_t *TypeOffsets; - - /// \brief The number of declarations in this AST file. - unsigned LocalNumDecls; + /// \brief The entire size of this module's source location offset range. + unsigned LocalSLocSize; - /// \brief Offset of each declaration within the bitstream, indexed - /// by the declaration ID (-1). - const uint32_t *DeclOffsets; + // === Identifiers === /// \brief The number of identifiers in this AST file. unsigned LocalNumIdentifiers; @@ -260,26 +264,72 @@ private: /// stored. const uint32_t *IdentifierOffsets; - /// \brief Actual data for the on-disk hash table. + /// \brief Actual data for the on-disk hash table of identifiers. /// - // This pointer points into a memory buffer, where the on-disk hash - // table for identifiers actually lives. + /// This pointer points into a memory buffer, where the on-disk hash + /// table for identifiers actually lives. const char *IdentifierTableData; /// \brief A pointer to an on-disk hash table of opaque type /// IdentifierHashTable. void *IdentifierLookupTable; + // === Macros === + + /// \brief The cursor to the start of the preprocessor block, which stores + /// all of the macro definitions. + llvm::BitstreamCursor MacroCursor; + + /// \brief The offset of the start of the set of defined macros. + uint64_t MacroStartOffset; + + // === Detailed PreprocessingRecord === + + /// \brief The cursor to the start of the (optional) detailed preprocessing + /// record block. + llvm::BitstreamCursor PreprocessorDetailCursor; + + /// \brief The offset of the start of the preprocessor detail cursor. + uint64_t PreprocessorDetailStartOffset; + /// \brief The number of macro definitions in this file. unsigned LocalNumMacroDefinitions; - + /// \brief Offsets of all of the macro definitions in the preprocessing /// record in the AST file. const uint32_t *MacroDefinitionOffsets; - - /// \brief The number of preallocated preprocessing entities in the - /// preprocessing record. - unsigned NumPreallocatedPreprocessingEntities; + + // === Header search information === + + /// \brief The number of local HeaderFileInfo structures. + unsigned LocalNumHeaderFileInfos; + + /// \brief Actual data for the on-disk hash table of header file + /// information. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for header file information actually lives. + const char *HeaderFileInfoTableData; + + /// \brief The on-disk hash table that contains information about each of + /// the header files. + void *HeaderFileInfoTable; + + // === Selectors === + + /// \brief The number of selectors new to this file. + /// + /// This is the number of entries in SelectorOffsets. + unsigned LocalNumSelectors; + + /// \brief Offsets into the selector lookup table's data array + /// where each selector resides. + const uint32_t *SelectorOffsets; + + /// \brief A pointer to the character data that comprises the selector table + /// + /// The SelectorOffsets table refers into this memory. + const unsigned char *SelectorLookupTableData; /// \brief A pointer to an on-disk hash table of opaque type /// ASTSelectorLookupTable. @@ -288,26 +338,81 @@ private: /// instance and factory methods. void *SelectorLookupTable; - /// \brief A pointer to the character data that comprises the selector table + /// \brief Method selectors used in a @selector expression. Used for + /// implementation of -Wselector. + llvm::SmallVector<uint64_t, 64> ReferencedSelectorsData; + + // === Declarations === + + /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It + /// has read all the abbreviations at the start of the block and is ready to + /// jump around with these in context. + llvm::BitstreamCursor DeclsCursor; + + /// \brief The number of declarations in this AST file. + unsigned LocalNumDecls; + + /// \brief Offset of each declaration within the bitstream, indexed + /// by the declaration ID (-1). + const uint32_t *DeclOffsets; + + /// \brief A snapshot of the pending instantiations in the chain. /// - /// The SelectorOffsets table refers into this memory. - const unsigned char *SelectorLookupTableData; + /// This record tracks the instantiations that Sema has to perform at the + /// end of the TU. It consists of a pair of values for every pending + /// instantiation where the first value is the ID of the decl and the second + /// is the instantiation location. + llvm::SmallVector<uint64_t, 64> PendingInstantiations; + + /// \brief The number of C++ base specifier sets in this AST file. + unsigned LocalNumCXXBaseSpecifiers; + + /// \brief Offset of each C++ base specifier set within the bitstream, + /// indexed by the C++ base specifier set ID (-1). + const uint32_t *CXXBaseSpecifiersOffsets; + + // === Types === - /// \brief Offsets into the method pool lookup table's data array - /// where each selector resides. - const uint32_t *SelectorOffsets; + /// \brief The number of types in this AST file. + unsigned LocalNumTypes; - /// \brief The number of selectors new to this file. + /// \brief Offset of each type within the bitstream, indexed by the + /// type ID, or the representation of a Type*. + const uint32_t *TypeOffsets; + + // === Miscellaneous === + + /// \brief The AST stat cache installed for this file, if any. /// - /// This is the number of entries in SelectorOffsets. - unsigned LocalNumSelectors; + /// The dynamic type of this stat cache is always ASTStatCache + void *StatCache; + + /// \brief The number of preallocated preprocessing entities in the + /// preprocessing record. + unsigned NumPreallocatedPreprocessingEntities; + + /// \brief The next module in source order. + PerFileData *NextInSource; + + /// \brief All the modules that loaded this one. Can contain NULL for + /// directly loaded modules. + llvm::SmallVector<PerFileData *, 1> Loaders; }; + /// \brief All loaded modules, indexed by name. + llvm::StringMap<PerFileData*> Modules; + + /// \brief The first module in source order. + PerFileData *FirstInSource; + /// \brief The chain of AST files. The first entry is the one named by the /// user, the last one is the one that doesn't depend on anything further. /// That is, the entry I was created with -include-pch I+1. llvm::SmallVector<PerFileData*, 2> Chain; + /// \brief SLocEntries that we're going to preload. + llvm::SmallVector<uint64_t, 64> PreloadSLocEntries; + /// \brief Types that have already been loaded from the chain. /// /// When the pointer at index I is non-NULL, the type with @@ -331,6 +436,14 @@ private: /// = I + 1 has already been loaded. std::vector<Decl *> DeclsLoaded; + typedef std::pair<PerFileData *, uint64_t> FileOffset; + typedef llvm::SmallVector<FileOffset, 2> FileOffsetsTy; + typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy> + DeclUpdateOffsetsMap; + /// \brief Declarations that have modifications residing in a later file + /// in the chain. + DeclUpdateOffsetsMap DeclUpdateOffsets; + typedef llvm::DenseMap<serialization::DeclID, std::pair<PerFileData *, uint64_t> > DeclReplacementMap; @@ -340,7 +453,7 @@ private: /// \brief Information about the contents of a DeclContext. struct DeclContextInfo { void *NameLookupTableData; // a ASTDeclContextNameLookupTable. - const serialization::DeclID *LexicalDecls; + const serialization::KindDeclIDPair *LexicalDecls; unsigned NumLexicalDecls; }; // In a full chain, there could be multiple updates to every decl context, @@ -366,22 +479,20 @@ private: /// haven't been loaded yet. DeclContextVisibleUpdatesPending PendingVisibleUpdates; + typedef llvm::SmallVector<CXXRecordDecl *, 4> ForwardRefs; + typedef llvm::DenseMap<const CXXRecordDecl *, ForwardRefs> + PendingForwardRefsMap; + /// \brief Forward references that have a definition but the definition decl + /// is still initializing. When the definition gets read it will update + /// the DefinitionData pointer of all pending references. + PendingForwardRefsMap PendingForwardRefs; + typedef llvm::DenseMap<serialization::DeclID, serialization::DeclID> FirstLatestDeclIDMap; /// \brief Map of first declarations from a chained PCH that point to the /// most recent declarations in another AST file. FirstLatestDeclIDMap FirstLatestDeclIDs; - typedef llvm::SmallVector<serialization::DeclID, 4> - AdditionalTemplateSpecializations; - typedef llvm::DenseMap<serialization::DeclID, - AdditionalTemplateSpecializations> - AdditionalTemplateSpecializationsMap; - - /// \brief Additional specializations (including partial) of templates that - /// were introduced after the template was serialized. - AdditionalTemplateSpecializationsMap AdditionalTemplateSpecializationsPending; - /// \brief Read the records that describe the contents of declcontexts. bool ReadDeclContextStorage(llvm::BitstreamCursor &Cursor, const std::pair<uint64_t, uint64_t> &Offsets, @@ -405,6 +516,11 @@ private: /// \brief The macro definitions we have already loaded. llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded; + /// \brief Mapping from identifiers that represent macros whose definitions + /// have not yet been deserialized to the global offset where the macro + /// record resides. + llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets; + /// \name CodeGen-relevant special data /// \brief Fields containing data that is relevant to CodeGen. //@{ @@ -437,10 +553,6 @@ private: /// \brief Fields containing data that is used for generating diagnostics //@{ - /// \brief Method selectors used in a @selector expression. Used for - /// implementation of -Wselector. - llvm::SmallVector<uint64_t, 64> ReferencedSelectorsData; - /// \brief A snapshot of Sema's unused file-scoped variable tracking, for /// generating warnings. llvm::SmallVector<uint64_t, 16> UnusedFileScopedDecls; @@ -466,14 +578,6 @@ private: /// local external declarations. llvm::SmallVector<uint64_t, 16> LocallyScopedExternalDecls; - /// \brief A snapshot of the pwnsinf instantiations in the chain. - /// - /// This record tracks the instantiations that Sema has to perform at the end - /// of the TU. It consists of a pair of values for every pending instantiation - /// where the first value is the ID of the decl and the second is the - /// instantiation location. - llvm::SmallVector<uint64_t, 64> PendingInstantiations; - /// \brief The IDs of all dynamic class declarations in the chain. /// /// Sema tracks these because it checks for the key functions being defined @@ -490,8 +594,23 @@ private: /// The AST context tracks a few important types, such as va_list, directly. llvm::SmallVector<uint64_t, 16> SpecialTypes; + /// \brief The IDs of CUDA-specific declarations ASTContext stores directly. + /// + /// The AST context tracks a few important decls, currently cudaConfigureCall, + /// directly. + llvm::SmallVector<uint64_t, 2> CUDASpecialDeclRefs; + + /// \brief The floating point pragma option settings. + llvm::SmallVector<uint64_t, 1> FPPragmaOptions; + + /// \brief The OpenCL extension settings. + llvm::SmallVector<uint64_t, 1> OpenCLExtensions; + //@} + /// \brief Diagnostic IDs and their mappings that the user changed. + llvm::SmallVector<uint64_t, 8> PragmaDiagMappings; + /// \brief The original file name that was used to build the primary AST file, /// which may have been modified for relocatable-pch support. std::string OriginalFileName; @@ -500,6 +619,13 @@ private: /// AST file. std::string ActualOriginalFileName; + /// \brief The directory that the PCH was originally created in. Used to + /// allow resolving headers even after headers+PCH was moved to a new path. + std::string OriginalDir; + + /// \brief The directory that the PCH we are reading is stored in. + std::string CurrentDir; + /// \brief Whether this precompiled header is a relocatable PCH file. bool RelocatablePCH; @@ -511,27 +637,17 @@ private: /// headers when they are loaded. bool DisableValidation; + /// \brief Whether to disable the use of stat caches in AST files. + bool DisableStatCache; + /// \brief Mapping from switch-case IDs in the chain to switch-case statements /// /// Statements usually don't have IDs, but switch cases need them, so that the /// switch statement can refer to them. std::map<unsigned, SwitchCase *> SwitchCaseStmts; - /// \brief Mapping from label statement IDs in the chain to label statements. - /// - /// Statements usually don't have IDs, but labeled statements need them, so - /// that goto statements and address-of-label expressions can refer to them. - std::map<unsigned, LabelStmt *> LabelStmts; - - /// \brief Mapping from label IDs to the set of "goto" statements - /// that point to that label before the label itself has been - /// de-serialized. - std::multimap<unsigned, GotoStmt *> UnresolvedGotoStmts; - - /// \brief Mapping from label IDs to the set of address label - /// expressions that point to that label before the label itself has - /// been de-serialized. - std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs; + /// \brief Mapping from opaque value IDs to OpaqueValueExprs. + std::map<unsigned, OpaqueValueExpr*> OpaqueValueExprs; /// \brief The number of stat() calls that hit/missed the stat /// cache. @@ -544,6 +660,9 @@ private: /// \brief The number of source location entries in the chain. unsigned TotalNumSLocEntries; + /// \brief The next offset for a SLocEntry after everything in this reader. + unsigned NextSLocOffset; + /// \brief The number of statements (and expressions) de-serialized /// from the chain. unsigned NumStatementsRead; @@ -602,6 +721,13 @@ private: /// Objective-C protocols. std::deque<Decl *> InterestingDecls; + /// \brief We delay loading of the previous declaration chain to avoid + /// deeply nested calls when there are many redeclarations. + std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls; + + /// \brief Ready to load the previous declaration of the given Decl. + void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID); + /// \brief When reading a Stmt tree, Stmt operands are placed in this stack. llvm::SmallVector<Stmt *, 16> StmtStack; @@ -645,20 +771,26 @@ private: std::string SuggestedPredefines; /// \brief Reads a statement from the specified cursor. - Stmt *ReadStmtFromStream(llvm::BitstreamCursor &Cursor); + Stmt *ReadStmtFromStream(PerFileData &F); void MaybeAddSystemRootToFilename(std::string &Filename); - ASTReadResult ReadASTCore(llvm::StringRef FileName); + ASTReadResult ReadASTCore(llvm::StringRef FileName, ASTFileType Type); ASTReadResult ReadASTBlock(PerFileData &F); bool CheckPredefinesBuffers(); - bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record); + bool ParseLineTable(PerFileData &F, llvm::SmallVectorImpl<uint64_t> &Record); ASTReadResult ReadSourceManagerBlock(PerFileData &F); ASTReadResult ReadSLocEntryRecord(unsigned ID); - llvm::BitstreamCursor &SLocCursorForID(unsigned ID); + PerFileData *SLocCursorForID(unsigned ID); + SourceLocation getImportLocation(PerFileData *F); bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record); - typedef std::pair<llvm::BitstreamCursor *, uint64_t> RecordLocation; + struct RecordLocation { + RecordLocation(PerFileData *M, uint64_t O) + : F(M), Offset(O) {} + PerFileData *F; + uint64_t Offset; + }; QualType ReadTypeRecord(unsigned Index); RecordLocation TypeCursorForIndex(unsigned Index); @@ -695,8 +827,14 @@ public: /// \param DisableValidation If true, the AST reader will suppress most /// of its regular consistency checking, allowing the use of precompiled /// headers that cannot be determined to be compatible. + /// + /// \param DisableStatCache If true, the AST reader will ignore the + /// stat cache in the AST files. This performance pessimization can + /// help when an AST file is being used in cases where the + /// underlying files in the file system may have changed, but + /// parsing should still continue. ASTReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0, - bool DisableValidation = false); + bool DisableValidation = false, bool DisableStatCache = false); /// \brief Load the AST file without using any pre-initialized Preprocessor. /// @@ -717,14 +855,20 @@ public: /// \param DisableValidation If true, the AST reader will suppress most /// of its regular consistency checking, allowing the use of precompiled /// headers that cannot be determined to be compatible. - ASTReader(SourceManager &SourceMgr, FileManager &FileMgr, + /// + /// \param DisableStatCache If true, the AST reader will ignore the + /// stat cache in the AST files. This performance pessimization can + /// help when an AST file is being used in cases where the + /// underlying files in the file system may have changed, but + /// parsing should still continue. + ASTReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags, const char *isysroot = 0, - bool DisableValidation = false); + bool DisableValidation = false, bool DisableStatCache = false); ~ASTReader(); /// \brief Load the precompiled header designated by the given file /// name. - ASTReadResult ReadAST(const std::string &FileName); + ASTReadResult ReadAST(const std::string &FileName, ASTFileType Type); /// \brief Set the AST callbacks listener. void setListener(ASTReaderListener *listener) { @@ -749,6 +893,7 @@ public: /// \brief Retrieve the name of the original source file name directly from /// the AST file, without actually loading the AST file. static std::string getOriginalSourceFile(const std::string &ASTFileName, + FileManager &FileMgr, Diagnostic &Diags); /// \brief Returns the suggested contents of the predefines buffer, @@ -756,14 +901,27 @@ public: /// build prior to including the precompiled header. const std::string &getSuggestedPredefines() { return SuggestedPredefines; } - /// \brief Read preprocessed entities into the + /// \brief Read preprocessed entities into the preprocessing record. virtual void ReadPreprocessedEntities(); + /// \brief Read the preprocessed entity at the given offset. + virtual PreprocessedEntity *ReadPreprocessedEntityAtOffset(uint64_t Offset); + + /// \brief Read the header file information for the given file entry. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE); + + void ReadPragmaDiagnosticMappings(Diagnostic &Diag); + /// \brief Returns the number of source locations found in the chain. unsigned getTotalNumSLocs() const { return TotalNumSLocEntries; } + /// \brief Returns the next SLocEntry offset after the chain. + unsigned getNextSLocOffset() const { + return NextSLocOffset; + } + /// \brief Returns the number of identifiers found in the chain. unsigned getTotalNumIdentifiers() const { return static_cast<unsigned>(IdentifiersLoaded.size()); @@ -784,20 +942,27 @@ public: return static_cast<unsigned>(SelectorsLoaded.size()); } + /// \brief Returns the number of macro definitions found in the chain. + unsigned getTotalNumMacroDefinitions() const { + return static_cast<unsigned>(MacroDefinitionsLoaded.size()); + } + + /// \brief Returns the number of C++ base specifiers found in the chain. + unsigned getTotalNumCXXBaseSpecifiers() const; + /// \brief Reads a TemplateArgumentLocInfo appropriate for the /// given TemplateArgument kind. TemplateArgumentLocInfo - GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, - llvm::BitstreamCursor &DeclsCursor, + GetTemplateArgumentLocInfo(PerFileData &F, TemplateArgument::ArgKind Kind, const RecordData &Record, unsigned &Idx); /// \brief Reads a TemplateArgumentLoc. TemplateArgumentLoc - ReadTemplateArgumentLoc(llvm::BitstreamCursor &DeclsCursor, + ReadTemplateArgumentLoc(PerFileData &F, const RecordData &Record, unsigned &Idx); /// \brief Reads a declarator info from the given record. - TypeSourceInfo *GetTypeSourceInfo(llvm::BitstreamCursor &DeclsCursor, + TypeSourceInfo *GetTypeSourceInfo(PerFileData &F, const RecordData &Record, unsigned &Idx); /// \brief Resolve and return the translation unit declaration. @@ -822,6 +987,12 @@ public: Decl *GetDecl(serialization::DeclID ID); virtual Decl *GetExternalDecl(uint32_t ID); + /// \brief Resolve a CXXBaseSpecifiers ID into an offset into the chain + /// of loaded AST files. + uint64_t GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID); + + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + /// \brief Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external @@ -857,6 +1028,7 @@ public: /// \returns true if there was an error while reading the /// declarations for this declaration context. virtual bool FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), llvm::SmallVectorImpl<Decl*> &Decls); /// \brief Notify ASTReader that we started deserialization of @@ -897,6 +1069,10 @@ public: return get(Name.begin(), Name.end()); } + /// \brief Retrieve an iterator into the set of all identifiers + /// in all loaded AST files. + virtual IdentifierIterator *getIdentifiers() const; + /// \brief Load the contents of the global method pool for a given /// selector. /// @@ -943,47 +1119,65 @@ public: /// \brief Read a declaration name. DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameLoc(PerFileData &F, + DeclarationNameLoc &DNLoc, DeclarationName Name, + const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameInfo(PerFileData &F, DeclarationNameInfo &NameInfo, + const RecordData &Record, unsigned &Idx); + + void ReadQualifierInfo(PerFileData &F, QualifierInfo &Info, + const RecordData &Record, unsigned &Idx); NestedNameSpecifier *ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx); /// \brief Read a template name. - TemplateName ReadTemplateName(const RecordData &Record, unsigned &Idx); + TemplateName ReadTemplateName(PerFileData &F, const RecordData &Record, + unsigned &Idx); /// \brief Read a template argument. - TemplateArgument ReadTemplateArgument(llvm::BitstreamCursor &DeclsCursor, + TemplateArgument ReadTemplateArgument(PerFileData &F, const RecordData &Record,unsigned &Idx); /// \brief Read a template parameter list. - TemplateParameterList *ReadTemplateParameterList(const RecordData &Record, + TemplateParameterList *ReadTemplateParameterList(PerFileData &F, + const RecordData &Record, unsigned &Idx); /// \brief Read a template argument array. void ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs, - llvm::BitstreamCursor &DeclsCursor, - const RecordData &Record, unsigned &Idx); + PerFileData &F, const RecordData &Record, + unsigned &Idx); /// \brief Read a UnresolvedSet structure. void ReadUnresolvedSet(UnresolvedSetImpl &Set, const RecordData &Record, unsigned &Idx); /// \brief Read a C++ base specifier. - CXXBaseSpecifier ReadCXXBaseSpecifier(llvm::BitstreamCursor &DeclsCursor, + CXXBaseSpecifier ReadCXXBaseSpecifier(PerFileData &F, const RecordData &Record,unsigned &Idx); - /// \brief Read a CXXBaseOrMemberInitializer array. - std::pair<CXXBaseOrMemberInitializer **, unsigned> - ReadCXXBaseOrMemberInitializers(llvm::BitstreamCursor &DeclsCursor, - const RecordData &Record, unsigned &Idx); + /// \brief Read a CXXCtorInitializer array. + std::pair<CXXCtorInitializer **, unsigned> + ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a source location from raw form. + SourceLocation ReadSourceLocation(PerFileData &Module, unsigned Raw) { + (void)Module; // No remapping yet + return SourceLocation::getFromRawEncoding(Raw); + } /// \brief Read a source location. - SourceLocation ReadSourceLocation(const RecordData &Record, unsigned& Idx) { - return SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation ReadSourceLocation(PerFileData &Module, + const RecordData &Record, unsigned& Idx) { + return ReadSourceLocation(Module, Record[Idx++]); } /// \brief Read a source range. - SourceRange ReadSourceRange(const RecordData &Record, unsigned& Idx); + SourceRange ReadSourceRange(PerFileData &F, + const RecordData &Record, unsigned& Idx); /// \brief Read an integral value llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx); @@ -1000,13 +1194,14 @@ public: CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx); /// \brief Reads attributes from the current stream position. - void ReadAttributes(llvm::BitstreamCursor &DeclsCursor, AttrVec &Attrs); + void ReadAttributes(PerFileData &F, AttrVec &Attrs, + const RecordData &Record, unsigned &Idx); /// \brief Reads a statement. - Stmt *ReadStmt(llvm::BitstreamCursor &Cursor); + Stmt *ReadStmt(PerFileData &F); /// \brief Reads an expression. - Expr *ReadExpr(llvm::BitstreamCursor &Cursor); + Expr *ReadExpr(PerFileData &F); /// \brief Reads a sub-statement operand during statement reading. Stmt *ReadSubStmt() { @@ -1022,13 +1217,30 @@ public: Expr *ReadSubExpr(); /// \brief Reads the macro record located at the given offset. - void ReadMacroRecord(llvm::BitstreamCursor &Stream, uint64_t Offset); + PreprocessedEntity *ReadMacroRecord(PerFileData &F, uint64_t Offset); + /// \brief Reads the preprocessed entity located at the current stream + /// position. + PreprocessedEntity *LoadPreprocessedEntity(PerFileData &F); + + /// \brief Note that the identifier is a macro whose record will be loaded + /// from the given AST file at the given (file-local) offset. + void SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F, + uint64_t Offset); + /// \brief Read the set of macros defined by this external macro source. virtual void ReadDefinedMacros(); + /// \brief Read the macro definition for this identifier. + virtual void LoadMacroDefinition(IdentifierInfo *II); + + /// \brief Read the macro definition corresponding to this iterator + /// into the unread macro record offsets table. + void LoadMacroDefinition( + llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos); + /// \brief Retrieve the macro definition with the given ID. - MacroDefinition *getMacroDefinition(serialization::IdentID ID); + MacroDefinition *getMacroDefinition(serialization::MacroID ID); /// \brief Retrieve the AST context that this AST reader supplements. ASTContext *getContext() { return Context; } @@ -1053,27 +1265,7 @@ public: /// \brief Retrieve the switch-case statement with the given ID. SwitchCase *getSwitchCaseWithID(unsigned ID); - /// \brief Record that the given label statement has been - /// deserialized and has the given ID. - void RecordLabelStmt(LabelStmt *S, unsigned ID); - - /// \brief Set the label of the given statement to the label - /// identified by ID. - /// - /// Depending on the order in which the label and other statements - /// referencing that label occur, this operation may complete - /// immediately (updating the statement) or it may queue the - /// statement to be back-patched later. - void SetLabelOf(GotoStmt *S, unsigned ID); - - /// \brief Set the label of the given expression to the label - /// identified by ID. - /// - /// Depending on the order in which the label and other statements - /// referencing that label occur, this operation may complete - /// immediately (updating the statement) or it may queue the - /// statement to be back-patched later. - void SetLabelOf(AddrLabelExpr *S, unsigned ID); + void ClearSwitchCaseIDs(); }; /// \brief Helper class that saves the current stream position and diff --git a/include/clang/Serialization/ASTSerializationListener.h b/include/clang/Serialization/ASTSerializationListener.h new file mode 100644 index 000000000000..0c62e0b9ca5a --- /dev/null +++ b/include/clang/Serialization/ASTSerializationListener.h @@ -0,0 +1,44 @@ +//===- ASTSerializationListener.h - Decl/Type PCH Write Events -*- 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 ASTSerializationListener class, which is notified +// by the ASTWriter when an entity is serialized. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_AST_SERIALIZATION_LISTENER_H +#define LLVM_CLANG_FRONTEND_AST_SERIALIZATION_LISTENER_H + +#include "llvm/Support/DataTypes.h" + +namespace clang { + +class PreprocessedEntity; + +/// \brief Listener object that receives callbacks when certain kinds of +/// entities are serialized. +class ASTSerializationListener { +public: + virtual ~ASTSerializationListener(); + + /// \brief Callback invoked whenever a preprocessed entity is serialized. + /// + /// This callback will only occur when the translation unit was created with + /// a detailed preprocessing record. + /// + /// \param Entity The entity that has been serialized. + /// + /// \param Offset The offset (in bits) of this entity in the resulting + /// AST file. + virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity, + uint64_t Offset) = 0; +}; + +} + +#endif diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 426fc4780148..beb493625e87 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -17,11 +17,13 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Sema/SemaConsumer.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/Bitcode/BitstreamWriter.h" #include <map> #include <queue> @@ -36,13 +38,19 @@ namespace llvm { namespace clang { class ASTContext; +class ASTSerializationListener; class NestedNameSpecifier; class CXXBaseSpecifier; -class CXXBaseOrMemberInitializer; -class LabelStmt; +class CXXCtorInitializer; +class FPOptions; +class HeaderSearch; class MacroDefinition; class MemorizeStatCalls; +class OpaqueValueExpr; +class OpenCLOptions; class ASTReader; +class PreprocessedEntity; +class PreprocessingRecord; class Preprocessor; class Sema; class SourceManager; @@ -55,9 +63,11 @@ class TargetInfo; /// representation of a given abstract syntax tree and its supporting /// data structures. This bitstream can be de-serialized via an /// instance of the ASTReader class. -class ASTWriter : public ASTDeserializationListener { +class ASTWriter : public ASTDeserializationListener, + public ASTMutationListener { public: typedef llvm::SmallVector<uint64_t, 64> RecordData; + typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl; friend class ASTDeclWriter; private: @@ -67,6 +77,10 @@ private: /// \brief The reader of existing AST files, if we're chaining. ASTReader *Chain; + /// \brief A listener object that receives notifications when certain + /// entities are serialized. + ASTSerializationListener *SerializationListener; + /// \brief Stores a declaration or a type to be written to the AST file. class DeclOrType { public: @@ -163,7 +177,7 @@ private: /// \brief Offset of each selector within the method pool/selector /// table, indexed by the Selector ID (-1). std::vector<uint32_t> SelectorOffsets; - + /// \brief Offsets of each of the macro identifiers into the /// bitstream. /// @@ -172,15 +186,30 @@ private: /// defined. llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets; + /// \brief The set of identifiers that had macro definitions at some point. + std::vector<const IdentifierInfo *> DeserializedMacroNames; + + /// \brief The first ID number we can use for our own macro definitions. + serialization::MacroID FirstMacroID; + + /// \brief The decl ID that will be assigned to the next new macro definition. + serialization::MacroID NextMacroID; + /// \brief Mapping from macro definitions (as they occur in the preprocessing - /// record) to the index into the macro definitions table. - llvm::DenseMap<const MacroDefinition *, serialization::IdentID> + /// record) to the macro IDs. + llvm::DenseMap<const MacroDefinition *, serialization::MacroID> MacroDefinitions; /// \brief Mapping from the macro definition indices in \c MacroDefinitions /// to the corresponding offsets within the preprocessor block. std::vector<uint32_t> MacroDefinitionOffsets; + typedef llvm::SmallVector<uint64_t, 2> UpdateRecord; + typedef llvm::DenseMap<const Decl *, UpdateRecord> DeclUpdateMap; + /// \brief Mapping from declarations that came from a chained PCH to the + /// record containing modifications to them. + DeclUpdateMap DeclUpdates; + typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap; /// \brief Map of first declarations from a chained PCH that point to the /// most recent declarations in another PCH. @@ -200,13 +229,17 @@ private: /// record. llvm::SmallVector<uint64_t, 16> ExternalDefinitions; - /// \brief Namespaces that have received extensions since their serialized + /// \brief DeclContexts that have received extensions since their serialized /// form. /// - /// Basically, when we're chaining and encountering a namespace, we check if + /// For namespaces, when we're chaining and encountering a namespace, we check if /// its primary namespace comes from the chain. If it does, we add the primary /// to this set, so that we can write out lexical content updates for it. - llvm::SmallPtrSet<const NamespaceDecl *, 16> UpdatedNamespaces; + llvm::SmallPtrSet<const DeclContext *, 16> UpdatedDeclContexts; + + typedef llvm::SmallPtrSet<const Decl *, 16> DeclsToRewriteTy; + /// \brief Decls that will be replaced in the current dependent AST file. + DeclsToRewriteTy DeclsToRewrite; /// \brief Decls that have been replaced in the current dependent AST file. /// @@ -217,16 +250,6 @@ private: llvm::SmallVector<std::pair<serialization::DeclID, uint64_t>, 16> ReplacedDecls; - typedef llvm::SmallVector<serialization::DeclID, 4> - AdditionalTemplateSpecializationsList; - typedef llvm::DenseMap<serialization::DeclID, - AdditionalTemplateSpecializationsList> - AdditionalTemplateSpecializationsMap; - - /// \brief Additional specializations (including partial) of templates that - /// were introduced after the template was serialized. - AdditionalTemplateSpecializationsMap AdditionalTemplateSpecializations; - /// \brief Statements that we've encountered while serializing a /// declaration or type. llvm::SmallVector<Stmt *, 16> StmtsToEmit; @@ -238,8 +261,8 @@ 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; + /// \brief Mapping from OpaqueValueExpr expressions to IDs. + llvm::DenseMap<OpaqueValueExpr *, unsigned> OpaqueValues; /// \brief The number of statements written to the AST file. unsigned NumStatements; @@ -255,17 +278,50 @@ private: /// file. unsigned NumVisibleDeclContexts; + /// \brief The offset of each CXXBaseSpecifier set within the AST. + llvm::SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets; + + /// \brief The first ID number we can use for our own base specifiers. + serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID; + + /// \brief The base specifiers ID that will be assigned to the next new + /// set of C++ base specifiers. + serialization::CXXBaseSpecifiersID NextCXXBaseSpecifiersID; + + /// \brief A set of C++ base specifiers that is queued to be written into the + /// AST file. + struct QueuedCXXBaseSpecifiers { + QueuedCXXBaseSpecifiers() : ID(), Bases(), BasesEnd() { } + + QueuedCXXBaseSpecifiers(serialization::CXXBaseSpecifiersID ID, + CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd) + : ID(ID), Bases(Bases), BasesEnd(BasesEnd) { } + + serialization::CXXBaseSpecifiersID ID; + CXXBaseSpecifier const * Bases; + CXXBaseSpecifier const * BasesEnd; + }; + + /// \brief Queue of C++ base specifiers to be written to the AST file, + /// in the order they should be written. + llvm::SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite; + /// \brief Write the given subexpression to the bitstream. void WriteSubStmt(Stmt *S); void WriteBlockInfoBlock(); - void WriteMetadata(ASTContext &Context, const char *isysroot); + void WriteMetadata(ASTContext &Context, const char *isysroot, + const std::string &OutputFile); void WriteLanguageOptions(const LangOptions &LangOpts); void WriteStatCache(MemorizeStatCalls &StatCalls); void WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP, const char* isysroot); void WritePreprocessor(const Preprocessor &PP); + void WriteHeaderSearch(HeaderSearch &HS, const char* isysroot); + void WritePreprocessorDetail(PreprocessingRecord &PPRec); + void WritePragmaDiagnosticMappings(const Diagnostic &Diag); void WriteType(QualType T); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); @@ -273,10 +329,12 @@ private: void WriteSelectors(Sema &SemaRef); void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP); - void WriteAttributeRecord(const AttrVec &Attrs); - void WriteDeclUpdateBlock(); + void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record); + void WriteDeclUpdatesBlocks(); + void WriteDeclReplacementsBlock(); void WriteDeclContextVisibleUpdate(const DeclContext *DC); - void WriteAdditionalTemplateSpecializations(); + void WriteFPPragmaOptions(const FPOptions &Opts); + void WriteOpenCLExtensions(Sema &SemaRef); unsigned ParmVarDeclAbbrev; unsigned DeclContextLexicalAbbrev; @@ -286,7 +344,7 @@ private: void WriteDecl(ASTContext &Context, Decl *D); void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char* isysroot); + const char* isysroot, const std::string &OutputFile); void WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, const char* isysroot); @@ -295,6 +353,12 @@ public: /// the given bitstream. ASTWriter(llvm::BitstreamWriter &Stream); + /// \brief Set the listener that will receive notification of serialization + /// events. + void SetSerializationListener(ASTSerializationListener *Listener) { + SerializationListener = Listener; + } + /// \brief Write a precompiled header for the given semantic analysis. /// /// \param SemaRef a reference to the semantic analysis object that processed @@ -309,32 +373,38 @@ public: /// \param PPRec Record of the preprocessing actions that occurred while /// preprocessing this file, e.g., macro instantiations void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, + const std::string &OutputFile, const char* isysroot); /// \brief Emit a source location. - void AddSourceLocation(SourceLocation Loc, RecordData &Record); + void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record); /// \brief Emit a source range. - void AddSourceRange(SourceRange Range, RecordData &Record); + void AddSourceRange(SourceRange Range, RecordDataImpl &Record); /// \brief Emit an integral value. - void AddAPInt(const llvm::APInt &Value, RecordData &Record); + void AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record); /// \brief Emit a signed integral value. - void AddAPSInt(const llvm::APSInt &Value, RecordData &Record); + void AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record); /// \brief Emit a floating-point value. - void AddAPFloat(const llvm::APFloat &Value, RecordData &Record); + void AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record); /// \brief Emit a reference to an identifier. - void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record); + void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record); /// \brief Emit a Selector (which is a smart pointer reference). - void AddSelectorRef(Selector, RecordData &Record); + void AddSelectorRef(Selector, RecordDataImpl &Record); /// \brief Emit a CXXTemporary. - void AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record); + void AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record); + /// \brief Emit a set of C++ base specifiers to the record. + void AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd, + RecordDataImpl &Record); + /// \brief Get the unique number used to refer to the given selector. serialization::SelectorID getSelectorRef(Selector Sel); @@ -353,10 +423,10 @@ public: /// \brief Retrieve the ID number corresponding to the given macro /// definition. - serialization::IdentID getMacroDefinitionID(MacroDefinition *MD); + serialization::MacroID getMacroDefinitionID(MacroDefinition *MD); /// \brief Emit a reference to a type. - void AddTypeRef(QualType T, RecordData &Record); + void AddTypeRef(QualType T, RecordDataImpl &Record); /// \brief Force a type to be emitted and get its ID. serialization::TypeID GetOrCreateTypeID(QualType T); @@ -371,20 +441,21 @@ public: serialization::TypeIdx getTypeIdx(QualType T) const; /// \brief Emits a reference to a declarator info. - void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record); + void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record); /// \brief Emits a template argument location info. void AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, const TemplateArgumentLocInfo &Arg, - RecordData &Record); + RecordDataImpl &Record); /// \brief Emits a template argument location. void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, - RecordData &Record); + RecordDataImpl &Record); /// \brief Emit a reference to a declaration. - void AddDeclRef(const Decl *D, RecordData &Record); + void AddDeclRef(const Decl *D, RecordDataImpl &Record); + /// \brief Force a declaration to be emitted and get its ID. serialization::DeclID GetDeclRef(const Decl *D); @@ -393,49 +464,57 @@ public: serialization::DeclID getDeclID(const Decl *D); /// \brief Emit a declaration name. - void AddDeclarationName(DeclarationName Name, RecordData &Record); + void AddDeclarationName(DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, + DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + RecordDataImpl &Record); + + void AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record); /// \brief Emit a nested name specifier. - void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordData &Record); + void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record); /// \brief Emit a template name. - void AddTemplateName(TemplateName Name, RecordData &Record); + void AddTemplateName(TemplateName Name, RecordDataImpl &Record); /// \brief Emit a template argument. - void AddTemplateArgument(const TemplateArgument &Arg, RecordData &Record); + void AddTemplateArgument(const TemplateArgument &Arg, RecordDataImpl &Record); /// \brief Emit a template parameter list. void AddTemplateParameterList(const TemplateParameterList *TemplateParams, - RecordData &Record); + RecordDataImpl &Record); /// \brief Emit a template argument list. void AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, - RecordData &Record); + RecordDataImpl &Record); /// \brief Emit a UnresolvedSet structure. - void AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordData &Record); + void AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record); /// \brief Emit a C++ base specifier. - void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, RecordData &Record); + void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, RecordDataImpl &Record); + + /// \brief Emit a CXXCtorInitializer array. + void AddCXXCtorInitializers( + const CXXCtorInitializer * const *CtorInitializers, + unsigned NumCtorInitializers, + RecordDataImpl &Record); - /// \brief Emit a CXXBaseOrMemberInitializer array. - void AddCXXBaseOrMemberInitializers( - const CXXBaseOrMemberInitializer * const *BaseOrMembers, - unsigned NumBaseOrMembers, RecordData &Record); + void AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record); /// \brief Add a string to the given record. - void AddString(llvm::StringRef Str, RecordData &Record); + void AddString(llvm::StringRef Str, RecordDataImpl &Record); - /// \brief Mark a namespace as needing an update. - void AddUpdatedNamespace(const NamespaceDecl *NS) { - UpdatedNamespaces.insert(NS); + /// \brief Mark a declaration context as needing an update. + void AddUpdatedDeclContext(const DeclContext *DC) { + UpdatedDeclContexts.insert(DC); } - /// \brief Record a template specialization or partial specialization of - /// a template from a previous PCH file. - void AddAdditionalTemplateSpecialization(serialization::DeclID Templ, - serialization::DeclID Spec) { - AdditionalTemplateSpecializations[Templ].push_back(Spec); + void RewriteDecl(const Decl *D) { + DeclsToRewrite.insert(D); + // Reset the flag, so that we don't add this decl multiple times. + const_cast<Decl *>(D)->setChangedSinceDeserialization(false); } /// \brief Note that the identifier II occurs at the given offset @@ -462,32 +541,46 @@ public: /// been added to the queue via AddStmt(). void FlushStmts(); + /// \brief Flush all of the C++ base specifier sets that have been added + /// via \c AddCXXBaseSpecifiersRef(). + void FlushCXXBaseSpecifiers(); + /// \brief Record an ID for the given switch-case statement. unsigned RecordSwitchCaseID(SwitchCase *S); /// \brief Retrieve the ID for the given switch-case statement. unsigned getSwitchCaseID(SwitchCase *S); - /// \brief Retrieve the ID for the given label statement, which may - /// or may not have been emitted yet. - unsigned GetLabelID(LabelStmt *S); + void ClearSwitchCaseIDs(); + + /// \brief Retrieve the ID for the given opaque value expression. + unsigned getOpaqueValueID(OpaqueValueExpr *e); unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; } bool hasChain() const { return Chain; } // ASTDeserializationListener implementation - void SetReader(ASTReader *Reader); + void ReaderInitialized(ASTReader *Reader); void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II); void TypeRead(serialization::TypeIdx Idx, QualType T); void DeclRead(serialization::DeclID ID, const Decl *D); - void SelectorRead(serialization::SelectorID iD, Selector Sel); + void SelectorRead(serialization::SelectorID ID, Selector Sel); + void MacroDefinitionRead(serialization::MacroID ID, MacroDefinition *MD); + + // ASTMutationListener implementation. + virtual void CompletedTagDefinition(const TagDecl *D); + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D); + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D); }; /// \brief AST and semantic-analysis consumer that generates a /// precompiled header from the parsed source code. class PCHGenerator : public SemaConsumer { const Preprocessor &PP; + std::string OutputFile; const char *isysroot; llvm::raw_ostream *Out; Sema *SemaPtr; @@ -495,16 +588,19 @@ class PCHGenerator : public SemaConsumer { std::vector<unsigned char> Buffer; llvm::BitstreamWriter Stream; ASTWriter Writer; + bool Chaining; protected: ASTWriter &getWriter() { return Writer; } const ASTWriter &getWriter() const { return Writer; } public: - PCHGenerator(const Preprocessor &PP, bool Chaining, + PCHGenerator(const Preprocessor &PP, const std::string &OutputFile, bool Chaining, const char *isysroot, llvm::raw_ostream *Out); virtual void InitializeSema(Sema &S) { SemaPtr = &S; } virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTSerializationListener *GetASTSerializationListener(); virtual ASTDeserializationListener *GetASTDeserializationListener(); }; diff --git a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td new file mode 100644 index 000000000000..e452ccfb6ceb --- /dev/null +++ b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -0,0 +1,38 @@ +//===--- CheckerBase.td - Checker TableGen classes ------------------------===// +// +// 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 TableGen core definitions for checkers +// +//===----------------------------------------------------------------------===// + +class Package<string name> { + string PackageName = name; + bit Hidden = 0; + Package ParentPackage; +} +class InPackage<Package P> { Package ParentPackage = P; } + +class CheckerGroup<string name> { + string GroupName = name; +} +class InGroup<CheckerGroup G> { CheckerGroup Group = G; } + +// All checkers are an indirect subclass of this. +class Checker<string name = ""> { + string CheckerName = name; + string DescFile; + string HelpText; + bit Hidden = 0; + Package ParentPackage; + CheckerGroup Group; +} + +class DescFile<string filename> { string DescFile = filename; } +class HelpText<string text> { string HelpText = text; } +class Hidden { bit Hidden = 1; } diff --git a/include/clang/Checker/Checkers/DereferenceChecker.h b/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h index a84183e7f27f..f9cce9ca9c62 100644 --- a/include/clang/Checker/Checkers/DereferenceChecker.h +++ b/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h @@ -8,23 +8,27 @@ //===----------------------------------------------------------------------===// // // This defines NullDerefChecker and UndefDerefChecker, two builtin checks -// in GRExprEngine that check for null and undefined pointers at loads +// in ExprEngine that check for null and undefined pointers at loads // and stores. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_DEREFCHECKER -#define LLVM_CLANG_DEREFCHECKER +#ifndef LLVM_CLANG_GR_DEREFCHECKER +#define LLVM_CLANG_GR_DEREFCHECKER #include <utility> namespace clang { -class GRExprEngine; +namespace ento { + +class ExprEngine; class ExplodedNode; std::pair<ExplodedNode * const *, ExplodedNode * const *> -GetImplicitNullDereferences(GRExprEngine &Eng); +GetImplicitNullDereferences(ExprEngine &Eng); + +} // end GR namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h new file mode 100644 index 000000000000..42feb78b4174 --- /dev/null +++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -0,0 +1,51 @@ +//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive 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 the interface to call a set of intra-procedural (local) +// checkers that use flow/path-sensitive analyses to find bugs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_LOCALCHECKERS_H +#define LLVM_CLANG_GR_LOCALCHECKERS_H + +namespace clang { + +class CFG; +class Decl; +class Diagnostic; +class ASTContext; +class LangOptions; +class ParentMap; +class LiveVariables; +class ObjCImplementationDecl; +class LangOptions; +class TranslationUnitDecl; + +namespace ento { + +class PathDiagnosticClient; +class TransferFuncs; +class BugType; +class BugReporter; +class ExprEngine; + +TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); + +void RegisterExperimentalChecks(ExprEngine &Eng); +void RegisterExperimentalInternalChecks(ExprEngine &Eng); + +void RegisterCallInliner(ExprEngine &Eng); + +} // end GR namespace + +} // end namespace clang + +#endif diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 370d96552c45..1786fe610d6b 100644 --- a/include/clang/Checker/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER -#define LLVM_CLANG_ANALYSIS_BUGREPORTER +#ifndef LLVM_CLANG_GR_BUGREPORTER +#define LLVM_CLANG_GR_BUGREPORTER #include "clang/Basic/SourceLocation.h" -#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableSet.h" @@ -25,20 +25,23 @@ namespace clang { +class ASTContext; +class Diagnostic; +class Stmt; +class ParentMap; + +namespace ento { + class PathDiagnostic; class PathDiagnosticPiece; class PathDiagnosticClient; -class ASTContext; -class Diagnostic; class ExplodedNode; class ExplodedGraph; class BugReporter; class BugReporterContext; -class GRExprEngine; +class ExprEngine; class GRState; -class Stmt; class BugType; -class ParentMap; //===----------------------------------------------------------------------===// // Interface for individual bug reports. @@ -61,8 +64,8 @@ protected: BugType& BT; std::string ShortDescription; std::string Description; - const ExplodedNode *EndNode; - SourceRange R; + const ExplodedNode *ErrorNode; + mutable SourceRange R; protected: friend class BugReporter; @@ -81,12 +84,13 @@ public: getOriginalNode(const ExplodedNode* N) = 0; }; - BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *n) - : BT(bt), Description(desc), EndNode(n) {} + BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode) + : BT(bt), Description(desc), ErrorNode(errornode) {} BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc, - const ExplodedNode *n) - : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} + const ExplodedNode *errornode) + : BT(bt), ShortDescription(shortDesc), Description(desc), + ErrorNode(errornode) {} virtual ~BugReport(); @@ -96,7 +100,7 @@ public: BugType& getBugType() { return BT; } // FIXME: Perhaps this should be moved into a subclass? - const ExplodedNode* getEndNode() const { return EndNode; } + const ExplodedNode* getErrorNode() const { return ErrorNode; } // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint // object. @@ -125,8 +129,10 @@ public: /// This location is used by clients rendering diagnostics. virtual SourceLocation getLocation() const; + typedef const SourceRange *ranges_iterator; + /// getRanges - Returns the source ranges associated with this bug. - virtual void getRanges(const SourceRange*& beg, const SourceRange*& end); + virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const; virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, const ExplodedNode* PrevN, @@ -191,14 +197,15 @@ public: // FIXME: Collapse this with the default BugReport class. class RangedBugReport : public BugReport { - std::vector<SourceRange> Ranges; + llvm::SmallVector<SourceRange, 4> Ranges; public: - RangedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) - : BugReport(D, description, n) {} + RangedBugReport(BugType& D, llvm::StringRef description, + ExplodedNode *errornode) + : BugReport(D, description, errornode) {} RangedBugReport(BugType& D, llvm::StringRef shortDescription, - llvm::StringRef description, ExplodedNode *n) - : BugReport(D, shortDescription, description, n) {} + llvm::StringRef description, ExplodedNode *errornode) + : BugReport(D, shortDescription, description, errornode) {} ~RangedBugReport(); @@ -208,17 +215,8 @@ public: Ranges.push_back(R); } - // FIXME: Move this out of line. - void getRanges(const SourceRange*& beg, const SourceRange*& end) { - - if (Ranges.empty()) { - beg = NULL; - end = NULL; - } - else { - beg = &Ranges[0]; - end = beg + Ranges.size(); - } + virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const { + return std::make_pair(Ranges.begin(), Ranges.end()); } }; @@ -232,12 +230,13 @@ private: Creators creators; public: - EnhancedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) - : RangedBugReport(D, description, n) {} + EnhancedBugReport(BugType& D, llvm::StringRef description, + ExplodedNode *errornode) + : RangedBugReport(D, description, errornode) {} EnhancedBugReport(BugType& D, llvm::StringRef shortDescription, - llvm::StringRef description, ExplodedNode *n) - : RangedBugReport(D, shortDescription, description, n) {} + llvm::StringRef description, ExplodedNode *errornode) + : RangedBugReport(D, shortDescription, description, errornode) {} ~EnhancedBugReport() {} @@ -279,10 +278,12 @@ private: void FlushReport(BugReportEquivClass& EQ); protected: - BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), + D(d) {} public: - BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} + BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), + D(d) {} virtual ~BugReporter(); void FlushReports(); @@ -305,8 +306,8 @@ public: SourceManager& getSourceManager() { return D.getSourceManager(); } - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, - BugReportEquivClass& EQ) {} + virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, + llvm::SmallVectorImpl<BugReport *> &bugReports) {} void Register(BugType *BT); @@ -347,17 +348,17 @@ public: // FIXME: Get rid of GRBugReporter. It's the wrong abstraction. class GRBugReporter : public BugReporter { - GRExprEngine& Eng; + ExprEngine& Eng; llvm::SmallSet<SymbolRef, 10> NotableSymbols; public: - GRBugReporter(BugReporterData& d, GRExprEngine& eng) + GRBugReporter(BugReporterData& d, ExprEngine& 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; } + ExprEngine &getEngine() { return Eng; } /// getGraph - Get the exploded graph created by the analysis engine /// for the analyzed method or function. @@ -367,8 +368,8 @@ public: /// engine. GRStateManager &getStateManager(); - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, - BugReportEquivClass& R); + virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, + llvm::SmallVectorImpl<BugReport*> &bugReports); void addNotableSymbol(SymbolRef Sym) { NotableSymbols.insert(Sym); @@ -392,7 +393,7 @@ class BugReporterContext { llvm::ImmutableList<BugReporterVisitor*> Callbacks; llvm::FoldingSet<BugReporterVisitor> CallbacksSet; public: - BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.GetEmptyList()) {} + BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {} virtual ~BugReporterContext(); void addVisitor(BugReporterVisitor* visitor); @@ -419,8 +420,8 @@ public: return BR.getStateManager(); } - ValueManager& getValueManager() { - return getStateManager().getValueManager(); + SValBuilder& getSValBuilder() { + return getStateManager().getSValBuilder(); } ASTContext& getASTContext() { @@ -478,6 +479,8 @@ void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt, //===----------------------------------------------------------------------===// +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index afc07c89e86f..2793284e298f 100644 --- a/include/clang/Checker/BugReporter/BugType.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -14,14 +14,16 @@ #ifndef LLVM_CLANG_ANALYSIS_BUGTYPE #define LLVM_CLANG_ANALYSIS_BUGTYPE -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "llvm/ADT/FoldingSet.h" #include <string> namespace clang { +namespace ento { + class ExplodedNode; -class GRExprEngine; +class ExprEngine; class BugType { private: @@ -68,5 +70,7 @@ public: llvm::StringRef getDescription() const { return desc; } }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 24c75ce7b228..6d53c097d29f 100644 --- a/include/clang/Checker/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -27,6 +27,8 @@ class Decl; class SourceManager; class Stmt; +namespace ento { + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// @@ -490,5 +492,9 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const; }; + +} // end GR namespace + } //end clang namespace + #endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h new file mode 100644 index 000000000000..65c8b80aa2a8 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -0,0 +1,109 @@ +//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H +#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include <vector> + +namespace clang { + class Decl; + +namespace ento { + class ExprEngine; + class AnalysisManager; + class BugReporter; + +class CheckerManager { +public: + ~CheckerManager(); + + typedef void *CheckerRef; + +//===----------------------------------------------------------------------===// +// registerChecker +//===----------------------------------------------------------------------===// + + /// \brief Used to register checkers. + template <typename CHECKER> + void registerChecker() { + CHECKER *checker = new CHECKER(); + Checkers.push_back(std::pair<CheckerRef, Dtor>(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + } + + typedef void (*RegisterToEngFunc)(ExprEngine &Eng); + void addCheckerRegisterFunction(RegisterToEngFunc fn) { + Funcs.push_back(fn); + } + +//===----------------------------------------------------------------------===// +// Functions for running checkers. +//===----------------------------------------------------------------------===// + + /// \brief Run checkers handling Decls. + void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + + /// \brief Run checkers handling Decls containing a Stmt body. + void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + +//===----------------------------------------------------------------------===// +// Internal registration functions. +//===----------------------------------------------------------------------===// + + // Functions used by the registration mechanism, checkers should not touch + // these directly. + + typedef void (*CheckDeclFunc)(CheckerRef checker, const Decl *D, + AnalysisManager& mgr, BugReporter &BR); + typedef bool (*HandlesDeclFunc)(const Decl *D); + void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn, + HandlesDeclFunc isForDeclFn); + + void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn); + + void registerCheckersToEngine(ExprEngine &eng); + +private: + template <typename CHECKER> + static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } + + std::vector<RegisterToEngFunc> Funcs; + + struct DeclCheckerInfo { + CheckerRef Checker; + CheckDeclFunc CheckFn; + HandlesDeclFunc IsForDeclFn; + }; + std::vector<DeclCheckerInfo> DeclCheckers; + + std::vector<std::pair<CheckerRef, CheckDeclFunc> > BodyCheckers; + + typedef void (*Dtor)(void *); + std::vector<std::pair<CheckerRef, Dtor> > Checkers; + + typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4> + CachedDeclCheckers; + typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy; + CachedDeclCheckersMapTy CachedDeclCheckersMap; +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h new file mode 100644 index 000000000000..414ad92b2a5a --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerProvider.h @@ -0,0 +1,54 @@ +//===--- CheckerProvider.h - Static Analyzer Checkers Provider --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Provider. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H +#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H + +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { + +namespace ento { + class CheckerManager; + +class CheckerOptInfo { + const char *Name; + bool Enable; + bool Claimed; + +public: + CheckerOptInfo(const char *name, bool enable) + : Name(name), Enable(enable), Claimed(false) { } + + const char *getName() const { return Name; } + bool isEnabled() const { return Enable; } + bool isDisabled() const { return !isEnabled(); } + + bool isClaimed() const { return Claimed; } + bool isUnclaimed() const { return !isClaimed(); } + void claim() { Claimed = true; } +}; + +class CheckerProvider { +public: + virtual ~CheckerProvider(); + virtual void registerCheckers(CheckerManager &checkerMgr, + CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0; +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h new file mode 100644 index 000000000000..8c96866f1c99 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -0,0 +1,93 @@ +//== CheckerV2.h - Registration mechanism 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 CheckerV2, used to create and register checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_CHECKERV2 +#define LLVM_CLANG_SA_CORE_CHECKERV2 + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "llvm/Support/Casting.h" + +namespace clang { +namespace ento { + class BugReporter; + +namespace check { + +struct _VoidCheck { + static void _register(void *checker, CheckerManager &mgr) { } +}; + +template <typename DECL> +class ASTDecl { + template <typename CHECKER> + static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR); + } + + static bool _handlesDecl(const Decl *D) { + return llvm::isa<DECL>(D); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl); + } +}; + +class ASTCodeBody { + template <typename CHECKER> + static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBody(checker, _checkBody<CHECKER>); + } +}; + +} // end check namespace + +template <typename CHECK1, typename CHECK2=check::_VoidCheck, + typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck, + typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck, + typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck, + typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck, + typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck> +class CheckerV2 { +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + CHECK1::_register(checker, mgr); + CHECK2::_register(checker, mgr); + CHECK3::_register(checker, mgr); + CHECK4::_register(checker, mgr); + CHECK5::_register(checker, mgr); + CHECK6::_register(checker, mgr); + CHECK7::_register(checker, mgr); + CHECK8::_register(checker, mgr); + CHECK9::_register(checker, mgr); + CHECK10::_register(checker, mgr); + CHECK11::_register(checker, mgr); + CHECK12::_register(checker, mgr); + } +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h index d3aa3b211433..2713e31fc0d1 100644 --- a/include/clang/Checker/PathDiagnosticClients.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h @@ -11,22 +11,32 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CHECKER_PATH_DIAGNOSTIC_CLIENTS_H -#define LLVM_CLANG_CHECKER_PATH_DIAGNOSTIC_CLiENTS_H +#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H +#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLiENTS_H #include <string> namespace clang { -class PathDiagnosticClient; class Preprocessor; +namespace ento { + +class PathDiagnosticClient; + PathDiagnosticClient* -CreateHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP); +createHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP); PathDiagnosticClient* -CreatePlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP, +createPlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP, PathDiagnosticClient *SubPD = 0); +PathDiagnosticClient* +createTextPathDiagnosticClient(const std::string& prefix, + const Preprocessor &PP); + +} // end GR namespace + } // end clang namespace + #endif diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 38550798b812..1ba038e6da2d 100644 --- a/include/clang/Checker/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -12,12 +12,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H -#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H +#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H +#define LLVM_CLANG_GR_ANALYSISMANAGER_H #include "clang/Analysis/AnalysisContext.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" namespace clang { @@ -26,6 +26,9 @@ namespace idx { class TranslationUnit; } +namespace ento { + class CheckerManager; + class AnalysisManager : public BugReporterData { AnalysisContextManager AnaCtxMgr; LocationContextManager LocCtxMgr; @@ -40,6 +43,8 @@ class AnalysisManager : public BugReporterData { StoreManagerCreator CreateStoreMgr; ConstraintManagerCreator CreateConstraintMgr; + CheckerManager *CheckerMgr; + /// \brief Provide function definitions in other translation units. This is /// NULL if we don't have multiple translation units. AnalysisManager does /// not own the Indexer. @@ -50,8 +55,8 @@ class AnalysisManager : public BugReporterData { // The maximum number of exploded nodes the analyzer will generate. unsigned MaxNodes; - // The maximum number of times the analyzer will go through a loop. - unsigned MaxLoop; + // The maximum number of times the analyzer visit a block. + unsigned MaxVisit; bool VisualizeEGDot; bool VisualizeEGUbi; @@ -67,23 +72,29 @@ class AnalysisManager : public BugReporterData { bool EagerlyAssume; bool TrimGraph; bool InlineCall; + bool EagerlyTrimEGraph; public: AnalysisManager(ASTContext &ctx, Diagnostic &diags, const LangOptions &lang, PathDiagnosticClient *pd, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, + CheckerManager *checkerMgr, idx::Indexer *idxer, - unsigned maxnodes, unsigned maxloop, + unsigned maxnodes, unsigned maxvisit, bool vizdot, bool vizubi, bool purge, bool eager, bool trim, - bool inlinecall, bool useUnoptimizedCFG) - - : AnaCtxMgr(useUnoptimizedCFG), Ctx(ctx), Diags(diags), LangInfo(lang), - PD(pd), - CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),Idxer(idxer), - AScope(ScopeDecl), MaxNodes(maxnodes), MaxLoop(maxloop), + bool inlinecall, bool useUnoptimizedCFG, + bool addImplicitDtors, bool addInitializers, + bool eagerlyTrimEGraph) + + : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers), + Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + CheckerMgr(checkerMgr), Idxer(idxer), + AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), - EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {} + EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall), + EagerlyTrimEGraph(eagerlyTrimEGraph) {} ~AnalysisManager() { FlushDiagnostics(); } @@ -104,6 +115,8 @@ public: return CreateConstraintMgr; } + CheckerManager *getCheckerManager() const { return CheckerMgr; } + idx::Indexer *getIndexer() const { return Idxer; } virtual ASTContext &getASTContext() { @@ -133,7 +146,7 @@ public: unsigned getMaxNodes() const { return MaxNodes; } - unsigned getMaxLoop() const { return MaxLoop; } + unsigned getMaxVisit() const { return MaxVisit; } bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } @@ -143,6 +156,8 @@ public: return VisualizeEGDot || VisualizeEGUbi; } + bool shouldEagerlyTrimExplodedGraph() const { return EagerlyTrimEGraph; } + bool shouldTrimGraph() const { return TrimGraph; } bool shouldPurgeDead() const { return PurgeDead; } @@ -153,7 +168,7 @@ public: bool hasIndexer() const { return Idxer != 0; } - const AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D); + AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D); CFG *getCFG(Decl const *D) { return AnaCtxMgr.getContext(D)->getCFG(); @@ -177,8 +192,8 @@ public: const StackFrameContext *getStackFrame(AnalysisContext *Ctx, LocationContext const *Parent, - Stmt const *S, const CFGBlock *Blk, - unsigned Idx) { + const Stmt *S, + const CFGBlock *Blk, unsigned Idx) { return LocCtxMgr.getStackFrame(Ctx, Parent, S, Blk, Idx); } @@ -189,14 +204,17 @@ public: } // Get a stack frame with parent. - StackFrameContext const *getStackFrame(Decl const *D, + StackFrameContext const *getStackFrame(const Decl *D, LocationContext const *Parent, - Stmt const *S, const CFGBlock *Blk, - unsigned Idx) { - return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S, Blk,Idx); + const Stmt *S, + const CFGBlock *Blk, unsigned Idx) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S, + Blk,Idx); } }; -} +} // end GR namespace + +} // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 59dd9190d25e..a4327e127f5f 100644 --- a/include/clang/Checker/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -8,15 +8,15 @@ //===----------------------------------------------------------------------===// // // 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 ExprEngine // and related classes. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H -#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H +#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H +#define LLVM_CLANG_GR_BASICVALUEFACTORY_H -#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/APSInt.h" @@ -24,6 +24,8 @@ namespace clang { +namespace ento { + class GRState; class CompoundValData : public llvm::FoldingSetNode { @@ -102,9 +104,9 @@ public: } const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { - assert(T->isIntegerType() || Loc::IsLocType(T)); + assert(T->isIntegerType() || Loc::isLocType(T)); unsigned bitwidth = Ctx.getTypeSize(T); - bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T); if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) return From; @@ -126,14 +128,14 @@ public: } inline const llvm::APSInt& getMaxValue(QualType T) { - assert(T->isIntegerType() || Loc::IsLocType(T)); - bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + assert(T->isIntegerType() || Loc::isLocType(T)); + 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); + assert(T->isIntegerType() || Loc::isLocType(T)); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T); return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); } @@ -162,7 +164,7 @@ public: } inline const llvm::APSInt& getTruthValue(bool b) { - return getTruthValue(b, Ctx.IntTy); + return getTruthValue(b, Ctx.getLogicalOperationType()); } const CompoundValData *getCompoundValData(QualType T, @@ -172,14 +174,14 @@ public: const TypedRegion *region); llvm::ImmutableList<SVal> getEmptySValList() { - return SValListFactory.GetEmptyList(); + return SValListFactory.getEmptyList(); } llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { - return SValListFactory.Add(X, L); + return SValListFactory.add(X, L); } - const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt& V1, const llvm::APSInt& V2); @@ -192,6 +194,8 @@ public: const SVal* getPersistentSVal(SVal X); }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/GRBlockCounter.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h index b7d0e8ae0c71..7d0fdfb5f11f 100644 --- a/include/clang/Checker/PathSensitive/GRBlockCounter.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h @@ -1,4 +1,4 @@ -//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// +//==- BlockCounter.h - ADT for counting block visits ---------------*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// // -// This file defines GRBlockCounter, an abstract data type used to count +// This file defines BlockCounter, an abstract data type used to count // the number of times a given block has been visited along a path -// analyzed by GRCoreEngine. +// analyzed by CoreEngine. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER -#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER +#ifndef LLVM_CLANG_GR_BLOCKCOUNTER +#define LLVM_CLANG_GR_BLOCKCOUNTER namespace llvm { class BumpPtrAllocator; @@ -24,13 +24,15 @@ namespace clang { class StackFrameContext; -class GRBlockCounter { +namespace ento { + +class BlockCounter { void* Data; - GRBlockCounter(void* D) : Data(D) {} + BlockCounter(void* D) : Data(D) {} public: - GRBlockCounter() : Data(0) {} + BlockCounter() : Data(0) {} unsigned getNumVisited(const StackFrameContext *CallSite, unsigned BlockID) const; @@ -41,8 +43,8 @@ public: Factory(llvm::BumpPtrAllocator& Alloc); ~Factory(); - GRBlockCounter GetEmptyCounter(); - GRBlockCounter IncrementCount(GRBlockCounter BC, + BlockCounter GetEmptyCounter(); + BlockCounter IncrementCount(BlockCounter BC, const StackFrameContext *CallSite, unsigned BlockID); }; @@ -50,6 +52,8 @@ public: friend class Factory; }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h index 136a29da5f2a..22c202749ba7 100644 --- a/include/clang/Checker/PathSensitive/Checker.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_CHECKER -#define LLVM_CLANG_ANALYSIS_CHECKER +#ifndef LLVM_CLANG_GR_CHECKER +#define LLVM_CLANG_GR_CHECKER #include "clang/Analysis/Support/SaveAndRestore.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" //===----------------------------------------------------------------------===// // Checker interface. @@ -24,13 +24,15 @@ namespace clang { +namespace ento { + class CheckerContext { ExplodedNodeSet &Dst; - GRStmtNodeBuilder &B; - GRExprEngine &Eng; + StmtNodeBuilder &B; + ExprEngine &Eng; ExplodedNode *Pred; SaveAndRestore<bool> OldSink; - SaveAndRestore<const void*> OldTag; + const void *checkerTag; SaveAndRestore<ProgramPoint::Kind> OldPointKind; SaveOr OldHasGen; const GRState *ST; @@ -39,22 +41,22 @@ class CheckerContext { public: bool *respondsToCallback; public: - CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, - GRExprEngine &eng, ExplodedNode *pred, + CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder, + ExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, bool *respondsToCB = 0, const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), OldSink(B.BuildSinks), - OldTag(B.Tag, tag), + checkerTag(tag), OldPointKind(B.PointKind, K), - OldHasGen(B.HasGeneratedNode), + OldHasGen(B.hasGeneratedNode), ST(st), statement(stmt), size(Dst.size()), respondsToCallback(respondsToCB) {} ~CheckerContext(); - GRExprEngine &getEngine() { + ExprEngine &getEngine() { return Eng; } @@ -71,7 +73,7 @@ public: } ExplodedNodeSet &getNodeSet() { return Dst; } - GRStmtNodeBuilder &getNodeBuilder() { return B; } + StmtNodeBuilder &getNodeBuilder() { return B; } ExplodedNode *&getPredecessor() { return Pred; } const GRState *getState() { return ST ? ST : B.GetState(Pred); } @@ -87,80 +89,74 @@ public: return getBugReporter().getSourceManager(); } - ValueManager &getValueManager() { - return Eng.getValueManager(); - } - - SValuator &getSValuator() { - return Eng.getSValuator(); + SValBuilder &getSValBuilder() { + return Eng.getSValBuilder(); } - ExplodedNode *GenerateNode(bool autoTransition = true) { + ExplodedNode *generateNode(bool autoTransition = true) { assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); + ExplodedNode *N = generateNodeImpl(statement, getState(), false, + checkerTag); if (N && autoTransition) Dst.Add(N); return N; } - ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, - bool autoTransition = true) { + ExplodedNode *generateNode(const Stmt *stmt, const GRState *state, + bool autoTransition = true, const void *tag = 0) { assert(state); - ExplodedNode *N = GenerateNodeImpl(stmt, state, false); + ExplodedNode *N = generateNodeImpl(stmt, state, false, + tag ? tag : checkerTag); if (N && autoTransition) addTransition(N); return N; } - ExplodedNode *GenerateNode(const GRState *state, ExplodedNode *pred, + ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred, bool autoTransition = true) { assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, state, pred, false); + ExplodedNode *N = generateNodeImpl(statement, state, pred, false); if (N && autoTransition) addTransition(N); return N; } - ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { + ExplodedNode *generateNode(const GRState *state, bool autoTransition = true, + const void *tag = 0) { assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, state, false); + ExplodedNode *N = generateNodeImpl(statement, state, false, + tag ? tag : checkerTag); if (N && autoTransition) addTransition(N); return N; } - ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { - return GenerateNodeImpl(stmt, state ? state : getState(), true); + ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) { + return generateNodeImpl(stmt, state ? state : getState(), true, + checkerTag); } - ExplodedNode *GenerateSink(const GRState *state = 0) { + ExplodedNode *generateSink(const GRState *state = 0) { assert(statement && "Only transitions with statements currently supported"); - return GenerateNodeImpl(statement, state ? state : getState(), true); + return generateNodeImpl(statement, state ? state : getState(), true, + checkerTag); } void addTransition(ExplodedNode *node) { Dst.Add(node); } - void addTransition(const GRState *state) { + void addTransition(const GRState *state, const void *tag = 0) { assert(state); // If the 'state' is not new, we need to check if the cached state 'ST' // is new. if (state != getState() || (ST && ST != B.GetState(Pred))) // state is new or equals to ST. - GenerateNode(state, true); + generateNode(state, true, tag); else Dst.Add(Pred); } - // Generate a node with a new program point different from the one that will - // be created by the GRStmtNodeBuilder. - void addTransition(const GRState *state, ProgramPoint Loc) { - ExplodedNode *N = B.generateNode(Loc, state, Pred); - if (N) - addTransition(N); - } - void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } @@ -170,17 +166,17 @@ public: } private: - ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, - bool markAsSink) { - ExplodedNode *node = B.generateNode(stmt, state, Pred); + ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, + bool markAsSink, const void *tag) { + ExplodedNode *node = B.generateNode(stmt, state, Pred, tag); if (markAsSink && node) node->markAsSink(); return node; } - ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state, ExplodedNode *pred, bool markAsSink) { - ExplodedNode *node = B.generateNode(stmt, state, pred); + ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag); if (markAsSink && node) node->markAsSink(); return node; @@ -189,12 +185,12 @@ private: class Checker { private: - friend class GRExprEngine; + friend class ExprEngine; // FIXME: Remove the 'tag' option. void GR_Visit(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, + StmtNodeBuilder &Builder, + ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, void *tag, bool isPrevisit, bool& respondsToCallback) { @@ -207,25 +203,39 @@ private: _PostVisit(C, S); } - bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const ObjCMessageExpr *ME, + void GR_visitObjCMessage(ExplodedNodeSet &Dst, + StmtNodeBuilder &Builder, + ExprEngine &Eng, + const ObjCMessage &msg, + ExplodedNode *Pred, void *tag, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + isPrevisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind, 0, msg.getOriginExpr()); + if (isPrevisit) + preVisitObjCMessage(C, msg); + else + postVisitObjCMessage(C, msg); + } + + bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, + ExprEngine &Eng, const ObjCMessage &msg, ExplodedNode *Pred, const GRState *state, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - 0, ME, state); - return EvalNilReceiver(C, ME); + 0, msg.getOriginExpr(), state); + return evalNilReceiver(C, msg); } - bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const CallExpr *CE, + bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, + ExprEngine &Eng, const CallExpr *CE, ExplodedNode *Pred, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, 0, CE); - return EvalCallExpr(C, CE); + return evalCallExpr(C, CE); } // FIXME: Remove the 'tag' option. void GR_VisitBind(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, GRExprEngine &Eng, + StmtNodeBuilder &Builder, ExprEngine &Eng, const Stmt *StoreE, ExplodedNode *Pred, void *tag, SVal location, SVal val, bool isPrevisit) { @@ -237,9 +247,9 @@ private: } // FIXME: Remove the 'tag' option. - void GR_VisitLocation(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, + void GR_visitLocation(ExplodedNodeSet &Dst, + StmtNodeBuilder &Builder, + ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, const GRState *state, SVal location, @@ -247,49 +257,52 @@ private: CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : ProgramPoint::PreStoreKind, 0, S, state); - VisitLocation(C, S, location); + visitLocation(C, S, location, isLoad); } - void GR_EvalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, + void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder, + ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostPurgeDeadSymbolsKind, 0, S); - EvalDeadSymbols(C, SymReaper); + evalDeadSymbols(C, SymReaper); } public: virtual ~Checker(); virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} - virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} + virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} + virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {} + virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location, + bool isLoad) {} virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, SVal location, SVal val) {} - virtual void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {} - virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) {} + virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {} + virtual void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, + ExprEngine &Eng) {} virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {} - virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, - GRExprEngine &Eng, + virtual void VisitBranchCondition(BranchNodeBuilder &Builder, + ExprEngine &Eng, const Stmt *Condition, void *tag) {} - virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) { + virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) { return false; } - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) { return false; } - virtual const GRState *EvalAssume(const GRState *state, SVal Cond, + virtual const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption, bool *respondsToCallback) { *respondsToCallback = false; return state; } - virtual bool WantsRegionChangeUpdate(const GRState *state) { return false; } + virtual bool wantsRegionChangeUpdate(const GRState *state) { return false; } virtual const GRState *EvalRegionChanges(const GRState *state, const MemRegion * const *Begin, @@ -300,8 +313,11 @@ public: } virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - GRExprEngine &Eng) {} + ExprEngine &Eng) {} }; + +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h index ea3c842ffc1f..12547e0969a1 100644 --- a/include/clang/Checker/PathSensitive/CheckerHelpers.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h @@ -11,13 +11,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CHECKER_PATHSENSITIVE_CHECKERHELPERS -#define LLVM_CLANG_CHECKER_PATHSENSITIVE_CHECKERHELPERS +#ifndef LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS +#define LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS #include "clang/AST/Stmt.h" namespace clang { +namespace ento { + bool containsMacro(const Stmt *S); bool containsEnum(const Stmt *S); bool containsStaticLocal(const Stmt *S); @@ -26,8 +28,7 @@ template <class T> bool containsStmt(const Stmt *S) { if (isa<T>(S)) return true; - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) + for (Stmt::const_child_range I = S->children(); I; ++I) if (const Stmt *child = *I) if (containsStmt<T>(child)) return true; @@ -35,6 +36,8 @@ template <class T> bool containsStmt(const Stmt *S) { return false; } -} +} // end GR namespace + +} // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.def b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def index 2edc4a37b7eb..9b3c263e7d53 100644 --- a/include/clang/Checker/PathSensitive/CheckerVisitor.def +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def @@ -21,17 +21,28 @@ PREVISIT(ArraySubscriptExpr, Stmt) PREVISIT(BinaryOperator, Stmt) -PREVISIT(CallExpr, Stmt) -PREVISIT(CXXOperatorCallExpr, CallExpr) +PREVISIT(CallExpr, GenericCall) +PREVISIT(CompoundAssignOperator, BinaryOperator) +PREVISIT(CStyleCastExpr, CastExpr) +PREVISIT(CXXConstCastExpr, CastExpr) +PREVISIT(CXXDynamicCastExpr, CastExpr) +PREVISIT(CXXFunctionalCastExpr, CastExpr) +PREVISIT(CXXOperatorCallExpr, GenericCall) +PREVISIT(CXXMemberCallExpr, GenericCall) +PREVISIT(CXXReinterpretCastExpr, CastExpr) +PREVISIT(CXXStaticCastExpr, CastExpr) PREVISIT(DeclStmt, Stmt) -PREVISIT(ObjCMessageExpr, Stmt) +PREVISIT(ImplicitCastExpr, CastExpr) +PREVISIT(ObjCAtSynchronizedStmt, Stmt) PREVISIT(ReturnStmt, Stmt) POSTVISIT(BlockExpr, Stmt) POSTVISIT(BinaryOperator, Stmt) -POSTVISIT(CallExpr, Stmt) -POSTVISIT(CXXOperatorCallExpr, CallExpr) -POSTVISIT(ObjCMessageExpr, Stmt) +POSTVISIT(CallExpr, GenericCall) +POSTVISIT(CompoundAssignOperator, BinaryOperator) +POSTVISIT(CXXOperatorCallExpr, GenericCall) +POSTVISIT(CXXMemberCallExpr, GenericCall) +POSTVISIT(ObjCIvarRefExpr, Stmt) #undef PREVISIT #undef POSTVISIT diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h index e2ba89bca1b8..dc76c9604741 100644 --- a/include/clang/Checker/PathSensitive/CheckerVisitor.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h @@ -11,12 +11,14 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR -#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR -#include "clang/Checker/PathSensitive/Checker.h" +#ifndef LLVM_CLANG_GR_CHECKERVISITOR +#define LLVM_CLANG_GR_CHECKERVISITOR +#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" namespace clang { +namespace ento { + //===----------------------------------------------------------------------===// // Checker visitor interface. Used by subclasses of Checker to specify their // own checker visitor logic. @@ -41,22 +43,11 @@ public: assert(false && "Unsupport statement."); return; - case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: - static_cast<ImplClass*>(this)->PreVisitCastExpr(C, - static_cast<const CastExpr*>(S)); - break; - - case Stmt::CompoundAssignOperatorClass: - static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C, - static_cast<const BinaryOperator*>(S)); - break; - #define PREVISIT(NAME, FALLBACK) \ case Stmt::NAME ## Class:\ static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\ break; -#include "clang/Checker/PathSensitive/CheckerVisitor.def" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" } } @@ -65,20 +56,23 @@ break; default: assert(false && "Unsupport statement."); return; - case Stmt::CompoundAssignOperatorClass: - static_cast<ImplClass*>(this)->PostVisitBinaryOperator(C, - static_cast<const BinaryOperator*>(S)); - break; #define POSTVISIT(NAME, FALLBACK) \ case Stmt::NAME ## Class:\ static_cast<ImplClass*>(this)->\ PostVisit ## NAME(C,static_cast<const NAME*>(S));\ break; -#include "clang/Checker/PathSensitive/CheckerVisitor.def" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" } } + void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE) { + static_cast<ImplClass*>(this)->PreVisitStmt(C, CE); + } + void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE) { + static_cast<ImplClass*>(this)->PostVisitStmt(C, CE); + } + void PreVisitStmt(CheckerContext &C, const Stmt *S) { *C.respondsToCallback = false; } @@ -99,9 +93,11 @@ void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\ void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\ static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\ } -#include "clang/Checker/PathSensitive/CheckerVisitor.def" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def" }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index 97535f55bfb9..199b41afefae 100644 --- a/include/clang/Checker/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H -#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H +#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H +#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H // FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place. -#include "clang/Checker/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" namespace llvm { class APSInt; @@ -23,21 +23,23 @@ class APSInt; namespace clang { +namespace ento { + class GRState; class GRStateManager; -class GRSubEngine; +class SubEngine; class SVal; class ConstraintManager { public: virtual ~ConstraintManager(); - virtual const GRState *Assume(const GRState *state, DefinedSVal Cond, + virtual const GRState *assume(const GRState *state, DefinedSVal Cond, bool Assumption) = 0; - std::pair<const GRState*, const GRState*> AssumeDual(const GRState *state, + std::pair<const GRState*, const GRState*> assumeDual(const GRState *state, DefinedSVal Cond) { - return std::make_pair(Assume(state, Cond, true), - Assume(state, Cond, false)); + return std::make_pair(assume(state, Cond, true), + assume(state, Cond, false)); } virtual const llvm::APSInt* getSymVal(const GRState *state, @@ -46,7 +48,7 @@ public: virtual bool isEqual(const GRState *state, SymbolRef sym, const llvm::APSInt& V) const = 0; - virtual const GRState *RemoveDeadBindings(const GRState *state, + virtual const GRState *removeDeadBindings(const GRState *state, SymbolReaper& SymReaper) = 0; virtual void print(const GRState *state, llvm::raw_ostream& Out, @@ -57,15 +59,17 @@ public: /// 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 - /// GRExprEngine to determine if the value should be replaced with a + /// ExprEngine to determine if the value should be replaced with a /// conjured symbolic value in order to recover some precision. virtual bool canReasonAbout(SVal X) const = 0; }; ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr, - GRSubEngine &subengine); + SubEngine &subengine); ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr, - GRSubEngine &subengine); + SubEngine &subengine); + +} // end GR namespace } // end clang namespace diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 216ecac73653..800e63a4cdeb 100644 --- a/include/clang/Checker/PathSensitive/GRCoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -1,4 +1,4 @@ -//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-// +//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -12,43 +12,45 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GRENGINE -#define LLVM_CLANG_ANALYSIS_GRENGINE +#ifndef LLVM_CLANG_GR_COREENGINE +#define LLVM_CLANG_GR_COREENGINE #include "clang/AST/Expr.h" -#include "clang/Checker/PathSensitive/ExplodedGraph.h" -#include "clang/Checker/PathSensitive/GRWorkList.h" -#include "clang/Checker/PathSensitive/GRBlockCounter.h" -#include "clang/Checker/PathSensitive/GRAuditor.h" -#include "clang/Checker/PathSensitive/GRSubEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "llvm/ADT/OwningPtr.h" namespace clang { +namespace ento { + //===----------------------------------------------------------------------===// -/// GRCoreEngine - Implements the core logic of the graph-reachability +/// CoreEngine - 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 GRCoreEngine) +/// The template class CoreEngine (which subclasses CoreEngine) /// 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 GRCoreEngine { - friend class GRStmtNodeBuilder; - friend class GRBranchNodeBuilder; - friend class GRIndirectGotoNodeBuilder; - friend class GRSwitchNodeBuilder; - friend class GREndPathNodeBuilder; - friend class GRCallEnterNodeBuilder; - friend class GRCallExitNodeBuilder; +class CoreEngine { + friend class StmtNodeBuilder; + friend class GenericNodeBuilderImpl; + friend class BranchNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; + friend class CallEnterNodeBuilder; + friend class CallExitNodeBuilder; public: typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > BlocksAborted; private: - GRSubEngine& SubEngine; + SubEngine& SubEng; /// G - The simulation graph. Each node is a (location,state) pair. llvm::OwningPtr<ExplodedGraph> G; @@ -56,25 +58,24 @@ private: /// 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; + WorkList* WList; - /// BCounterFactory - A factory object for created GRBlockCounter objects. + /// BCounterFactory - A factory object for created BlockCounter 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; + BlockCounter::Factory BCounterFactory; /// The locations where we stopped doing work because we visited a location /// too many times. BlocksAborted blocksAborted; - void GenerateNode(const ProgramPoint& Loc, const GRState* State, + 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(const CFGBlock* B, ExplodedNode* Pred); - void HandlePostStmt(const PostStmt& S, const CFGBlock* B, - unsigned StmtIdx, ExplodedNode *Pred); + void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred); void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B, ExplodedNode* Pred); @@ -82,68 +83,26 @@ private: unsigned Index, ExplodedNode *Pred); void HandleCallExit(const CallExit &L, ExplodedNode *Pred); - /// Get the initial state from the subengine. - const GRState* getInitialState(const LocationContext *InitLoc) { - return SubEngine.getInitialState(InitLoc); - } - - void ProcessEndPath(GREndPathNodeBuilder& Builder) { - SubEngine.ProcessEndPath(Builder); - } - - void ProcessStmt(const CFGElement E, GRStmtNodeBuilder& Builder) { - SubEngine.ProcessStmt(E, Builder); - } - - bool ProcessBlockEntrance(const CFGBlock* Blk, const ExplodedNode *Pred, - GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, Pred, BC); - } - - - void ProcessBranch(const Stmt* Condition, const Stmt* Terminator, - GRBranchNodeBuilder& Builder) { - SubEngine.ProcessBranch(Condition, Terminator, Builder); - } - - - void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder) { - SubEngine.ProcessIndirectGoto(Builder); - } - - - void ProcessSwitch(GRSwitchNodeBuilder& Builder) { - SubEngine.ProcessSwitch(Builder); - } - - void ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { - SubEngine.ProcessCallEnter(Builder); - } - - void ProcessCallExit(GRCallExitNodeBuilder &Builder) { - SubEngine.ProcessCallExit(Builder); - } - private: - GRCoreEngine(const GRCoreEngine&); // Do not implement. - GRCoreEngine& operator=(const GRCoreEngine&); + CoreEngine(const CoreEngine&); // Do not implement. + CoreEngine& operator=(const CoreEngine&); public: - /// Construct a GRCoreEngine object to analyze the provided CFG using + /// Construct a CoreEngine object to analyze the provided CFG using /// a DFS exploration of the exploded graph. - GRCoreEngine(GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph()), - WList(GRWorkList::MakeBFS()), + CoreEngine(SubEngine& subengine) + : SubEng(subengine), G(new ExplodedGraph()), + WList(WorkList::makeBFS()), BCounterFactory(G->getAllocator()) {} - /// Construct a GRCoreEngine object to analyze the provided CFG and to + /// Construct a CoreEngine 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(GRWorkList* wlist, GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph()), WList(wlist), + /// The CoreEngine object assumes ownership of 'wlist'. + CoreEngine(WorkList* wlist, SubEngine& subengine) + : SubEng(subengine), G(new ExplodedGraph()), WList(wlist), BCounterFactory(G->getAllocator()) {} - ~GRCoreEngine() { + ~CoreEngine() { delete WList; } @@ -166,7 +125,7 @@ public: bool wasBlockAborted() const { return !blocksAborted.empty(); } bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); } - GRWorkList *getWorkList() const { return WList; } + WorkList *getWorkList() const { return WList; } BlocksAborted::const_iterator blocks_aborted_begin() const { return blocksAborted.begin(); @@ -176,18 +135,17 @@ public: } }; -class GRStmtNodeBuilder { - GRCoreEngine& Eng; +class StmtNodeBuilder { + CoreEngine& Eng; const CFGBlock& B; const unsigned Idx; ExplodedNode* Pred; GRStateManager& Mgr; - GRAuditor* Auditor; public: bool PurgingDeadSymbols; bool BuildSinks; - bool HasGeneratedNode; + bool hasGeneratedNode; ProgramPoint::Kind PointKind; const void *Tag; @@ -200,21 +158,21 @@ public: void GenerateAutoTransition(ExplodedNode* N); public: - GRStmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N, - GRCoreEngine* e, GRStateManager &mgr); + StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N, + CoreEngine* e, GRStateManager &mgr); - ~GRStmtNodeBuilder(); + ~StmtNodeBuilder(); - ExplodedNode* getBasePredecessor() const { return Pred; } + ExplodedNode* getPredecessor() const { return Pred; } // FIXME: This should not be exposed. - GRWorkList *getWorkList() { return Eng.WList; } + WorkList *getWorkList() { return Eng.WList; } void SetCleanedState(const GRState* St) { CleanedState = St; } - GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} unsigned getCurrentBlockCount() const { return getBlockCounter().getNumVisited( @@ -223,28 +181,29 @@ public: } ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) { - HasGeneratedNode = true; + hasGeneratedNode = true; return generateNodeInternal(PP, St, Pred); } ExplodedNode* generateNode(const Stmt *S, const GRState *St, - ExplodedNode *Pred, ProgramPoint::Kind K) { - HasGeneratedNode = true; + ExplodedNode *Pred, ProgramPoint::Kind K, + const void *tag = 0) { + hasGeneratedNode = true; if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; - return generateNodeInternal(S, St, Pred, K, Tag); + return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag); } ExplodedNode* generateNode(const Stmt *S, const GRState *St, - ExplodedNode *Pred) { - return generateNode(S, St, Pred, PointKind); + ExplodedNode *Pred, const void *tag = 0) { + return generateNode(S, St, Pred, PointKind, tag); } ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State, ExplodedNode* Pred) { - HasGeneratedNode = true; + hasGeneratedNode = true; return generateNodeInternal(PP, State, Pred); } @@ -259,7 +218,13 @@ public: /// getStmt - Return the current block-level expression associated with /// this builder. - const Stmt* getStmt() const { return B[Idx]; } + const Stmt* getStmt() const { + CFGStmt CS = B[Idx].getAs<CFGStmt>(); + if (CS) + return CS.getStmt(); + else + return 0; + } /// getBlock - Return the CFGBlock associated with the block-level expression /// of this builder. @@ -267,10 +232,8 @@ public: unsigned getIndex() const { return Idx; } - void setAuditor(GRAuditor* A) { Auditor = A; } - const GRState* GetState(ExplodedNode* Pred) const { - if (Pred == getBasePredecessor()) + if (Pred == getPredecessor()) return CleanedState; else return Pred->getState(); @@ -294,8 +257,8 @@ public: } }; -class GRBranchNodeBuilder { - GRCoreEngine& Eng; +class BranchNodeBuilder { + CoreEngine& Eng; const CFGBlock* Src; const CFGBlock* DstT; const CFGBlock* DstF; @@ -310,19 +273,19 @@ class GRBranchNodeBuilder { bool InFeasibleFalse; public: - GRBranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT, - const CFGBlock* dstF, ExplodedNode* pred, GRCoreEngine* e) + BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT, + const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e) : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), GeneratedTrue(false), GeneratedFalse(false), InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} - ~GRBranchNodeBuilder(); + ~BranchNodeBuilder(); ExplodedNode* getPredecessor() const { return Pred; } const ExplodedGraph& getGraph() const { return *Eng.G; } - GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} ExplodedNode* generateNode(const GRState* State, bool branch); @@ -346,33 +309,33 @@ public: } }; -class GRIndirectGotoNodeBuilder { - GRCoreEngine& Eng; +class IndirectGotoNodeBuilder { + CoreEngine& Eng; const CFGBlock* Src; const CFGBlock& DispatchBlock; const Expr* E; ExplodedNode* Pred; public: - GRIndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src, - const Expr* e, const CFGBlock* dispatch, GRCoreEngine* eng) + IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src, + const Expr* e, const CFGBlock* dispatch, CoreEngine* eng) : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} class iterator { CFGBlock::const_succ_iterator I; - friend class GRIndirectGotoNodeBuilder; + friend class IndirectGotoNodeBuilder; iterator(CFGBlock::const_succ_iterator i) : I(i) {} public: iterator& operator++() { ++I; return *this; } bool operator!=(const iterator& X) const { return I != X.I; } - const LabelStmt* getLabel() const { - return llvm::cast<LabelStmt>((*I)->getLabel()); + const LabelDecl *getLabel() const { + return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl(); } - const CFGBlock* getBlock() const { + const CFGBlock *getBlock() const { return *I; } }; @@ -388,21 +351,21 @@ public: const GRState* getState() const { return Pred->State; } }; -class GRSwitchNodeBuilder { - GRCoreEngine& Eng; +class SwitchNodeBuilder { + CoreEngine& Eng; const CFGBlock* Src; const Expr* Condition; ExplodedNode* Pred; public: - GRSwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src, - const Expr* condition, GRCoreEngine* eng) + SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src, + const Expr* condition, CoreEngine* eng) : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} class iterator { CFGBlock::const_succ_reverse_iterator I; - friend class GRSwitchNodeBuilder; + friend class SwitchNodeBuilder; iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} public: @@ -422,6 +385,10 @@ public: iterator begin() { return iterator(Src->succ_rbegin()+1); } iterator end() { return iterator(Src->succ_rend()); } + const SwitchStmt *getSwitch() const { + return llvm::cast<SwitchStmt>(Src->getTerminator()); + } + ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State); ExplodedNode* generateDefaultCaseNode(const GRState* State, @@ -432,25 +399,69 @@ public: const GRState* getState() const { return Pred->State; } }; -class GREndPathNodeBuilder { - GRCoreEngine &Eng; +class GenericNodeBuilderImpl { +protected: + CoreEngine &engine; + ExplodedNode *pred; + ProgramPoint pp; + llvm::SmallVector<ExplodedNode*, 2> sinksGenerated; + + ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred, + ProgramPoint programPoint, bool asSink); + + GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p) + : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {} + +public: + bool hasGeneratedNode; + + WorkList &getWorkList() { return *engine.WList; } + + ExplodedNode* getPredecessor() const { return pred; } + + BlockCounter getBlockCounter() const { + return engine.WList->getBlockCounter(); + } + + const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const { + return sinksGenerated; + } +}; + +template <typename PP_T> +class GenericNodeBuilder : public GenericNodeBuilderImpl { +public: + GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p) + : GenericNodeBuilderImpl(eng, pr, p) {} + + ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred, + const void *tag, bool asSink) { + return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag), + asSink); + } + + const PP_T &getProgramPoint() const { return cast<PP_T>(pp); } +}; + +class EndOfFunctionNodeBuilder { + CoreEngine &Eng; const CFGBlock& B; ExplodedNode* Pred; public: - bool HasGeneratedNode; + bool hasGeneratedNode; public: - GREndPathNodeBuilder(const CFGBlock* b, ExplodedNode* N, GRCoreEngine* e) - : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e) + : Eng(*e), B(*b), Pred(N), hasGeneratedNode(false) {} - ~GREndPathNodeBuilder(); + ~EndOfFunctionNodeBuilder(); - GRWorkList &getWorkList() { return *Eng.WList; } + WorkList &getWorkList() { return *Eng.WList; } ExplodedNode* getPredecessor() const { return Pred; } - GRBlockCounter getBlockCounter() const { + BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); } @@ -472,16 +483,17 @@ public: } }; -class GRCallEnterNodeBuilder { - GRCoreEngine &Eng; +class CallEnterNodeBuilder { + CoreEngine &Eng; const ExplodedNode *Pred; - // The call site. + // The call site. For implicit automatic object dtor, this is the trigger + // statement. const Stmt *CE; - // The AnalysisContext of the callee. - AnalysisContext *CalleeCtx; + // The context of the callee. + const StackFrameContext *CalleeCtx; // The parent block of the CallExpr. const CFGBlock *Block; @@ -490,8 +502,8 @@ class GRCallEnterNodeBuilder { unsigned Index; public: - GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, - const Stmt *s, AnalysisContext *callee, + CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred, + const Stmt *s, const StackFrameContext *callee, const CFGBlock *blk, unsigned idx) : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {} @@ -503,29 +515,32 @@ public: const Stmt *getCallExpr() const { return CE; } - AnalysisContext *getCalleeContext() const { return CalleeCtx; } + const StackFrameContext *getCalleeContext() const { return CalleeCtx; } const CFGBlock *getBlock() const { return Block; } unsigned getIndex() const { return Index; } - void GenerateNode(const GRState *state, const LocationContext *LocCtx); + void generateNode(const GRState *state); }; -class GRCallExitNodeBuilder { - GRCoreEngine &Eng; +class CallExitNodeBuilder { + CoreEngine &Eng; const ExplodedNode *Pred; public: - GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) + CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred) : Eng(eng), Pred(pred) {} const ExplodedNode *getPredecessor() const { return Pred; } const GRState *getState() const { return Pred->getState(); } - void GenerateNode(const GRState *state); + void generateNode(const GRState *state); }; + +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index 611f5079452a..732a40cb2145 100644 --- a/include/clang/Checker/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -11,23 +11,25 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H -#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H +#ifndef LLVM_CLANG_GR_ENVIRONMENT_H +#define LLVM_CLANG_GR_ENVIRONMENT_H -// For using typedefs in StoreManager. Should find a better place for these -// typedefs. -#include "clang/Checker/PathSensitive/Store.h" - -#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ImmutableMap.h" namespace clang { -class EnvironmentManager; -class ValueManager; class LiveVariables; +namespace ento { + +class EnvironmentManager; +class SValBuilder; +/// Environment - An immutable map from Stmts to their current +/// symbolic values (SVals). +/// class Environment { private: friend class EnvironmentManager; @@ -41,22 +43,22 @@ private: Environment(BindingsTy eb) : ExprBindings(eb) {} + SVal lookupExpr(const Stmt* E) const; + public: 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 = ExprBindings.lookup(E); - return X ? *X : UnknownVal(); - } - SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const; + /// GetSVal - Fetches the current binding of the expression in the + /// Environment. + SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder) const; /// Profile - Profile the contents of an Environment object for use /// in a FoldingSet. - static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { - E->ExprBindings.Profile(ID); + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) { + env->ExprBindings.Profile(ID); } /// Profile - Used to profile the contents of this object for inclusion @@ -80,7 +82,7 @@ public: ~EnvironmentManager() {} Environment getInitialEnvironment() { - return Environment(F.GetEmptyMap()); + return Environment(F.getEmptyMap()); } /// Bind the value 'V' to the statement 'S'. @@ -92,11 +94,13 @@ public: Environment bindExprAndLocation(Environment Env, const Stmt *S, SVal location, SVal V); - Environment RemoveDeadBindings(Environment Env, + Environment removeDeadBindings(Environment Env, SymbolReaper &SymReaper, const GRState *ST, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index c875a2308ba3..e5d6876fa6b2 100644 --- a/include/clang/Checker/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -16,8 +16,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH -#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH +#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH +#define LLVM_CLANG_GR_EXPLODEDGRAPH #include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/AnalysisContext.h" @@ -31,11 +31,14 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/Support/Casting.h" #include "clang/Analysis/Support/BumpVector.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" namespace clang { -class GRState; class CFG; + +namespace ento { + class ExplodedGraph; //===----------------------------------------------------------------------===// @@ -44,14 +47,17 @@ class ExplodedGraph; // on top of these classes. //===----------------------------------------------------------------------===// +// ExplodedNode is not constified all over the engine because we need to add +// successors to it at any time after creating it. + 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; + friend class CoreEngine; + friend class StmtNodeBuilder; + friend class BranchNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; class NodeGroup { enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; @@ -69,7 +75,7 @@ class ExplodedNode : public llvm::FoldingSetNode { ExplodedNode *getNode() const { return reinterpret_cast<ExplodedNode*>(getPtr()); } - + public: NodeGroup() : P(0) {} @@ -83,6 +89,8 @@ class ExplodedNode : public llvm::FoldingSetNode { void addNode(ExplodedNode* N, ExplodedGraph &G); + void replaceNode(ExplodedNode *node); + void setFlag() { assert(P == 0); P = AuxFlag; @@ -109,7 +117,13 @@ class ExplodedNode : public llvm::FoldingSetNode { public: explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) - : Location(loc), State(state) {} + : Location(loc), State(state) { + const_cast<GRState*>(State)->incrementReferenceCount(); + } + + ~ExplodedNode() { + const_cast<GRState*>(State)->decrementReferenceCount(); + } /// getLocation - Returns the edge associated with the given node. ProgramPoint getLocation() const { return Location; } @@ -200,6 +214,10 @@ public: }; static void SetAuditor(Auditor* A); + +private: + void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); } + void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } }; // FIXME: Is this class necessary? @@ -216,7 +234,7 @@ public: class ExplodedGraph { protected: - friend class GRCoreEngine; + friend class CoreEngine; // Type definitions. typedef llvm::SmallVector<ExplodedNode*,2> RootsTy; @@ -241,6 +259,15 @@ protected: /// NumNodes - The number of nodes in the graph. unsigned NumNodes; + + /// A list of recently allocated nodes that can potentially be recycled. + void *recentlyAllocatedNodes; + + /// A list of nodes that can be reused. + void *freeNodes; + + /// A flag that indicates whether nodes should be recycled. + bool reclaimNodes; public: /// getNode - Retrieve the node associated with a (Location,State) pair, @@ -267,10 +294,12 @@ public: return V; } - ExplodedGraph() : NumNodes(0) {} - - ~ExplodedGraph() {} + ExplodedGraph() + : NumNodes(0), recentlyAllocatedNodes(0), + freeNodes(0), reclaimNodes(false) {} + ~ExplodedGraph(); + unsigned num_roots() const { return Roots.size(); } unsigned num_eops() const { return EndNodes.size(); } @@ -324,6 +353,14 @@ public: const ExplodedNode* const * NEnd, InterExplodedGraphMap *M, llvm::DenseMap<const void*, const void*> *InverseMap) const; + + /// Enable tracking of recently allocated nodes for potential reclamation + /// when calling reclaimRecentlyAllocatedNodes(). + void enableNodeReclamation() { reclaimNodes = true; } + + /// Reclaim "uninteresting" nodes created since the last time this method + /// was called. + void reclaimRecentlyAllocatedNodes(); }; class ExplodedNodeSet { @@ -368,13 +405,15 @@ public: inline const_iterator end() const { return Impl.end(); } }; +} // end GR namespace + } // end clang namespace // GraphTraits namespace llvm { - template<> struct GraphTraits<clang::ExplodedNode*> { - typedef clang::ExplodedNode NodeType; + template<> struct GraphTraits<clang::ento::ExplodedNode*> { + typedef clang::ento::ExplodedNode NodeType; typedef NodeType::succ_iterator ChildIteratorType; typedef llvm::df_iterator<NodeType*> nodes_iterator; @@ -399,8 +438,8 @@ namespace llvm { } }; - template<> struct GraphTraits<const clang::ExplodedNode*> { - typedef const clang::ExplodedNode NodeType; + template<> struct GraphTraits<const clang::ento::ExplodedNode*> { + typedef const clang::ento::ExplodedNode NodeType; typedef NodeType::const_succ_iterator ChildIteratorType; typedef llvm::df_iterator<NodeType*> nodes_iterator; diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 5ba0b36b315d..767644a03292 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -1,4 +1,4 @@ -//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= +//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -8,41 +8,45 @@ //===----------------------------------------------------------------------===// // // This file defines a meta-engine for path-sensitive dataflow analysis that -// is built on GRCoreEngine, but provides the boilerplate to execute transfer +// is built on CoreEngine, but provides the boilerplate to execute transfer // functions and build the ExplodedGraph at the expression level. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE -#define LLVM_CLANG_ANALYSIS_GREXPRENGINE +#ifndef LLVM_CLANG_GR_EXPRENGINE +#define LLVM_CLANG_GR_EXPRENGINE -#include "clang/Checker/PathSensitive/AnalysisManager.h" -#include "clang/Checker/PathSensitive/GRSubEngine.h" -#include "clang/Checker/PathSensitive/GRCoreEngine.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h" -#include "clang/Checker/PathSensitive/GRTransferFuncs.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/Type.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtObjC.h" namespace clang { + +class ObjCForCollectionStmt; + +namespace ento { + class AnalysisManager; class Checker; -class ObjCForCollectionStmt; -class GRExprEngine : public GRSubEngine { +class ExprEngine : public SubEngine { AnalysisManager &AMgr; - GRCoreEngine CoreEngine; + CoreEngine Engine; /// G - the simulation graph. ExplodedGraph& G; - /// Builder - The current GRStmtNodeBuilder which is used when building the + /// Builder - The current StmtNodeBuilder which is used when building the /// nodes for a given statement. - GRStmtNodeBuilder* Builder; + StmtNodeBuilder* Builder; /// StateMgr - Object that manages the data for all created states. GRStateManager StateMgr; @@ -50,11 +54,8 @@ class GRExprEngine : public GRSubEngine { /// 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. - SValuator &SVator; + /// svalBuilder - SValBuilder object that creates SVals from expressions. + SValBuilder &svalBuilder; /// EntryNode - The immediate predecessor node. ExplodedNode* EntryNode; @@ -63,8 +64,8 @@ class GRExprEngine : public GRSubEngine { /// variables and symbols (as determined by a liveness analysis). const GRState* CleanedState; - /// CurrentStmt - The current block-level statement. - const Stmt* CurrentStmt; + /// currentStmt - The current block-level statement. + const Stmt* currentStmt; // Obj-C Class Identifiers. IdentifierInfo* NSExceptionII; @@ -73,12 +74,10 @@ class GRExprEngine : public GRSubEngine { Selector* NSExceptionInstanceRaiseSelectors; Selector RaiseSel; - llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; - enum CallbackKind { PreVisitStmtCallback, PostVisitStmtCallback, - ProcessAssumeCallback, + processAssumeCallback, EvalRegionChangesCallback }; @@ -110,27 +109,18 @@ class GRExprEngine : public GRSubEngine { /// 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. + /// destructor is called before the rest of the ExprEngine is destroyed. GRBugReporter BR; - llvm::OwningPtr<GRTransferFuncs> TF; - - class CallExprWLItem { - public: - CallExpr::const_arg_iterator I; - ExplodedNode *N; - - CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} - }; + llvm::OwningPtr<TransferFuncs> TF; public: - GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf); + ExprEngine(AnalysisManager &mgr, TransferFuncs *tf); - ~GRExprEngine(); + ~ExprEngine(); void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { - CoreEngine.ExecuteWorkList(L, Steps, 0); + Engine.ExecuteWorkList(L, Steps, 0); } /// Execute the work list with an initial state. Nodes that reaches the exit @@ -139,7 +129,7 @@ public: void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, const GRState *InitState, ExplodedNodeSet &Dst) { - CoreEngine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst); + Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst); } /// getContext - Return the ASTContext associated with this analysis. @@ -147,16 +137,16 @@ public: virtual AnalysisManager &getAnalysisManager() { return AMgr; } - SValuator &getSValuator() { return SVator; } + SValBuilder &getSValBuilder() { return svalBuilder; } - GRTransferFuncs& getTF() { return *TF; } + TransferFuncs& getTF() { return *TF; } BugReporter& getBugReporter() { return BR; } - GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; } + StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; } - // FIXME: Remove once GRTransferFuncs is no longer referenced. - void setTransferFunction(GRTransferFuncs* tf); + // FIXME: Remove once TransferFuncs is no longer referenced. + void setTransferFunction(TransferFuncs* tf); /// ViewGraph - Visualize the ExplodedGraph created by executing the /// simulation. @@ -186,56 +176,64 @@ public: return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag())); } - void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); - void AddCheck(GRSimpleAPICheck* A); + /// processCFGElement - Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a CFG element. + void processCFGElement(const CFGElement E, StmtNodeBuilder& builder); + + void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder); + + void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &builder); - /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - void ProcessStmt(const CFGElement E, GRStmtNodeBuilder& builder); + void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &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(const CFGBlock* B, const ExplodedNode *Pred, - GRBlockCounter BC); + void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, + StmtNodeBuilder &builder); + void ProcessBaseDtor(const CFGBaseDtor D, StmtNodeBuilder &builder); + void ProcessMemberDtor(const CFGMemberDtor D, StmtNodeBuilder &builder); + void ProcessTemporaryDtor(const CFGTemporaryDtor D, + StmtNodeBuilder &builder); - /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// Called by CoreEngine when processing the entrance of a CFGBlock. + virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes, + GenericNodeBuilder<BlockEntrance> &nodeBuilder); + + /// ProcessBranch - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a branch condition. - void ProcessBranch(const Stmt* Condition, const Stmt* Term, - GRBranchNodeBuilder& builder); + void processBranch(const Stmt* Condition, const Stmt* Term, + BranchNodeBuilder& builder); - /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. - void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder); + void processIndirectGoto(IndirectGotoNodeBuilder& builder); - /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// ProcessSwitch - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. - void ProcessSwitch(GRSwitchNodeBuilder& builder); + void processSwitch(SwitchNodeBuilder& builder); - /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. - void ProcessEndPath(GREndPathNodeBuilder& builder); + void processEndOfFunction(EndOfFunctionNodeBuilder& builder); /// Generate the entry node of the callee. - void ProcessCallEnter(GRCallEnterNodeBuilder &builder); + void processCallEnter(CallEnterNodeBuilder &builder); /// Generate the first post callsite node. - void ProcessCallExit(GRCallExitNodeBuilder &builder); + void processCallExit(CallExitNodeBuilder &builder); - /// Called by GRCoreEngine when the analysis worklist has terminated. - void ProcessEndWorklist(bool hasWorkRemaining); + /// Called by CoreEngine when the analysis worklist has terminated. + void processEndWorklist(bool hasWorkRemaining); - /// EvalAssume - Callback function invoked by the ConstraintManager when + /// evalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. - const GRState *ProcessAssume(const GRState *state, SVal cond,bool assumption); + const GRState *processAssume(const GRState *state, SVal cond,bool assumption); - /// WantsRegionChangeUpdate - Called by GRStateManager to determine if a - /// region change should trigger a ProcessRegionChanges update. - bool WantsRegionChangeUpdate(const GRState* state); + /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a + /// region change should trigger a processRegionChanges update. + bool wantsRegionChangeUpdate(const GRState* state); - /// ProcessRegionChanges - Called by GRStateManager whenever a change is made + /// processRegionChanges - Called by GRStateManager whenever a change is made /// to the store. Used to update checkers that track region values. - const GRState* ProcessRegionChanges(const GRState *state, + const GRState* processRegionChanges(const GRState *state, const MemRegion * const *Begin, const MemRegion * const *End); @@ -247,7 +245,7 @@ public: return StateMgr.getConstraintManager(); } - // FIXME: Remove when we migrate over to just using ValueManager. + // FIXME: Remove when we migrate over to just using SValBuilder. BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); } @@ -255,20 +253,18 @@ public: return StateMgr.getBasicVals(); } - 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; } // Functions for external checking of whether we have unfinished work - bool wasBlockAborted() const { return CoreEngine.wasBlockAborted(); } + bool wasBlockAborted() const { return Engine.wasBlockAborted(); } + bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); } bool hasWorkRemaining() const { - return wasBlockAborted() || CoreEngine.getWorkList()->hasWork(); + return wasBlockAborted() || Engine.getWorkList()->hasWork(); } - const GRCoreEngine &getCoreEngine() const { return CoreEngine; } + const CoreEngine &getCoreEngine() const { return Engine; } protected: const GRState* GetState(ExplodedNode* N) { @@ -286,11 +282,14 @@ public: void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, CallbackKind Kind); + void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, bool isPrevisit); + bool CheckerEvalCall(const CallExpr *CE, ExplodedNodeSet &Dst, ExplodedNode *Pred); - void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + void CheckerEvalNilReceiver(const ObjCMessage &msg, ExplodedNodeSet &Dst, const GRState *state, ExplodedNode *Pred); @@ -303,14 +302,10 @@ public: /// other functions that handle specific kinds of statements. void Visit(const 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(const Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); - /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitArraySubscriptExpr(const ArraySubscriptExpr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* Ex, + ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitAsmStmt - Transfer function logic for inline asm. void VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst); @@ -331,35 +326,26 @@ public: /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNodeSet& Dst); /// VisitCall - Transfer function for function calls. void VisitCall(const CallExpr* CE, ExplodedNode* Pred, CallExpr::const_arg_iterator AI, CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNodeSet& Dst); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst, bool asLValue); + ExplodedNodeSet &Dst); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, - ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); - - /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(const DeclRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNode* Pred, ExplodedNodeSet& Dst); - /// VisitBlockDeclRefExpr - Transfer function logic for BlockDeclRefExprs. - void VisitBlockDeclRefExpr(const BlockDeclRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - + /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs. void VisitCommonDeclRefExpr(const Expr* DR, const NamedDecl *D, - ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(const DeclStmt* DS, ExplodedNode* Pred, @@ -383,11 +369,18 @@ public: /// VisitMemberExpr - Transfer function for member expressions. void VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNodeSet& Dst); - /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + /// Transfer function logic for ObjCAtSynchronizedStmts. + void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Transfer function logic for computing the lvalue of an Objective-C ivar. + void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitObjCForCollectionStmt - Transfer function logic for /// ObjCForCollectionStmt. @@ -400,7 +393,9 @@ public: /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNodeSet& Dst); + void VisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Src, + ExplodedNodeSet& Dst); /// VisitReturnStmt - Transfer function logic for return statements. void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred, @@ -416,25 +411,36 @@ public: /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + ExplodedNodeSet& Dst); void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst); - - void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst); + + void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + VisitCXXConstructExpr(expr, 0, Pred, Dst); + } + + void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXDestructor(const CXXDestructorDecl *DD, + const MemRegion *Dest, const Stmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, ExplodedNodeSet &Dst); + void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst); void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred, + void VisitAggExpr(const Expr *E, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// Create a C++ temporary object for an rvalue. @@ -442,87 +448,103 @@ public: ExplodedNodeSet &Dst); /// Synthesize CXXThisRegion. - const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD, + const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD, const StackFrameContext *SFC); + const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl, + const StackFrameContext *frameCtx); + /// Evaluate arguments with a work list algorithm. - void EvalArguments(ConstExprIterator AI, ConstExprIterator AE, + void evalArguments(ConstExprIterator AI, ConstExprIterator AE, const FunctionProtoType *FnType, - ExplodedNode *Pred, ExplodedNodeSet &Dst); + ExplodedNode *Pred, ExplodedNodeSet &Dst, + bool FstArgAsLValue = false); - /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic + /// Evaluate method call itself. Used for CXXMethodCallExpr and + /// CXXOperatorCallExpr. + void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, + const Expr *ThisExpr, ExplodedNode *Pred, + ExplodedNodeSet &Src, ExplodedNodeSet &Dst); + + /// 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(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, + void evalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, const Expr *Ex); - SVal EvalMinus(SVal X) { - return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X; + SVal evalMinus(SVal X) { + return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X; } - SVal EvalComplement(SVal X) { - return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X; + SVal evalComplement(SVal X) { + return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X; } public: - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) { - return SVator.EvalBinOpNN(state, op, L, R, T); + return svalBuilder.evalBinOpNN(state, op, L, R, T); } - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) { - return R.isValid() ? SVator.EvalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R; + return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R; } - SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op, SVal LHS, SVal RHS, QualType T) { - return SVator.EvalBinOp(ST, Op, LHS, RHS, T); + return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T); } protected: - void EvalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME, - ExplodedNode* Pred, const GRState *state) { - assert (Builder && "GRStmtNodeBuilder must be defined."); - getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state); + void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg, + ExplodedNode* Pred, const GRState *state) { + assert (Builder && "StmtNodeBuilder must be defined."); + getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state); } const GRState* MarkBranch(const GRState* St, const 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(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred, + /// evalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by evalStore, VisitDeclStmt, and others. + void evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred, const GRState* St, SVal location, SVal Val, bool atDeclInit = false); public: // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. - void EvalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, + // FIXME: Comment on the meaning of the arguments, when 'St' may not + // be the same as Pred->state, and when 'location' may not be the + // same as state->getLValue(Ex). + /// Simulate a read of the result of Ex. + void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag = 0, QualType LoadTy = QualType()); // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. - void EvalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE, + void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, const void *tag = 0); -private: - void EvalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, +private: + void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag, QualType LoadTy); // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. - void EvalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred, + void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred, const GRState* St, SVal location, const void *tag, bool isLoad); bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred); }; +} // end ento namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h index 5503412f7e45..18e39d999bb4 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h @@ -1,4 +1,4 @@ -//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- C++ -*-= +//===-- ExprEngineBuilders.h - "Builder" classes for ExprEngine ---*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -8,52 +8,53 @@ //===----------------------------------------------------------------------===// // // This file defines smart builder "references" which are used to marshal -// builders between GRExprEngine objects and their related components. +// builders between ExprEngine objects and their related components. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS -#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS -#include "clang/Checker/PathSensitive/GRExprEngine.h" +#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS +#define LLVM_CLANG_GR_EXPRENGINE_BUILDERS +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/Analysis/Support/SaveAndRestore.h" namespace clang { -class GRStmtNodeBuilderRef { +namespace ento { + +class StmtNodeBuilderRef { ExplodedNodeSet &Dst; - GRStmtNodeBuilder &B; - GRExprEngine& Eng; + StmtNodeBuilder &B; + ExprEngine& Eng; ExplodedNode* Pred; const GRState* state; const Stmt* stmt; const unsigned OldSize; const bool AutoCreateNode; SaveAndRestore<bool> OldSink; - SaveAndRestore<const void*> OldTag; SaveOr OldHasGen; private: - friend class GRExprEngine; + friend class ExprEngine; - GRStmtNodeBuilderRef(); // do not implement - void operator=(const GRStmtNodeBuilderRef&); // do not implement + StmtNodeBuilderRef(); // do not implement + void operator=(const StmtNodeBuilderRef&); // do not implement - GRStmtNodeBuilderRef(ExplodedNodeSet &dst, - GRStmtNodeBuilder &builder, - GRExprEngine& eng, + StmtNodeBuilderRef(ExplodedNodeSet &dst, + StmtNodeBuilder &builder, + ExprEngine& eng, 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) {} + OldSink(B.BuildSinks), OldHasGen(B.hasGeneratedNode) {} public: - ~GRStmtNodeBuilderRef() { + ~StmtNodeBuilderRef() { // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { + if (!B.BuildSinks && Dst.size() == OldSize && !B.hasGeneratedNode) { if (AutoCreateNode) B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); else @@ -72,5 +73,8 @@ public: } }; +} // end GR namespace + } // end clang namespace + #endif diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h index d72d63ab3c98..37694da6573c 100644 --- a/include/clang/Checker/PathSensitive/GRState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h @@ -1,4 +1,4 @@ -//== GRState*h - Path-Sens. "State" for tracking valuues -----*- C++ -*--==// +//== GRState.h - Path-sensitive "State" for tracking values -----*- C++ -*--==// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,18 @@ // //===----------------------------------------------------------------------===// // -// This file defines SymbolRef, ExprBindKey, and GRState* +// This file defines SymbolRef, ExprBindKey, and GRState*. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H -#define LLVM_CLANG_ANALYSIS_VALUESTATE_H +#ifndef LLVM_CLANG_GR_VALUESTATE_H +#define LLVM_CLANG_GR_VALUESTATE_H -#include "clang/Checker/PathSensitive/ConstraintManager.h" -#include "clang/Checker/PathSensitive/Environment.h" -#include "clang/Checker/PathSensitive/Store.h" -#include "clang/Checker/PathSensitive/ValueManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Casting.h" @@ -30,11 +31,14 @@ class raw_ostream; namespace clang { class ASTContext; + +namespace ento { + class GRStateManager; class Checker; typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&, - GRSubEngine&); + SubEngine&); typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); //===----------------------------------------------------------------------===// @@ -52,16 +56,19 @@ template <typename T> struct GRStateTrait { } }; -//===----------------------------------------------------------------------===// -// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals. -//===----------------------------------------------------------------------===// - 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. +/// GRState - This class encapsulates: +/// +/// 1. A mapping from expressions to values (Environment) +/// 2. A mapping from locations to values (Store) +/// 3. Constraints on symbolic values (GenericDataMap) +/// +/// Together these represent the "abstract state" of a program. +/// +/// GRState 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: typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; @@ -71,60 +78,59 @@ private: void operator=(const GRState& R) const; // Do not implement. friend class GRStateManager; + friend class ExplodedGraph; + friend class ExplodedNode; - GRStateManager *StateMgr; - Environment Env; - Store St; - GenericDataMap GDM; + GRStateManager *stateMgr; + Environment Env; // Maps a Stmt to its current SVal. + Store store; // Maps a location to its current value. + GenericDataMap GDM; // Custom data stored by a client of this class. + unsigned refCount; /// 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; + const GRState *makeWithStore(const StoreRef &store) const; + + void setStore(const StoreRef &storeRef); public: /// This ctor is used when creating the first GRState object. GRState(GRStateManager *mgr, const Environment& env, - Store st, GenericDataMap gdm) - : StateMgr(mgr), - Env(env), - St(st), - GDM(gdm) {} - + StoreRef st, GenericDataMap 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(), - StateMgr(RHS.StateMgr), - Env(RHS.Env), - St(RHS.St), - GDM(RHS.GDM) {} - - /// getStateManager - Return the GRStateManager associated with this state. - GRStateManager &getStateManager() const { - return *StateMgr; - } + GRState(const GRState& RHS); + + ~GRState(); + + /// Return the GRStateManager associated with this state. + GRStateManager &getStateManager() const { return *stateMgr; } + + /// Return true if this state is referenced by a persistent ExplodedNode. + bool referencedByExplodedNode() const { return refCount > 0; } /// 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 + /// 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; } + Store getStore() const { return store; } + /// 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. + /// Profile - Profile the contents of a GRState object for use in a + /// FoldingSet. Two GRState objects are considered equal if they + /// have the same Environment, Store, and GenericDataMap. static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { V->Env.Profile(ID); - ID.AddPointer(V->St); + ID.AddPointer(V->store); V->GDM.Profile(ID); } @@ -134,10 +140,6 @@ public: Profile(ID, this); } - SVal LookupExpr(Expr* E) const { - return Env.LookupExpr(E); - } - BasicValueFactory &getBasicVals() const; SymbolManager &getSymbolManager() const; @@ -150,36 +152,32 @@ public: // As constraints gradually accrue on symbolic values, added constraints // may conflict and indicate that a state is infeasible (as no real values // could satisfy all the constraints). This is the principal mechanism - // for modeling path-sensitivity in GRExprEngine/GRState. + // for modeling path-sensitivity in ExprEngine/GRState. // - // Various "Assume" methods form the interface for adding constraints to - // symbolic values. A call to "Assume" indicates an assumption being placed - // on one or symbolic values. Assume methods take the following inputs: + // Various "assume" methods form the interface for adding constraints to + // symbolic values. A call to 'assume' indicates an assumption being placed + // on one or symbolic values. 'assume' methods take the following inputs: // // (1) A GRState object representing the current state. // - // (2) The assumed constraint (which is specific to a given "Assume" method). + // (2) The assumed constraint (which is specific to a given "assume" method). // // (3) A binary value "Assumption" that indicates whether the constraint is // assumed to be true or false. // - // The output of "Assume" are two values: - // - // (a) "isFeasible" is set to true or false to indicate whether or not - // the assumption is feasible. - // - // (b) A new GRState object with the added constraints. - // - // FIXME: (a) should probably disappear since it is redundant with (b). - // (i.e., (b) could just be set to NULL). + // The output of "assume*" is a new GRState object with the added constraints. + // If no new state is feasible, NULL is returned. // - const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const; - + const GRState *assume(DefinedOrUnknownSVal cond, bool assumption) const; + + /// This method assumes both "true" and "false" for 'cond', and + /// returns both corresponding states. It's shorthand for doing + /// 'assume' twice. std::pair<const GRState*, const GRState*> - Assume(DefinedOrUnknownSVal cond) const; + assume(DefinedOrUnknownSVal cond) const; - const GRState *AssumeInBound(DefinedOrUnknownSVal idx, + const GRState *assumeInBound(DefinedOrUnknownSVal idx, DefinedOrUnknownSVal upperBound, bool assumption) const; @@ -194,9 +192,7 @@ public: //==---------------------------------------------------------------------==// /// 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. + /// in this state plus the bindings for the CompoundLiteral. const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC, SVal V) const; @@ -222,27 +218,27 @@ public: const GRState *unbindLoc(Loc LV) const; - /// InvalidateRegion - Returns the state with bindings for the given region - /// cleared from the store. See InvalidateRegions. - const GRState *InvalidateRegion(const MemRegion *R, + /// invalidateRegion - Returns the state with bindings for the given region + /// cleared from the store. See invalidateRegions. + const GRState *invalidateRegion(const MemRegion *R, const Expr *E, unsigned BlockCount, StoreManager::InvalidatedSymbols *IS = NULL) const { - return InvalidateRegions(&R, &R+1, E, BlockCount, IS, false); + return invalidateRegions(&R, &R+1, E, BlockCount, IS, false); } - /// InvalidateRegions - Returns the state with bindings for the given regions + /// invalidateRegions - Returns the state with bindings for the given regions /// cleared from the store. The regions are provided as a continuous array /// from Begin to End. Optionally invalidates global regions as well. - const GRState *InvalidateRegions(const MemRegion * const *Begin, + const GRState *invalidateRegions(const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, unsigned BlockCount, StoreManager::InvalidatedSymbols *IS, bool invalidateGlobals) const; - /// EnterStackFrame - Returns the state for entry to the given stack frame, + /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. - const GRState *EnterStackFrame(const StackFrameContext *frame) const; + const GRState *enterStackFrame(const StackFrameContext *frame) const; /// Get the lvalue for a variable reference. Loc getLValue(const VarDecl *D, const LocationContext *LC) const; @@ -270,12 +266,9 @@ public: SVal getSValAsScalarOrLoc(const Stmt *Ex) const; SVal getSVal(Loc LV, QualType T = QualType()) const; - - /// Returns a "simplified" SVal bound to the location 'LV' in the state's - /// store. A simplified SVal will include optimizations such as - /// if the SVal is a symbol whose value is perfectly constrained then that - /// constant value is returned instead. - SVal getSimplifiedSVal(Loc LV, QualType T= QualType()) const; + + /// Returns the "raw" SVal bound to LV before any value simplfication. + SVal getRawSVal(Loc LV, QualType T= QualType()) const; SVal getSVal(const MemRegion* R) const; @@ -368,6 +361,16 @@ public: void printStdErr(CFG &C) const; void printDOT(llvm::raw_ostream& Out, CFG &C) const; + +private: + /// Increments the number of times this state is referenced by ExplodeNodes. + void incrementReferenceCount() { ++refCount; } + + /// Decrement the number of times this state is referenced by ExplodeNodes. + void decrementReferenceCount() { + assert(refCount > 0); + --refCount; + } }; class GRStateSet { @@ -409,10 +412,10 @@ public: class GRStateManager { friend class GRState; - friend class GRExprEngine; // FIXME: Remove. + friend class ExprEngine; // FIXME: Remove. private: - /// Eng - The GRSubEngine that owns this state manager. - GRSubEngine &Eng; + /// Eng - The SubEngine that owns this state manager. + SubEngine *Eng; /* Can be null. */ EnvironmentManager EnvMgr; llvm::OwningPtr<StoreManager> StoreMgr; @@ -431,65 +434,86 @@ private: /// a particular function. This is used to unique states. llvm::FoldingSet<GRState> StateSet; - /// ValueMgr - Object that manages the data for all created SVals. - ValueManager ValueMgr; + /// Object that manages the data for all created SVals. + llvm::OwningPtr<SValBuilder> svalBuilder; - /// Alloc - A BumpPtrAllocator to allocate states. + /// A BumpPtrAllocator to allocate states. llvm::BumpPtrAllocator &Alloc; + /// A vector of recently allocated GRStates that can potentially be + /// reused. + std::vector<GRState *> recentlyAllocatedStates; + + /// A vector of GRStates that we can reuse. + std::vector<GRState *> freeStates; + public: GRStateManager(ASTContext& Ctx, StoreManagerCreator CreateStoreManager, ConstraintManagerCreator CreateConstraintManager, llvm::BumpPtrAllocator& alloc, - GRSubEngine &subeng) - : Eng(subeng), + SubEngine &subeng) + : Eng(&subeng), EnvMgr(alloc), GDMFactory(alloc), - ValueMgr(alloc, Ctx, *this), + svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)), Alloc(alloc) { StoreMgr.reset((*CreateStoreManager)(*this)); ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng)); } + GRStateManager(ASTContext& Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManager* ConstraintManagerPtr, + llvm::BumpPtrAllocator& alloc) + : Eng(0), + EnvMgr(alloc), + GDMFactory(alloc), + svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset(ConstraintManagerPtr); + } + ~GRStateManager(); const GRState *getInitialState(const LocationContext *InitLoc); - ASTContext &getContext() { return ValueMgr.getContext(); } - const ASTContext &getContext() const { return ValueMgr.getContext(); } + ASTContext &getContext() { return svalBuilder->getContext(); } + const ASTContext &getContext() const { return svalBuilder->getContext(); } BasicValueFactory &getBasicVals() { - return ValueMgr.getBasicValueFactory(); + return svalBuilder->getBasicValueFactory(); } const BasicValueFactory& getBasicVals() const { - return ValueMgr.getBasicValueFactory(); + return svalBuilder->getBasicValueFactory(); + } + + SValBuilder &getSValBuilder() { + return *svalBuilder; } SymbolManager &getSymbolManager() { - return ValueMgr.getSymbolManager(); + return svalBuilder->getSymbolManager(); } const SymbolManager &getSymbolManager() const { - return ValueMgr.getSymbolManager(); + return svalBuilder->getSymbolManager(); } - ValueManager &getValueManager() { return ValueMgr; } - const ValueManager &getValueManager() const { return ValueMgr; } - llvm::BumpPtrAllocator& getAllocator() { return Alloc; } MemRegionManager& getRegionManager() { - return ValueMgr.getRegionManager(); + return svalBuilder->getRegionManager(); } const MemRegionManager& getRegionManager() const { - return ValueMgr.getRegionManager(); + return svalBuilder->getRegionManager(); } StoreManager& getStoreManager() { return *StoreMgr; } ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - GRSubEngine& getOwningEngine() { return Eng; } + SubEngine* getOwningEngine() { return Eng; } - const GRState* RemoveDeadBindings(const GRState* St, + const GRState* removeDeadBindings(const GRState* St, const StackFrameContext *LCtx, SymbolReaper& SymReaper); @@ -514,6 +538,10 @@ public: } const GRState* getPersistentState(GRState& Impl); + + /// Periodically called by ExprEngine to recycle GRStates that were + /// created but never used for creating an ExplodedNode. + void recycleUnusedStates(); //==---------------------------------------------------------------------==// // Generic Data Map methods. @@ -608,21 +636,21 @@ inline const VarRegion* GRState::getRegion(const VarDecl *D, return getStateManager().getRegionManager().getVarRegion(D, LC); } -inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond, +inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond, bool Assumption) const { if (Cond.isUnknown()) return this; - return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond), + return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond), Assumption); } inline std::pair<const GRState*, const GRState*> -GRState::Assume(DefinedOrUnknownSVal Cond) const { +GRState::assume(DefinedOrUnknownSVal Cond) const { if (Cond.isUnknown()) return std::make_pair(this, this); - return getStateManager().ConstraintMgr->AssumeDual(this, + return getStateManager().ConstraintMgr->assumeDual(this, cast<DefinedSVal>(Cond)); } @@ -653,7 +681,9 @@ inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const { } inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ - return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base); + if (NonLoc *N = dyn_cast<NonLoc>(&Idx)) + return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); + return UnknownVal(); } inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { @@ -661,25 +691,25 @@ inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { } inline SVal GRState::getSVal(const Stmt* Ex) const { - return Env.GetSVal(Ex, getStateManager().ValueMgr); + return Env.getSVal(Ex, *getStateManager().svalBuilder); } inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { if (const Expr *Ex = dyn_cast<Expr>(S)) { QualType T = Ex->getType(); - if (Loc::IsLocType(T) || T->isIntegerType()) + if (Loc::isLocType(T) || T->isIntegerType()) return getSVal(S); } return UnknownVal(); } -inline SVal GRState::getSVal(Loc LV, QualType T) const { - return getStateManager().StoreMgr->Retrieve(St, LV, T); +inline SVal GRState::getRawSVal(Loc LV, QualType T) const { + return getStateManager().StoreMgr->Retrieve(getStore(), LV, T); } inline SVal GRState::getSVal(const MemRegion* R) const { - return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R)); + return getStateManager().StoreMgr->Retrieve(getStore(), loc::MemRegionVal(R)); } inline BasicValueFactory &GRState::getBasicVals() const { @@ -755,6 +785,9 @@ CB GRState::scanReachableSymbols(const MemRegion * const *beg, scanReachableSymbols(beg, end, cb); return cb; } + +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h index 5189a1f5aa7e..411441f8fe34 100644 --- a/include/clang/Checker/PathSensitive/GRStateTrait.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H -#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H +#ifndef LLVM_CLANG_GR_GRSTATETRAIT_H +#define LLVM_CLANG_GR_GRSTATETRAIT_H namespace llvm { class BumpPtrAllocator; @@ -26,6 +26,8 @@ namespace llvm { } namespace clang { + +namespace ento { template <typename T> struct GRStatePartialTrait; // Partial-specialization for ImmutableMap. @@ -48,11 +50,11 @@ namespace clang { 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); + return F.add(B, K, E); } static data_type Remove(data_type B, key_type K, context_type F) { - return F.Remove(B, K); + return F.remove(B, K); } static inline context_type MakeContext(void* p) { @@ -86,11 +88,11 @@ namespace clang { } static data_type Add(data_type B, key_type K, context_type F) { - return F.Add(B, K); + return F.add(B, K); } static data_type Remove(data_type B, key_type K, context_type F) { - return F.Remove(B, K); + return F.remove(B, K); } static bool Contains(data_type B, key_type K) { @@ -119,7 +121,7 @@ namespace clang { 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); + return F.add(K, L); } static inline data_type MakeData(void* const* p) { @@ -143,6 +145,21 @@ namespace clang { delete (typename data_type::Factory*) Ctx; } }; + + // Partial specialization for bool. + template <> struct GRStatePartialTrait<bool> { + typedef bool data_type; + + static inline data_type MakeData(void* const* p) { + return (bool) (uintptr_t) p; + } + static inline void *MakeVoidPtr(data_type d) { + return (void*) (uintptr_t) d; + } + }; + +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 96f906af28e1..8d19b5199274 100644 --- a/include/clang/Checker/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -13,12 +13,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H -#define LLVM_CLANG_ANALYSIS_MEMREGION_H +#ifndef LLVM_CLANG_GR_MEMREGION_H +#define LLVM_CLANG_GR_MEMREGION_H +#include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" -#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/FoldingSet.h" @@ -31,11 +32,14 @@ class raw_ostream; namespace clang { -class MemRegionManager; -class MemSpaceRegion; class LocationContext; class StackFrameContext; -class ValueManager; + +namespace ento { + +class MemRegionManager; +class MemSpaceRegion; +class SValBuilder; class VarRegion; class CodeTextRegion; @@ -93,9 +97,10 @@ public: VarRegionKind = BEG_DECL_REGIONS, FieldRegionKind, ObjCIvarRegionKind, - CXXObjectRegionKind, - END_DECL_REGIONS = CXXObjectRegionKind, - END_TYPED_REGIONS = END_DECL_REGIONS + END_DECL_REGIONS = ObjCIvarRegionKind, + CXXTempObjectRegionKind, + CXXBaseObjectRegionKind, + END_TYPED_REGIONS = CXXBaseObjectRegionKind }; private: @@ -294,7 +299,7 @@ public: } /// getExtent - Returns the size of the region in bytes. - virtual DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const { + virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { return UnknownVal(); } @@ -329,7 +334,7 @@ public: bool isBoundable() const { return true; } - DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; void Profile(llvm::FoldingSetNodeID& ID) const; @@ -353,16 +358,20 @@ public: virtual QualType getLocationType() const { // FIXME: We can possibly optimize this later to cache this value. - return getContext().getPointerType(getValueType()); + QualType T = getValueType(); + ASTContext &ctx = getContext(); + if (T->getAs<ObjCObjectType>()) + return ctx.getObjCObjectPointerType(T); + return ctx.getPointerType(getValueType()); } - QualType getDesugaredValueType() const { + QualType getDesugaredValueType(ASTContext &Context) const { QualType T = getValueType(); - return T.getTypePtr() ? T.getDesugaredType() : T; + return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T; } - QualType getDesugaredLocationType() const { - return getLocationType().getDesugaredType(); + QualType getDesugaredLocationType(ASTContext &Context) const { + return getLocationType().getDesugaredType(Context); } bool isBoundable() const { return true; } @@ -542,7 +551,7 @@ public: bool isBoundable() const { return true; } - DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; void Profile(llvm::FoldingSetNodeID& ID) const; @@ -578,7 +587,7 @@ public: return Str->getType(); } - DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; bool isBoundable() const { return false; } @@ -639,7 +648,7 @@ public: const Decl* getDecl() const { return D; } void Profile(llvm::FoldingSetNodeID& ID) const; - DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; static bool classof(const MemRegion* R) { unsigned k = R->getKind(); @@ -725,7 +734,7 @@ public: return getDecl()->getType(); } - DefinedOrUnknownSVal getExtent(ValueManager& ValMgr) const; + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD, const MemRegion* superRegion) { @@ -770,14 +779,14 @@ private: friend class ElementRegion; const MemRegion *Region; - int64_t Offset; + CharUnits Offset; - RegionRawOffset(const MemRegion* reg, int64_t offset = 0) + RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero()) : Region(reg), Offset(offset) {} public: // FIXME: Eventually support symbolic offsets. - int64_t getByteOffset() const { return Offset; } + CharUnits getOffset() const { return Offset; } const MemRegion *getRegion() const { return Region; } void dumpToStream(llvm::raw_ostream& os) const; @@ -788,9 +797,9 @@ class ElementRegion : public TypedRegion { friend class MemRegionManager; QualType ElementType; - SVal Index; + NonLoc Index; - ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg) + ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) : TypedRegion(sReg, ElementRegionKind), ElementType(elementType), Index(Idx) { assert((!isa<nonloc::ConcreteInt>(&Idx) || @@ -803,7 +812,7 @@ class ElementRegion : public TypedRegion { public: - SVal getIndex() const { return Index; } + NonLoc getIndex() const { return Index; } QualType getValueType() const { return ElementType; @@ -825,13 +834,13 @@ public: }; // C++ temporary object associated with an expression. -class CXXObjectRegion : public TypedRegion { +class CXXTempObjectRegion : public TypedRegion { friend class MemRegionManager; Expr const *Ex; - CXXObjectRegion(Expr const *E, MemRegion const *sReg) - : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {} + CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) + : TypedRegion(sReg, CXXTempObjectRegionKind), Ex(E) {} static void ProfileRegion(llvm::FoldingSetNodeID &ID, Expr const *E, const MemRegion *sReg); @@ -841,10 +850,39 @@ public: return Ex->getType(); } + void dumpToStream(llvm::raw_ostream& os) const; + void Profile(llvm::FoldingSetNodeID &ID) const; static bool classof(const MemRegion* R) { - return R->getKind() == CXXObjectRegionKind; + return R->getKind() == CXXTempObjectRegionKind; + } +}; + +// CXXBaseObjectRegion represents a base object within a C++ object. It is +// identified by the base class declaration and the region of its parent object. +class CXXBaseObjectRegion : public TypedRegion { + friend class MemRegionManager; + + const CXXRecordDecl *decl; + + CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg) + : TypedRegion(sReg, CXXBaseObjectRegionKind), decl(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const CXXRecordDecl *decl, const MemRegion *sReg); + +public: + const CXXRecordDecl *getDecl() const { return decl; } + + QualType getValueType() const; + + void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *region) { + return region->getKind() == CXXBaseObjectRegionKind; } }; @@ -942,7 +980,7 @@ public: /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. - const ElementRegion *getElementRegion(QualType elementType, SVal Idx, + const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, const MemRegion *superRegion, ASTContext &Ctx); @@ -971,8 +1009,19 @@ public: const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex, - LocationContext const *LC); + const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, + LocationContext const *LC); + + const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl, + const MemRegion *superRegion); + + /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different + /// super region. + const CXXBaseObjectRegion * + getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, + const MemRegion *superRegion) { + return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion); + } const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, @@ -1024,6 +1073,8 @@ inline ASTContext& MemRegion::getContext() const { return getMemRegionManager()->getContext(); } +} // end GR namespace + } // end clang namespace //===----------------------------------------------------------------------===// @@ -1032,7 +1083,7 @@ inline ASTContext& MemRegion::getContext() const { namespace llvm { static inline raw_ostream& operator<<(raw_ostream& os, - const clang::MemRegion* R) { + const clang::ento::MemRegion* R) { R->dumpToStream(os); return os; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h new file mode 100644 index 000000000000..710fc6b84f9e --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -0,0 +1,210 @@ +//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- 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 ObjCMessage which serves as a common wrapper for ObjC +// message expressions or implicit messages for loading/storing ObjC properties. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE +#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { +namespace ento { + +/// \brief Represents both explicit ObjC message expressions and implicit +/// messages that are sent for handling properties in dot syntax. +class ObjCMessage { + const Expr *MsgOrPropE; + const Expr *OriginE; + bool IsPropSetter; + SVal SetterArgV; + +protected: + ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV) + : MsgOrPropE(E), OriginE(origE), + IsPropSetter(isSetter), SetterArgV(setArgV) { } + +public: + ObjCMessage() : MsgOrPropE(0), OriginE(0) { } + + ObjCMessage(const ObjCMessageExpr *E) + : MsgOrPropE(E), OriginE(E) { + assert(E && "should not be initialized with null expression"); + } + + bool isValid() const { return MsgOrPropE != 0; } + bool isInvalid() const { return !isValid(); } + + bool isMessageExpr() const { + return isValid() && isa<ObjCMessageExpr>(MsgOrPropE); + } + + bool isPropertyGetter() const { + return isValid() && + isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter; + } + + bool isPropertySetter() const { + return isValid() && + isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter; + } + + const Expr *getOriginExpr() const { return OriginE; } + + QualType getType(ASTContext &ctx) const; + + QualType getResultType(ASTContext &ctx) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + if (const ObjCMethodDecl *MD = msgE->getMethodDecl()) + return MD->getResultType(); + return getType(ctx); + } + + Selector getSelector() const; + + const Expr *getInstanceReceiver() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getInstanceReceiver(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (propE->isObjectReceiver()) + return propE->getBase(); + return 0; + } + + bool isInstanceMessage() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->isInstanceMessage(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + // FIXME: 'super' may be super class. + return propE->isObjectReceiver() || propE->isSuperReceiver(); + } + + const ObjCMethodDecl *getMethodDecl() const; + + const ObjCInterfaceDecl *getReceiverInterface() const; + + SourceLocation getSuperLoc() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getSuperLoc(); + return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation(); + } + + SourceRange getSourceRange() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + return MsgOrPropE->getSourceRange(); + } + + unsigned getNumArgs() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getNumArgs(); + return isPropertySetter() ? 1 : 0; + } + + SVal getArgSVal(unsigned i, const GRState *state) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return state->getSVal(msgE->getArg(i)); + assert(isPropertySetter()); + return SetterArgV; + } + + QualType getArgType(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getArg(i)->getType(); + assert(isPropertySetter()); + return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType(); + } + + const Expr *getArgExpr(unsigned i) const; + + SourceRange getArgSourceRange(unsigned i) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + assert(i < getNumArgs() && "Invalid index for argument"); + if (const Expr *argE = getArgExpr(i)) + return argE->getSourceRange(); + return OriginE->getSourceRange(); + } +}; + +class ObjCPropertyGetter : public ObjCMessage { +public: + ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE) + : ObjCMessage(propE, originE, false, SVal()) { + assert(propE && originE && + "should not be initialized with null expressions"); + } +}; + +class ObjCPropertySetter : public ObjCMessage { +public: + ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE, + SVal argV) + : ObjCMessage(propE, storeE, true, argV) { + assert(propE && storeE &&"should not be initialized with null expressions"); + } +}; + +/// \brief Common wrapper for a call expression or an ObjC message, mainly to +/// provide a common interface for handling their arguments. +class CallOrObjCMessage { + const CallExpr *CallE; + ObjCMessage Msg; + const GRState *State; + +public: + CallOrObjCMessage(const CallExpr *callE, const GRState *state) + : CallE(callE), State(state) { } + CallOrObjCMessage(const ObjCMessage &msg, const GRState *state) + : CallE(0), Msg(msg), State(state) { } + + QualType getResultType(ASTContext &ctx) const; + + unsigned getNumArgs() const { + if (CallE) return CallE->getNumArgs(); + return Msg.getNumArgs(); + } + + SVal getArgSVal(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return State->getSVal(CallE->getArg(i)); + return Msg.getArgSVal(i, State); + } + + SVal getArgSValAsScalarOrLoc(unsigned i) const; + + const Expr *getArg(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return CallE->getArg(i); + return Msg.getArgExpr(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return CallE->getArg(i)->getSourceRange(); + return Msg.getArgSourceRange(i); + } +}; + +} +} + +#endif diff --git a/include/clang/Checker/PathSensitive/ValueManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index b81e9c150234..fc2b76e04a66 100644 --- a/include/clang/Checker/PathSensitive/ValueManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -1,4 +1,4 @@ -//== ValueManager.h - Aggregate manager of symbols and SVals ----*- C++ -*--==// +// SValBuilder.h - Construction of SVals from evaluating expressions -*- C++ -*- // // The LLVM Compiler Infrastructure // @@ -7,65 +7,102 @@ // //===----------------------------------------------------------------------===// // -// This file defines ValueManager, a class that manages symbolic values -// and SVals created for use by GRExprEngine and related classes. It -// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory. +// This file defines SValBuilder, a class that defines the interface for +// "symbolical evaluators" which construct an SVal from an expression. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H -#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#ifndef LLVM_CLANG_GR_SVALBUILDER +#define LLVM_CLANG_GR_SVALBUILDER -#include "llvm/ADT/OwningPtr.h" -#include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Checker/PathSensitive/SVals.h" -#include "clang/Checker/PathSensitive/BasicValueFactory.h" -#include "clang/Checker/PathSensitive/SymbolManager.h" -#include "clang/Checker/PathSensitive/SValuator.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" - -namespace llvm { class BumpPtrAllocator; } +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" namespace clang { -class GRStateManager; +namespace ento { -class ValueManager { +class GRState; +class SValBuilder { +protected: ASTContext &Context; + + /// Manager of APSInt values. BasicValueFactory BasicVals; - /// SymMgr - Object that manages the symbol information. + /// Manages the creation of symbols. SymbolManager SymMgr; - /// SVator - SValuator object that creates SVals from expressions. - llvm::OwningPtr<SValuator> SVator; - + /// Manages the creation of memory regions. MemRegionManager MemMgr; GRStateManager &StateMgr; + /// The scalar type to use for array indices. const QualType ArrayIndexTy; + + /// The width of the scalar type used for array indices. const unsigned ArrayIndexWidth; public: - 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)); - } + // FIXME: Make these protected again one RegionStoreManager correctly + // handles loads from differening bound value types. + virtual SVal evalCastNL(NonLoc val, QualType castTy) = 0; + virtual SVal evalCastL(Loc val, QualType castTy) = 0; - // Accessors to submanagers. +public: + SValBuilder(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)) {} + + virtual ~SValBuilder() {} + + SVal evalCast(SVal V, QualType castTy, QualType originalType); + + virtual SVal evalMinus(NonLoc val) = 0; + + virtual SVal evalComplement(NonLoc val) = 0; + + virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, + NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; + + virtual SVal evalBinOpLL(const GRState *state, 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; + + /// getKnownValue - evaluates a given SVal. If the SVal has only one possible + /// (integer) value, that value is returned. Otherwise, returns NULL. + virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0; + + SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal L, SVal R, QualType T); + + DefinedOrUnknownSVal evalEQ(const GRState *ST, DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R); ASTContext &getContext() { return Context; } const ASTContext &getContext() const { return Context; } GRStateManager &getStateManager() { return StateMgr; } + + QualType getConditionType() const { + return getContext().IntTy; + } + + QualType getArrayIndexType() const { + return ArrayIndexTy; + } BasicValueFactory &getBasicValueFactory() { return BasicVals; } const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } @@ -73,8 +110,6 @@ public: 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; } @@ -137,9 +172,8 @@ public: I->getType()->isUnsignedIntegerType())); } - nonloc::ConcreteInt makeIntVal(const CXXBoolLiteralExpr *E) { - return E->getValue() ? nonloc::ConcreteInt(BasicVals.getValue(1, 1, true)) - : nonloc::ConcreteInt(BasicVals.getValue(0, 1, true)); + nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *E) { + return makeTruthVal(E->getValue()); } nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { @@ -155,7 +189,7 @@ public: } DefinedSVal makeIntVal(uint64_t X, QualType T) { - if (Loc::IsLocType(T)) + if (Loc::isLocType(T)) return loc::ConcreteInt(BasicVals.getValue(X, T)); return nonloc::ConcreteInt(BasicVals.getValue(X, T)); @@ -183,11 +217,11 @@ public: NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType T); - NonLoc makeTruthVal(bool b, QualType T) { + nonloc::ConcreteInt makeTruthVal(bool b, QualType T) { return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); } - NonLoc makeTruthVal(bool b) { + nonloc::ConcreteInt makeTruthVal(bool b) { return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); } @@ -203,14 +237,22 @@ public: return loc::MemRegionVal(R); } - Loc makeLoc(const AddrLabelExpr* E) { + Loc makeLoc(const AddrLabelExpr *E) { return loc::GotoLabel(E->getLabel()); } Loc makeLoc(const llvm::APSInt& V) { return loc::ConcreteInt(BasicVals.getValue(V)); } + }; + +SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc, + ASTContext &context, + GRStateManager &stateMgr); + +} // end GR namespace + } // end clang namespace -#endif +#endif diff --git a/include/clang/Checker/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index cdb338a3f2cc..0d430794e76c 100644 --- a/include/clang/Checker/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -12,10 +12,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H -#define LLVM_CLANG_ANALYSIS_RVALUE_H +#ifndef LLVM_CLANG_GR_RVALUE_H +#define LLVM_CLANG_GR_RVALUE_H -#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/ImmutableList.h" @@ -29,6 +29,8 @@ namespace llvm { namespace clang { +namespace ento { + class CompoundValData; class LazyCompoundValData; class GRState; @@ -37,26 +39,38 @@ class MemRegion; class TypedRegion; class MemRegionManager; class GRStateManager; -class ValueManager; +class SValBuilder; +/// SVal - This represents a symbolic expression, which can be either +/// an L-value or an R-value. +/// class SVal { public: - enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; + enum BaseKind { + // The enumerators must be representable using 2 bits. + UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value) + UnknownKind = 1, // for subclass UnknownVal (a void value) + LocKind = 2, // for subclass Loc (an L-value) + NonLocKind = 3 // for subclass NonLoc (an R-value that's not + // an L-value) + }; enum { BaseBits = 2, BaseMask = 0x3 }; protected: const void* Data; + + /// The lowest 2 bits are a BaseKind (0 -- 3). + /// The higher bits are an unsigned "kind" value. unsigned Kind; -protected: - SVal(const void* d, bool isLoc, unsigned ValKind) + explicit SVal(const void* d, bool isLoc, unsigned ValKind) : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} explicit SVal(BaseKind k, const void* D = NULL) : Data(D), Kind(k) {} public: - SVal() : Data(0), Kind(0) {} + explicit SVal() : Data(0), Kind(0) {} ~SVal() {} /// BufferTy - A temporary buffer to hold a set of SVals. @@ -66,6 +80,8 @@ public: inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + // This method is required for using SVal in a FoldingSetNode. It + // extracts a unique signature for this SVal object. inline void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) getRawKind()); ID.AddPointer(Data); @@ -194,13 +210,13 @@ public: class UnknownVal : public DefinedOrUnknownSVal { public: - UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + explicit 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 @@ -209,7 +225,7 @@ private: bool isUnknownOrUndef() const; bool isValid() const; protected: - DefinedSVal(const void* d, bool isLoc, unsigned ValKind) + explicit DefinedSVal(const void* d, bool isLoc, unsigned ValKind) : DefinedOrUnknownSVal(d, isLoc, ValKind) {} public: // Implement isa<T> support. @@ -220,7 +236,8 @@ public: class NonLoc : public DefinedSVal { protected: - NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {} + explicit NonLoc(unsigned SubKind, const void* d) + : DefinedSVal(d, false, SubKind) {} public: void dumpToStream(llvm::raw_ostream& Out) const; @@ -233,21 +250,20 @@ public: class Loc : public DefinedSVal { protected: - Loc(unsigned SubKind, const void* D) + explicit Loc(unsigned SubKind, const void* D) : DefinedSVal(const_cast<void*>(D), true, SubKind) {} public: void dumpToStream(llvm::raw_ostream& Out) const; 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) { + static inline bool isLocType(QualType T) { return T->isAnyPointerType() || T->isBlockPointerType() || T->isReferenceType(); } @@ -282,7 +298,7 @@ public: class SymExprVal : public NonLoc { public: - SymExprVal(const SymExpr *SE) + explicit SymExprVal(const SymExpr *SE) : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {} const SymExpr *getSymbolicExpression() const { @@ -301,19 +317,19 @@ public: class ConcreteInt : public NonLoc { public: - ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} const llvm::APSInt& getValue() const { return *static_cast<const llvm::APSInt*>(Data); } // Transfer functions for binary/unary operations on ConcreteInts. - SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, + SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, const ConcreteInt& R) const; - ConcreteInt evalComplement(ValueManager &ValMgr) const; + ConcreteInt evalComplement(SValBuilder &svalBuilder) const; - ConcreteInt evalMinus(ValueManager &ValMgr) const; + ConcreteInt evalMinus(SValBuilder &svalBuilder) const; // Implement isa<T> support. static inline bool classof(const SVal* V) { @@ -327,9 +343,9 @@ public: }; class LocAsInteger : public NonLoc { - friend class clang::ValueManager; + friend class ento::SValBuilder; - LocAsInteger(const std::pair<SVal, uintptr_t>& data) : + explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) : NonLoc(LocAsIntegerKind, &data) { assert (isa<Loc>(data.first)); } @@ -361,9 +377,9 @@ public: }; class CompoundVal : public NonLoc { - friend class clang::ValueManager; + friend class ento::SValBuilder; - CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} public: const CompoundValData* getValue() const { @@ -384,9 +400,9 @@ public: }; class LazyCompoundVal : public NonLoc { - friend class clang::ValueManager; + friend class ento::SValBuilder; - LazyCompoundVal(const LazyCompoundValData *D) + explicit LazyCompoundVal(const LazyCompoundValData *D) : NonLoc(LazyCompoundValKind, D) {} public: const LazyCompoundValData *getCVData() const { @@ -404,7 +420,7 @@ public: } }; -} // end namespace clang::nonloc +} // end namespace ento::nonloc //==------------------------------------------------------------------------==// // Subclasses of Loc. @@ -412,19 +428,18 @@ public: namespace loc { -enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind, ObjCPropRefKind }; class GotoLabel : public Loc { public: - GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} + explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} - const LabelStmt* getLabel() const { - return static_cast<const LabelStmt*>(Data); + const LabelDecl *getLabel() const { + return static_cast<const LabelDecl*>(Data); } static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && - V->getSubKind() == GotoLabelKind; + return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind; } static inline bool classof(const Loc* V) { @@ -435,13 +450,13 @@ public: class MemRegionVal : public Loc { public: - MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} const MemRegion* getRegion() const { return static_cast<const MemRegion*>(Data); } - const MemRegion* StripCasts() const; + const MemRegion* stripCasts() const; template <typename REGION> const REGION* getRegionAs() const { @@ -469,14 +484,14 @@ public: class ConcreteInt : public Loc { public: - ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} const llvm::APSInt& getValue() const { return *static_cast<const llvm::APSInt*>(Data); } // Transfer functions for binary/unary operations on ConcreteInts. - SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const ConcreteInt& R) const; // Implement isa<T> support. @@ -490,14 +505,40 @@ public: } }; -} // end clang::loc namespace +/// \brief Pseudo-location SVal used by the ExprEngine to simulate a "load" or +/// "store" of an ObjC property for the dot syntax. +class ObjCPropRef : public Loc { +public: + explicit ObjCPropRef(const ObjCPropertyRefExpr *E) + : Loc(ObjCPropRefKind, E) {} + + const ObjCPropertyRefExpr *getPropRefExpr() const { + return static_cast<const ObjCPropertyRefExpr *>(Data); + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ObjCPropRefKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ObjCPropRefKind; + } +}; + +} // end ento::loc namespace +} // end GR namespace + } // end clang namespace namespace llvm { static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, - clang::SVal V) { + clang::ento::SVal V) { V.dumpToStream(os); return os; } + } // end llvm namespace + #endif diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index a1a41847a206..0251311c27ae 100644 --- a/include/clang/Checker/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -11,30 +11,56 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_STORE_H -#define LLVM_CLANG_ANALYSIS_STORE_H +#ifndef LLVM_CLANG_GR_STORE_H +#define LLVM_CLANG_GR_STORE_H -#include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Checker/PathSensitive/SVals.h" -#include "clang/Checker/PathSensitive/ValueManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" namespace clang { +class Stmt; +class Expr; +class ObjCIvarDecl; +class StackFrameContext; + +namespace ento { + +/// Store - This opaque type encapsulates an immutable mapping from +/// locations to values. At a high-level, it represents the symbolic +/// memory model. Different subclasses of StoreManager may choose +/// different types to represent the locations and values. typedef const void* Store; class GRState; class GRStateManager; -class Stmt; -class Expr; -class ObjCIvarDecl; class SubRegionMap; -class StackFrameContext; +class StoreManager; + +class StoreRef { + Store store; + StoreManager &mgr; +public: + StoreRef(Store, StoreManager &); + StoreRef(const StoreRef &); + StoreRef &operator=(StoreRef const &); + + bool operator==(const StoreRef &x) const { + assert(&mgr == &x.mgr); + return x.store == store; + } + bool operator!=(const StoreRef &x) const { return !operator==(x); } + ~StoreRef(); + + Store getStore() const { return store; } +}; + class StoreManager { protected: - ValueManager &ValMgr; + SValBuilder &svalBuilder; GRStateManager &StateMgr; /// MRMgr - Manages region objects associated with this StoreManager. @@ -62,25 +88,22 @@ public: /// \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 Store Bind(Store store, Loc loc, SVal val) = 0; - - virtual Store BindDefault(Store store, const MemRegion *R, SVal V) { - return store; - } + virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; - virtual Store Remove(Store St, Loc L) = 0; + virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V); + virtual StoreRef 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 /// array of initializer values. - virtual Store BindCompoundLiteral(Store store, - const CompoundLiteralExpr* cl, - const LocationContext *LC, SVal v) = 0; + virtual StoreRef BindCompoundLiteral(Store store, + const CompoundLiteralExpr* cl, + const LocationContext *LC, SVal v) = 0; /// getInitialStore - Returns the initial "empty" store representing the /// value bindings upon entry to an analyzed function. - virtual Store getInitialStore(const LocationContext *InitLoc) = 0; + virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0; /// getRegionManager - Returns the internal RegionManager object that is /// used to query and manipulate MemRegion objects. @@ -92,11 +115,11 @@ public: virtual SubRegionMap *getSubRegionMap(Store store) = 0; virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) { - return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); + return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC)); } virtual Loc getLValueString(const StringLiteral* S) { - return ValMgr.makeLoc(MRMgr.getStringRegion(S)); + return svalBuilder.makeLoc(MRMgr.getStringRegion(S)); } Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL, @@ -112,7 +135,7 @@ public: return getLValueFieldOrIvar(D, Base); } - virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base); + virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base); // FIXME: This should soon be eliminated altogether; clients should deal with // region extents directly. @@ -122,10 +145,15 @@ public: return UnknownVal(); } - /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit + /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. virtual SVal ArrayToPointer(Loc Array) = 0; + /// Evaluates DerivedToBase casts. + virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) { + return UnknownVal(); + } + class CastResult { const GRState *state; const MemRegion *region; @@ -137,30 +165,32 @@ public: const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); - /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from + /// castRegion - Used by ExprEngine::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. - const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); - - - /// EvalBinOp - Perform pointer arithmetic. - virtual SVal EvalBinOp(BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs, QualType resultTy) { - return UnknownVal(); - } + const MemRegion *castRegion(const MemRegion *region, QualType CastToTy); - virtual Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper, + virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; - virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0; + virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0; + + virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0; + + /// If the StoreManager supports it, increment the reference count of + /// the specified Store object. + virtual void incrementReferenceCount(Store store) {} - virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0; + /// If the StoreManager supports it, decrement the reference count of + /// the specified Store object. If the reference count hits 0, the memory + /// associated with the object is recycled. + virtual void decrementReferenceCount(Store store) {} typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; typedef llvm::SmallVector<const MemRegion *, 8> InvalidatedRegions; - /// InvalidateRegions - Clears out the specified regions from the store, + /// invalidateRegions - Clears out the specified regions from the store, /// marking their values as unknown. Depending on the store, this may also /// invalidate additional regions that may have changed based on accessing /// the given regions. Optionally, invalidates non-static globals as well. @@ -179,18 +209,18 @@ public: /// invalidated. This should include any regions explicitly invalidated /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. - virtual Store InvalidateRegions(Store store, - const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS, - bool invalidateGlobals, - InvalidatedRegions *Regions) = 0; - - /// EnterStackFrame - Let the StoreManager to do something when execution + virtual StoreRef invalidateRegions(Store store, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS, + bool invalidateGlobals, + InvalidatedRegions *Regions) = 0; + + /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. - virtual Store EnterStackFrame(const GRState *state, - const StackFrameContext *frame); + virtual StoreRef enterStackFrame(const GRState *state, + const StackFrameContext *frame); virtual void print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) = 0; @@ -206,19 +236,48 @@ public: virtual void iterBindings(Store store, BindingsHandler& f) = 0; protected: - const MemRegion *MakeElementRegion(const MemRegion *Base, + const MemRegion *MakeElementRegion(const MemRegion *baseRegion, 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. - SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy, + SVal CastRetrievedVal(SVal val, const TypedRegion *region, QualType castTy, bool performTestOnly = true); private: - SVal getLValueFieldOrIvar(const Decl* D, SVal Base); + SVal getLValueFieldOrIvar(const Decl* decl, SVal base); }; + +inline StoreRef::StoreRef(Store store, StoreManager & smgr) + : store(store), mgr(smgr) { + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::StoreRef(const StoreRef &sr) + : store(sr.store), mgr(sr.mgr) +{ + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::~StoreRef() { + if (store) + mgr.decrementReferenceCount(store); +} + +inline StoreRef &StoreRef::operator=(StoreRef const &newStore) { + assert(&newStore.mgr == &mgr); + if (store != newStore.store) { + mgr.incrementReferenceCount(newStore.store); + mgr.decrementReferenceCount(store); + store = newStore.getStore(); + } + return *this; +} + // FIXME: Do we still need this? /// SubRegionMap - An abstract interface that represents a queryable map /// between MemRegion objects and their subregions. @@ -240,6 +299,9 @@ StoreManager *CreateBasicStoreManager(GRStateManager& StMgr); StoreManager *CreateRegionStoreManager(GRStateManager& StMgr); StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr); StoreManager *CreateFlatStoreManager(GRStateManager &StMgr); + +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h new file mode 100644 index 000000000000..3d6f9fa15b73 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -0,0 +1,116 @@ +//== SubEngine.h - Interface of the subengine of CoreEngine --------*- 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 CoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_GR_SUBENGINE_H +#define LLVM_CLANG_GR_SUBENGINE_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" + +namespace clang { + +class CFGBlock; +class CFGElement; +class LocationContext; +class Stmt; + +namespace ento { + +template <typename PP> class GenericNodeBuilder; +class AnalysisManager; +class ExplodedNodeSet; +class ExplodedNode; +class GRState; +class GRStateManager; +class BlockCounter; +class StmtNodeBuilder; +class BranchNodeBuilder; +class IndirectGotoNodeBuilder; +class SwitchNodeBuilder; +class EndOfFunctionNodeBuilder; +class CallEnterNodeBuilder; +class CallExitNodeBuilder; +class MemRegion; + +class SubEngine { +public: + virtual ~SubEngine() {} + + virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; + + virtual AnalysisManager &getAnalysisManager() = 0; + + virtual GRStateManager &getStateManager() = 0; + + /// Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void processCFGElement(const CFGElement E, StmtNodeBuilder& builder)=0; + + /// Called by CoreEngine when it starts processing a CFGBlock. The + /// SubEngine is expected to populate dstNodes with new nodes representing + /// updated analysis state, or generate no nodes at all if it doesn't. + virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes, + GenericNodeBuilder<BlockEntrance> &nodeBuilder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void processBranch(const Stmt* Condition, const Stmt* Term, + BranchNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void processSwitch(SwitchNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void processEndOfFunction(EndOfFunctionNodeBuilder& builder) = 0; + + // Generate the entry node of the callee. + virtual void processCallEnter(CallEnterNodeBuilder &builder) = 0; + + // Generate the first post callsite node. + virtual void processCallExit(CallExitNodeBuilder &builder) = 0; + + /// Called by ConstraintManager. Used to call checker-specific + /// logic for handling assumptions on symbolic values. + virtual const GRState* processAssume(const GRState *state, + SVal cond, bool assumption) = 0; + + /// wantsRegionChangeUpdate - Called by GRStateManager to determine if a + /// region change should trigger a processRegionChanges update. + virtual bool wantsRegionChangeUpdate(const GRState* state) = 0; + + /// processRegionChanges - Called by GRStateManager whenever a change is made + /// to the store. Used to update checkers that track region values. + virtual const GRState* processRegionChanges(const GRState* state, + const MemRegion* const *Begin, + const MemRegion* const *End) = 0; + + inline const GRState* processRegionChange(const GRState* state, + const MemRegion* MR) { + return processRegionChanges(state, &MR, &MR+1); + } + + /// Called by CoreEngine when the analysis worklist is either empty or the + // maximum number of analysis steps have been reached. + virtual void processEndWorklist(bool hasWorkRemaining) = 0; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/SummaryManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h index fd23189491b3..ed878515988a 100644 --- a/include/clang/Checker/PathSensitive/SummaryManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h @@ -12,14 +12,16 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CHECKER_SUMMARY -#define LLVM_CLANG_CHECKER_SUMMARY +#ifndef LLVM_CLANG_GR_SUMMARY +#define LLVM_CLANG_GR_SUMMARY #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Allocator.h" namespace clang { +namespace ento { + namespace summMgr { @@ -52,6 +54,8 @@ class SummaryManager : SummaryManagerImpl { }; +} // end GR namespace + } // end clang namespace #endif diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 26ed0c1bc06f..ad173bb43536 100644 --- a/include/clang/Checker/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -8,17 +8,17 @@ //===----------------------------------------------------------------------===// // // This file defines SymbolManager, a class that manages symbolic values -// created for use by GRExprEngine and related classes. +// created for use by ExprEngine and related classes. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H -#define LLVM_CLANG_ANALYSIS_SYMMGR_H +#ifndef LLVM_CLANG_GR_SYMMGR_H +#define LLVM_CLANG_GR_SYMMGR_H #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/Analysis/AnalysisContext.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseSet.h" @@ -29,12 +29,14 @@ class raw_ostream; namespace clang { class ASTContext; + class StackFrameContext; + +namespace ento { class BasicValueFactory; class MemRegion; class SubRegion; class TypedRegion; class VarRegion; - class StackFrameContext; class SymExpr : public llvm::FoldingSetNode { public: @@ -458,7 +460,7 @@ public: /// isDead - Returns whether or not a symbol has been confirmed dead. This /// should only be called once all marking of dead symbols has completed. - /// (For checkers, this means only in the EvalDeadSymbols callback.) + /// (For checkers, this means only in the evalDeadSymbols callback.) bool isDead(SymbolRef sym) const { return TheDead.count(sym); } @@ -473,11 +475,13 @@ public: virtual ~SymbolVisitor(); }; +} // end GR namespace + } // end clang namespace namespace llvm { static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, - const clang::SymExpr *SE) { + const clang::ento::SymExpr *SE) { SE->dumpToStream(os); return os; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h new file mode 100644 index 000000000000..23ed2be8c7a4 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h @@ -0,0 +1,93 @@ +//== TransferFuncs.h - Path-Sens. Transfer Functions Interface ---*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines TransferFuncs, which provides a base-class that +// defines an interface for transfer functions used by ExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_TRANSFERFUNCS +#define LLVM_CLANG_GR_TRANSFERFUNCS + +#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include <vector> + +namespace clang { +class ObjCMessageExpr; + +namespace ento { +class ExplodedNode; +class ExplodedNodeSet; +class EndOfFunctionNodeBuilder; +class ExprEngine; +class StmtNodeBuilder; +class StmtNodeBuilderRef; + +class TransferFuncs { +public: + TransferFuncs() {} + virtual ~TransferFuncs() {} + + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} + virtual void RegisterChecks(ExprEngine& Eng) {} + + + // Calls. + + virtual void evalCall(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + const CallExpr* CE, SVal L, + ExplodedNode* Pred) {} + + virtual void evalObjCMessage(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + ObjCMessage msg, + ExplodedNode* Pred, + const GRState *state) {} + + // Stores. + + virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {} + + // End-of-path and dead symbol notification. + + virtual void evalEndPath(ExprEngine& Engine, + EndOfFunctionNodeBuilder& Builder) {} + + + virtual void evalDeadSymbols(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + ExplodedNode* Pred, + const GRState* state, + SymbolReaper& SymReaper) {} + + // Return statements. + virtual void evalReturn(ExplodedNodeSet& Dst, + ExprEngine& Engine, + StmtNodeBuilder& Builder, + const ReturnStmt* S, + ExplodedNode* Pred) {} + + // Assumptions. + virtual const GRState* evalAssume(const GRState *state, + SVal Cond, bool Assumption) { + return state; + } +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h new file mode 100644 index 000000000000..6bc9fe56f8d6 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -0,0 +1,101 @@ +//==- WorkList.h - Worklist class used by CoreEngine ---------------*- 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 WorkList, a pure virtual class that represents an opaque +// worklist used by CoreEngine to explore the reachability state space. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_WORKLIST +#define LLVM_CLANG_GR_WORKLIST + +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include <cstddef> + +namespace clang { + +class CFGBlock; + +namespace ento { + +class ExplodedNode; +class ExplodedNodeImpl; + +class WorkListUnit { + ExplodedNode* node; + BlockCounter counter; + const CFGBlock* block; + unsigned blockIdx; // This is the index of the next statement. + +public: + WorkListUnit(ExplodedNode* N, BlockCounter C, + const CFGBlock* B, unsigned idx) + : node(N), + counter(C), + block(B), + blockIdx(idx) {} + + explicit WorkListUnit(ExplodedNode* N, BlockCounter C) + : node(N), + counter(C), + block(NULL), + blockIdx(0) {} + + /// Returns the node associated with the worklist unit. + ExplodedNode *getNode() const { return node; } + + /// Returns the block counter map associated with the worklist unit. + BlockCounter getBlockCounter() const { return counter; } + + /// Returns the CFGblock associated with the worklist unit. + const CFGBlock *getBlock() const { return block; } + + /// Return the index within the CFGBlock for the worklist unit. + unsigned getIndex() const { return blockIdx; } +}; + +class WorkList { + BlockCounter CurrentCounter; +public: + virtual ~WorkList(); + virtual bool hasWork() const = 0; + + virtual void enqueue(const WorkListUnit& U) = 0; + + void enqueue(ExplodedNode *N, const CFGBlock *B, unsigned idx) { + enqueue(WorkListUnit(N, CurrentCounter, B, idx)); + } + + void enqueue(ExplodedNode *N) { + enqueue(WorkListUnit(N, CurrentCounter)); + } + + virtual WorkListUnit dequeue() = 0; + + void setBlockCounter(BlockCounter C) { CurrentCounter = C; } + BlockCounter getBlockCounter() const { return CurrentCounter; } + + class Visitor { + public: + Visitor() {} + virtual ~Visitor(); + virtual bool visit(const WorkListUnit &U) = 0; + }; + virtual bool visitItemsInWorkList(Visitor &V) = 0; + + static WorkList *makeDFS(); + static WorkList *makeBFS(); + static WorkList *makeBFSBlockDFSContents(); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h new file mode 100644 index 000000000000..4c3e379f3345 --- /dev/null +++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -0,0 +1,26 @@ +//===-- CheckerRegistration.h - Checker Registration Function-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H +#define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H + +namespace clang { + class AnalyzerOptions; + class Diagnostic; + +namespace ento { + class CheckerManager; + +CheckerManager *registerCheckers(const AnalyzerOptions &opts,Diagnostic &diags); + +} // end ento namespace + +} // end namespace clang + +#endif diff --git a/include/clang/Checker/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index 1c0bbb78ba8c..e3867a2a2478 100644 --- a/include/clang/Checker/FrontendActions.h +++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -7,13 +7,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_CHECKER_FRONTENDACTIONS_H -#define LLVM_CLANG_CHECKER_FRONTENDACTIONS_H +#ifndef LLVM_CLANG_GR_FRONTENDACTIONS_H +#define LLVM_CLANG_GR_FRONTENDACTIONS_H #include "clang/Frontend/FrontendAction.h" namespace clang { +namespace ento { + //===----------------------------------------------------------------------===// // AST Consumer Actions //===----------------------------------------------------------------------===// @@ -24,6 +26,8 @@ protected: llvm::StringRef InFile); }; -} // end namespace clang +} // end GR namespace + +} // end namespace clang #endif |