diff options
Diffstat (limited to 'include/clang')
177 files changed, 49815 insertions, 0 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h new file mode 100644 index 000000000000..5d5abfe011d4 --- /dev/null +++ b/include/clang/AST/APValue.h @@ -0,0 +1,253 @@ +//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- 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 APValue class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_APVALUE_H +#define LLVM_CLANG_AST_APVALUE_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/APFloat.h" + +namespace clang { + class Expr; + +/// APValue - This class implements a discriminated union of [uninitialized] +/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset]. +class APValue { + typedef llvm::APSInt APSInt; + typedef llvm::APFloat APFloat; +public: + enum ValueKind { + Uninitialized, + Int, + Float, + ComplexInt, + ComplexFloat, + LValue, + Vector + }; +private: + ValueKind Kind; + + struct ComplexAPSInt { + APSInt Real, Imag; + ComplexAPSInt() : Real(1), Imag(1) {} + }; + struct ComplexAPFloat { + APFloat Real, Imag; + ComplexAPFloat() : Real(0.0), Imag(0.0) {} + }; + + struct LV { + Expr* Base; + uint64_t Offset; + }; + struct Vec { + APValue *Elts; + unsigned NumElts; + Vec() : Elts(0), NumElts(0) {} + ~Vec() { delete[] Elts; } + }; + + enum { + MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ? + sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat)) + }; + + /// Data - space for the largest member in units of void*. This is an effort + /// to ensure that the APSInt/APFloat values have proper alignment. + void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)]; + +public: + APValue() : Kind(Uninitialized) {} + explicit APValue(const APSInt &I) : Kind(Uninitialized) { + MakeInt(); setInt(I); + } + explicit APValue(const APFloat &F) : Kind(Uninitialized) { + MakeFloat(); setFloat(F); + } + explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) { + MakeVector(); setVector(E, N); + } + APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) { + MakeComplexInt(); setComplexInt(R, I); + } + APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) { + MakeComplexFloat(); setComplexFloat(R, I); + } + APValue(const APValue &RHS) : Kind(Uninitialized) { + *this = RHS; + } + APValue(Expr* B, uint64_t O) : Kind(Uninitialized) { + MakeLValue(); setLValue(B, O); + } + ~APValue() { + MakeUninit(); + } + + ValueKind getKind() const { return Kind; } + bool isUninit() const { return Kind == Uninitialized; } + bool isInt() const { return Kind == Int; } + bool isFloat() const { return Kind == Float; } + bool isComplexInt() const { return Kind == ComplexInt; } + bool isComplexFloat() const { return Kind == ComplexFloat; } + bool isLValue() const { return Kind == LValue; } + bool isVector() const { return Kind == Vector; } + + void print(llvm::raw_ostream &OS) const; + void dump() const; + + APSInt &getInt() { + assert(isInt() && "Invalid accessor"); + return *(APSInt*)(void*)Data; + } + const APSInt &getInt() const { + return const_cast<APValue*>(this)->getInt(); + } + + APFloat &getFloat() { + assert(isFloat() && "Invalid accessor"); + return *(APFloat*)(void*)Data; + } + const APFloat &getFloat() const { + return const_cast<APValue*>(this)->getFloat(); + } + + APValue &getVectorElt(unsigned i) const { + assert(isVector() && "Invalid accessor"); + return ((Vec*)(void*)Data)->Elts[i]; + } + unsigned getVectorLength() const { + assert(isVector() && "Invalid accessor"); + return ((Vec*)(void *)Data)->NumElts; + } + + APSInt &getComplexIntReal() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(void*)Data)->Real; + } + const APSInt &getComplexIntReal() const { + return const_cast<APValue*>(this)->getComplexIntReal(); + } + + APSInt &getComplexIntImag() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(void*)Data)->Imag; + } + const APSInt &getComplexIntImag() const { + return const_cast<APValue*>(this)->getComplexIntImag(); + } + + APFloat &getComplexFloatReal() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(void*)Data)->Real; + } + const APFloat &getComplexFloatReal() const { + return const_cast<APValue*>(this)->getComplexFloatReal(); + } + + APFloat &getComplexFloatImag() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(void*)Data)->Imag; + } + const APFloat &getComplexFloatImag() const { + return const_cast<APValue*>(this)->getComplexFloatImag(); + } + + Expr* getLValueBase() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Base; + } + uint64_t getLValueOffset() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Offset; + } + + void setInt(const APSInt &I) { + assert(isInt() && "Invalid accessor"); + *(APSInt*)(void*)Data = I; + } + void setFloat(const APFloat &F) { + assert(isFloat() && "Invalid accessor"); + *(APFloat*)(void*)Data = F; + } + void setVector(const APValue *E, unsigned N) { + assert(isVector() && "Invalid accessor"); + ((Vec*)(void*)Data)->Elts = new APValue[N]; + ((Vec*)(void*)Data)->NumElts = N; + for (unsigned i = 0; i != N; ++i) + ((Vec*)(void*)Data)->Elts[i] = E[i]; + } + void setComplexInt(const APSInt &R, const APSInt &I) { + assert(R.getBitWidth() == I.getBitWidth() && + "Invalid complex int (type mismatch)."); + assert(isComplexInt() && "Invalid accessor"); + ((ComplexAPSInt*)(void*)Data)->Real = R; + ((ComplexAPSInt*)(void*)Data)->Imag = I; + } + void setComplexFloat(const APFloat &R, const APFloat &I) { + assert(&R.getSemantics() == &I.getSemantics() && + "Invalid complex float (type mismatch)."); + assert(isComplexFloat() && "Invalid accessor"); + ((ComplexAPFloat*)(void*)Data)->Real = R; + ((ComplexAPFloat*)(void*)Data)->Imag = I; + } + void setLValue(Expr *B, uint64_t O) { + assert(isLValue() && "Invalid accessor"); + ((LV*)(void*)Data)->Base = B; + ((LV*)(void*)Data)->Offset = O; + } + + const APValue &operator=(const APValue &RHS); + +private: + void MakeUninit(); + void MakeInt() { + assert(isUninit() && "Bad state change"); + new ((void*)Data) APSInt(1); + Kind = Int; + } + void MakeFloat() { + assert(isUninit() && "Bad state change"); + new ((APFloat*)(void*)Data) APFloat(0.0); + Kind = Float; + } + void MakeVector() { + assert(isUninit() && "Bad state change"); + new ((Vec*)(void*)Data) Vec(); + Kind = Vector; + } + void MakeComplexInt() { + assert(isUninit() && "Bad state change"); + new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt(); + Kind = ComplexInt; + } + void MakeComplexFloat() { + assert(isUninit() && "Bad state change"); + new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat(); + Kind = ComplexFloat; + } + void MakeLValue() { + assert(isUninit() && "Bad state change"); + new ((LV*)(void*)Data) LV(); + Kind = LValue; + } +}; + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) { + V.print(OS); + return OS; +} + +} // end namespace clang. + +#endif diff --git a/include/clang/AST/AST.h b/include/clang/AST/AST.h new file mode 100644 index 000000000000..164c5fbbb6e2 --- /dev/null +++ b/include/clang/AST/AST.h @@ -0,0 +1,28 @@ +//===--- AST.h - "Umbrella" header for AST library --------------*- 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 the AST classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_AST_H +#define LLVM_CLANG_AST_AST_H + +// This header exports all AST interfaces. +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Type.h" +#include "clang/AST/StmtVisitor.h" + +#endif diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h new file mode 100644 index 000000000000..6dc7e13d8f70 --- /dev/null +++ b/include/clang/AST/ASTConsumer.h @@ -0,0 +1,81 @@ +//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- 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 ASTConsumer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONSUMER_H +#define LLVM_CLANG_AST_ASTCONSUMER_H + +namespace clang { + class ASTContext; + class DeclGroupRef; + class TagDecl; + class HandleTagDeclDefinition; + class SemaConsumer; // layering violation required for safe SemaConsumer + class VarDecl; + +/// ASTConsumer - This is an abstract interface that should be implemented by +/// clients that read ASTs. This abstraction layer allows the client to be +/// independent of the AST producer (e.g. parser vs AST dump file reader, etc). +class ASTConsumer { + /// \brief Whether this AST consumer also requires information about + /// semantic analysis. + bool SemaConsumer; + + friend class SemaConsumer; + +public: + ASTConsumer() : SemaConsumer(false) { } + + virtual ~ASTConsumer() {} + + /// Initialize - This is called to initialize the consumer, providing the + /// ASTContext and the Action. + virtual void Initialize(ASTContext &Context) {} + + /// HandleTopLevelDecl - Handle the specified top-level declaration. This is + /// called by the parser to process every top-level Decl*. Note that D can + /// be the head of a chain of Decls (e.g. for `int a, b` the chain will have + /// two elements). Use Decl::getNextDeclarator() to walk the chain. + virtual void HandleTopLevelDecl(DeclGroupRef D); + + /// HandleTranslationUnit - This method is called when the ASTs for entire + /// translation unit have been parsed. + virtual void HandleTranslationUnit(ASTContext &Ctx) {} + + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl + /// (e.g. struct, union, enum, class) is completed. This allows the client to + /// hack on the type, which can occur at any point in the file (because these + /// can be defined in declspecs). + virtual void HandleTagDeclDefinition(TagDecl *D) {} + + /// \brief Callback invoked at the end of a translation unit to + /// notify the consumer that the given tentative definition should + /// be completed. + /// + /// The variable declaration itself will be a tentative + /// definition. If it had an incomplete array type, its type will + /// have already been changed to an array of size 1. However, the + /// declaration remains a tentative definition and has not been + /// modified by the introduction of an implicit zero initializer. + virtual void CompleteTentativeDefinition(VarDecl *D) {} + + /// PrintStats - If desired, print any statistics. + virtual void PrintStats() { + } + + // Support isa/cast/dyn_cast + static bool classof(const ASTConsumer *) { return true; } +}; + +} // end namespace clang. + +#endif diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h new file mode 100644 index 000000000000..e99e9f2b18f3 --- /dev/null +++ b/include/clang/AST/ASTContext.h @@ -0,0 +1,857 @@ +//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- 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 ASTContext interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONTEXT_H +#define LLVM_CLANG_AST_ASTCONTEXT_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Builtins.h" +#include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +namespace llvm { + struct fltSemantics; +} + +namespace clang { + class FileManager; + class ASTRecordLayout; + class Expr; + class ExternalASTSource; + class IdentifierTable; + class SelectorTable; + class SourceManager; + class TargetInfo; + // Decls + class Decl; + class ObjCPropertyDecl; + class RecordDecl; + class TagDecl; + class TranslationUnitDecl; + class TypeDecl; + class TypedefDecl; + class TemplateTypeParmDecl; + class FieldDecl; + class ObjCIvarRefExpr; + class ObjCIvarDecl; + +/// ASTContext - This class holds long-lived AST nodes (such as types and +/// decls) that can be referred to throughout the semantic analysis of a file. +class ASTContext { + std::vector<Type*> Types; + llvm::FoldingSet<ExtQualType> ExtQualTypes; + 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; + std::vector<DependentSizedArrayType*> DependentSizedArrayTypes; + llvm::FoldingSet<VectorType> VectorTypes; + llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; + llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes; + llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; + llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; + llvm::FoldingSet<TypenameType> TypenameTypes; + llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes; + llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes; + + llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; + llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; + + /// \brief The set of nested name specifiers. + /// + /// This set is managed by the NestedNameSpecifier class. + llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; + 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; + + llvm::DenseMap<unsigned, FixedWidthIntType*> SignedFixedWidthIntTypes; + llvm::DenseMap<unsigned, FixedWidthIntType*> UnsignedFixedWidthIntTypes; + + /// BuiltinVaListType - built-in va list type. + /// This is initially null and set by Sema::LazilyCreateBuiltin when + /// a builtin that takes a valist is encountered. + QualType BuiltinVaListType; + + /// ObjCIdType - a pseudo built-in typedef type (set by Sema). + QualType ObjCIdType; + const RecordType *IdStructType; + + /// ObjCSelType - another pseudo built-in typedef type (set by Sema). + QualType ObjCSelType; + const RecordType *SelStructType; + + /// ObjCProtoType - another pseudo built-in typedef type (set by Sema). + QualType ObjCProtoType; + const RecordType *ProtoStructType; + + /// ObjCClassType - another pseudo built-in typedef type (set by Sema). + QualType ObjCClassType; + const RecordType *ClassStructType; + + QualType ObjCConstantStringType; + RecordDecl *CFConstantStringTypeDecl; + + RecordDecl *ObjCFastEnumerationStateTypeDecl; + + TranslationUnitDecl *TUDecl; + + /// SourceMgr - The associated SourceManager object. + SourceManager &SourceMgr; + + /// LangOpts - The language options used to create the AST associated with + /// this ASTContext object. + LangOptions LangOpts; + + /// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects. + bool FreeMemory; + llvm::MallocAllocator MallocAlloc; + llvm::BumpPtrAllocator BumpAlloc; +public: + TargetInfo &Target; + IdentifierTable &Idents; + SelectorTable &Selectors; + DeclarationNameTable DeclarationNames; + llvm::OwningPtr<ExternalASTSource> ExternalSource; + clang::PrintingPolicy PrintingPolicy; + + SourceManager& getSourceManager() { return SourceMgr; } + const SourceManager& getSourceManager() const { return SourceMgr; } + void *Allocate(unsigned Size, unsigned Align = 8) { + return FreeMemory ? MallocAlloc.Allocate(Size, Align) : + BumpAlloc.Allocate(Size, Align); + } + void Deallocate(void *Ptr) { + if (FreeMemory) + MallocAlloc.Deallocate(Ptr); + } + const LangOptions& getLangOptions() const { return LangOpts; } + + FullSourceLoc getFullLoc(SourceLocation Loc) const { + return FullSourceLoc(Loc,SourceMgr); + } + + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } + + Builtin::Context BuiltinInfo; + + // Builtin Types. + QualType VoidTy; + QualType BoolTy; + QualType CharTy; + QualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; + QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; + QualType UnsignedLongLongTy, UnsignedInt128Ty; + QualType FloatTy, DoubleTy, LongDoubleTy; + QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; + QualType VoidPtrTy, NullPtrTy; + QualType OverloadTy; + QualType DependentTy; + + ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, + IdentifierTable &idents, SelectorTable &sels, + bool FreeMemory = true, unsigned size_reserve=0, + bool InitializeBuiltins = true); + + ~ASTContext(); + + /// \brief Initialize builtins. + /// + /// Typically, this routine will be called automatically by the + /// constructor. However, in certain cases (e.g., when there is a + /// PCH file to be loaded), the constructor does not perform + /// initialization for builtins. This routine can be called to + /// perform the initialization. + void InitializeBuiltins(IdentifierTable &idents); + + /// \brief Attach an external AST source to the AST context. + /// + /// The external AST source provides the ability to load parts of + /// the abstract syntax tree as needed from some external storage, + /// e.g., a precompiled header. + void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source); + + /// \brief Retrieve a pointer to the external AST source associated + /// with this AST context, if any. + ExternalASTSource *getExternalSource() const { return ExternalSource.get(); } + + void PrintStats() const; + const std::vector<Type*>& getTypes() const { return Types; } + + //===--------------------------------------------------------------------===// + // Type Constructors + //===--------------------------------------------------------------------===// + + /// getAddSpaceQualType - Return the uniqued reference to the type for an + /// address space qualified type with the specified type and address space. + /// The resulting type has a union of the qualifiers from T and the address + /// space. If T already has an address space specifier, it is silently + /// replaced. + QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace); + + /// getObjCGCQualType - Returns the uniqued reference to the type for an + /// objc gc qualified type. The retulting type has a union of the qualifiers + /// from T and the gc attribute. + QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr); + + /// getComplexType - Return the uniqued reference to the type for a complex + /// number with the specified element type. + QualType getComplexType(QualType T); + + /// getPointerType - Return the uniqued reference to the type for a pointer to + /// the specified type. + QualType getPointerType(QualType T); + + /// getBlockPointerType - Return the uniqued reference to the type for a block + /// of the specified type. + QualType getBlockPointerType(QualType T); + + /// getLValueReferenceType - Return the uniqued reference to the type for an + /// lvalue reference to the specified type. + QualType getLValueReferenceType(QualType T); + + /// getRValueReferenceType - Return the uniqued reference to the type for an + /// rvalue reference to the specified type. + QualType getRValueReferenceType(QualType T); + + /// 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); + + /// 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); + + /// getDependentSizedArrayType - Returns a non-unique reference to + /// the type for a dependently-sized array of the specified element + /// type. FIXME: We will need these to be uniqued, or at least + /// comparable, at some point. + QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals); + + /// 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); + + /// 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); + + /// 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); + + /// 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); + + /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. + /// + QualType getFunctionNoProtoType(QualType ResultTy); + + /// 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 = false, + bool hasAnyExceptionSpec = false, + unsigned NumExs = 0, const QualType *ExArray = 0); + + /// getTypeDeclType - Return the unique reference to the type for + /// the specified type declaration. + QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0); + + /// getTypedefType - Return the unique reference to the type for the + /// specified typename decl. + QualType getTypedefType(TypedefDecl *Decl); + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl); + + QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, + IdentifierInfo *Name = 0); + + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon = QualType()); + + QualType getQualifiedNameType(NestedNameSpecifier *NNS, + QualType NamedType); + QualType getTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon = QualType()); + QualType getTypenameType(NestedNameSpecifier *NNS, + const TemplateSpecializationType *TemplateId, + QualType Canon = QualType()); + + /// getObjCQualifiedInterfaceType - Return a + /// ObjCQualifiedInterfaceType type for the given interface decl and + /// the conforming protocol list. + QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **ProtocolList, + unsigned NumProtocols); + + /// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for a + /// given 'id' and conforming protocol list. + QualType getObjCQualifiedIdType(ObjCProtocolDecl **ProtocolList, + unsigned NumProtocols); + + + /// getTypeOfType - GCC extension. + QualType getTypeOfExprType(Expr *e); + QualType getTypeOfType(QualType t); + + /// getTagDeclType - Return the unique reference to the type for the + /// specified TagDecl (struct/union/class/enum) decl. + QualType getTagDeclType(TagDecl *Decl); + + /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined + /// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4). + QualType getSizeType() const; + + /// getWCharType - In C++, this returns the unique wchar_t type. In C99, this + /// returns a type compatible with the type defined in <stddef.h> as defined + /// by the target. + QualType getWCharType() const { return WCharTy; } + + /// getSignedWCharType - Return the type of "signed wchar_t". + /// Used when in C++, as a GCC extension. + QualType getSignedWCharType() const; + + /// getUnsignedWCharType - Return the type of "unsigned wchar_t". + /// Used when in C++, as a GCC extension. + QualType getUnsignedWCharType() const; + + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) + /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). + QualType getPointerDiffType() const; + + // getCFConstantStringType - Return the C structure type used to represent + // constant CFStrings. + QualType getCFConstantStringType(); + + /// Get the structure type used to representation CFStrings, or NULL + /// if it hasn't yet been built. + QualType getRawCFConstantStringType() { + if (CFConstantStringTypeDecl) + return getTagDeclType(CFConstantStringTypeDecl); + return QualType(); + } + void setCFConstantStringType(QualType T); + + // This setter/getter represents the ObjC type for an NSConstantString. + void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl); + QualType getObjCConstantStringInterface() const { + return ObjCConstantStringType; + } + + //// This gets the struct used to keep track of fast enumerations. + QualType getObjCFastEnumerationStateType(); + + /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet + /// been built. + QualType getRawObjCFastEnumerationStateType() { + if (ObjCFastEnumerationStateTypeDecl) + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); + return QualType(); + } + + void setObjCFastEnumerationStateType(QualType T); + + /// 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); + + void getLegacyIntegralTypeEncoding(QualType &t) const; + + // Put the string version of type qualifiers into S. + void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + std::string &S) const; + + /// getObjCEncodingForMethodDecl - Return the encoded type for this method + /// declaration. + void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S); + + /// getObjCEncodingForPropertyDecl - Return the encoded type for + /// this method declaration. If non-NULL, Container must be either + /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should + /// only be NULL when getting encodings for protocol properties. + void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, + const Decl *Container, + std::string &S); + + /// getObjCEncodingTypeSize returns size of type for objective-c encoding + /// purpose. + int getObjCEncodingTypeSize(QualType t); + + /// This setter/getter represents the ObjC 'id' type. It is setup lazily, by + /// Sema. id is always a (typedef for a) pointer type, a pointer to a struct. + QualType getObjCIdType() const { return ObjCIdType; } + void setObjCIdType(QualType T); + + void setObjCSelType(QualType T); + QualType getObjCSelType() const { return ObjCSelType; } + + void setObjCProtoType(QualType QT); + QualType getObjCProtoType() const { return ObjCProtoType; } + + /// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by + /// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a + /// struct. + QualType getObjCClassType() const { return ObjCClassType; } + void setObjCClassType(QualType T); + + void setBuiltinVaListType(QualType T); + QualType getBuiltinVaListType() const { return BuiltinVaListType; } + + QualType getFixedWidthIntType(unsigned Width, bool Signed); + + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template); + + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name); + +private: + QualType getFromTargetType(unsigned Type) const; + + //===--------------------------------------------------------------------===// + // Type Predicates. + //===--------------------------------------------------------------------===// + +public: + /// isObjCObjectPointerType - Returns true if type is an Objective-C pointer + /// to an object type. This includes "id" and "Class" (two 'special' pointers + /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified + /// ID type). + bool isObjCObjectPointerType(QualType Ty) const; + + /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's + /// garbage collection attribute. + /// + QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const; + + /// isObjCNSObjectType - Return true if this is an NSObject object with + /// its NSObject attribute set. + bool isObjCNSObjectType(QualType Ty) const; + + //===--------------------------------------------------------------------===// + // Type Sizing and Analysis + //===--------------------------------------------------------------------===// + + /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified + /// scalar floating point type. + const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; + + /// getTypeInfo - Get the size and alignment of the specified complete type in + /// bits. + std::pair<uint64_t, unsigned> getTypeInfo(const Type *T); + std::pair<uint64_t, unsigned> getTypeInfo(QualType T) { + return getTypeInfo(T.getTypePtr()); + } + + /// getTypeSize - Return the size of the specified type, in bits. This method + /// does not work on incomplete types. + uint64_t getTypeSize(QualType T) { + return getTypeInfo(T).first; + } + uint64_t getTypeSize(const Type *T) { + return getTypeInfo(T).first; + } + + /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. + /// This method does not work on incomplete types. + unsigned getTypeAlign(QualType T) { + return getTypeInfo(T).second; + } + unsigned getTypeAlign(const Type *T) { + return getTypeInfo(T).second; + } + + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified + /// type for the current target in bits. This can be different than the ABI + /// alignment in cases where it is beneficial for performance to overalign + /// a data type. + unsigned getPreferredTypeAlign(const Type *T); + + /// getDeclAlignInBytes - Return the alignment of the specified decl + /// that should be returned by __alignof(). Note that bitfields do + /// not have a valid alignment, so this method will assert on them. + unsigned getDeclAlignInBytes(const Decl *D); + + /// getASTRecordLayout - Get or compute information about the layout of the + /// specified record (struct/union/class), which indicates its size and field + /// position information. + const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D); + + /// getASTObjCInterfaceLayout - Get or compute information about the + /// layout of the specified Objective-C interface. + const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D); + + /// 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); + + void CollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<FieldDecl*> &Fields); + + void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); + void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); + + //===--------------------------------------------------------------------===// + // Type Operators + //===--------------------------------------------------------------------===// + + /// getCanonicalType - Return the canonical (structural) type corresponding to + /// the specified potentially non-canonical type. The non-canonical version + /// of a type may have many "decorated" versions of types. Decorators can + /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed + /// to be free of any of these, allowing two canonical types to be compared + /// for exact equality with a simple pointer comparison. + QualType getCanonicalType(QualType T); + const Type *getCanonicalType(const Type *T) { + return T->getCanonicalTypeInternal().getTypePtr(); + } + + /// \brief Determine whether the given types are equivalent. + bool hasSameType(QualType T1, QualType T2) { + return getCanonicalType(T1) == getCanonicalType(T2); + } + + /// \brief Determine whether the given types are equivalent after + /// cvr-qualifiers have been removed. + bool hasSameUnqualifiedType(QualType T1, QualType T2) { + T1 = getCanonicalType(T1); + T2 = getCanonicalType(T2); + return T1.getUnqualifiedType() == T2.getUnqualifiedType(); + } + + /// \brief Retrieves the "canonical" declaration of the given declaration. + Decl *getCanonicalDecl(Decl *D); + + /// \brief Retrieves the "canonical" declaration of the given tag + /// declaration. + /// + /// The canonical declaration for the given tag declaration is + /// either the definition of the tag (if it is a complete type) or + /// the first declaration of that tag. + TagDecl *getCanonicalDecl(TagDecl *Tag) { + return cast<TagDecl>(getCanonicalDecl((Decl *)Tag)); + } + + /// \brief Retrieves the "canonical" declaration of + + /// \brief Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template<typename T> struct X { typename T* type; }; + /// }; + /// } + /// + /// template<typename T> struct Y { + /// typename N::S::X<T>::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X<T>:: will be + /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined + /// 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); + + /// \brief Retrieves the "canonical" template name that refers to a + /// given template. + /// + /// The canonical template name is the simplest expression that can + /// be used to refer to a given template. For most templates, this + /// expression is just the template declaration itself. For example, + /// the template std::vector can be referred to via a variety of + /// names---std::vector, ::std::vector, vector (if vector is in + /// scope), etc.---but all of these names map down to the same + /// TemplateDecl, which is used to form the canonical template name. + /// + /// Dependent template names are more interesting. Here, the + /// template name could be something like T::template apply or + /// std::allocator<T>::template rebind, where the nested name + /// specifier itself is dependent. In this case, the canonical + /// 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); + + /// 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) { + return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T)); + } + const VariableArrayType *getAsVariableArrayType(QualType T) { + return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T)); + } + const IncompleteArrayType *getAsIncompleteArrayType(QualType T) { + return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T)); + } + + /// getBaseElementType - Returns the innermost element type of a variable + /// length array type. For example, will return "int" for int[m][n] + QualType getBaseElementType(const VariableArrayType *VAT); + + /// getArrayDecayedType - Return the properly qualified result of decaying the + /// specified array type to a pointer. This operation is non-trivial when + /// handling typedefs etc. The canonical type of "T" must be an array type, + /// 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); + + /// 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); + + /// 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); + + /// getFloatingTypeOfSizeWithinDomain - Returns a real floating + /// point or a complex type (based on typeDomain/typeSize). + /// 'typeDomain' is a real floating point or complex type. + /// 'typeSize' is a real floating point or complex type. + QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, + QualType typeDomain) const; + +private: + // Helper for integer ordering + unsigned getIntegerRank(Type* T); + +public: + + //===--------------------------------------------------------------------===// + // Type Compatibility Predicates + //===--------------------------------------------------------------------===// + + /// Compatibility predicates used to check assignment expressions. + bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1 + bool typesAreBlockCompatible(QualType lhs, QualType rhs); + + bool isObjCIdType(QualType T) const { + return T == ObjCIdType; + } + bool isObjCIdStructType(QualType T) const { + if (!IdStructType) // ObjC isn't enabled + return false; + return T->getAsStructureType() == IdStructType; + } + bool isObjCClassType(QualType T) const { + return T == ObjCClassType; + } + bool isObjCClassStructType(QualType T) const { + if (!ClassStructType) // ObjC isn't enabled + return false; + return T->getAsStructureType() == ClassStructType; + } + bool isObjCSelType(QualType T) const { + assert(SelStructType && "isObjCSelType used before 'SEL' type is built"); + return T->getAsStructureType() == SelStructType; + } + + // Check the safety of assignment from LHS to RHS + bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, + const ObjCInterfaceType *RHS); + bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); + + // Functions for calculating composite types + QualType mergeTypes(QualType, QualType); + QualType mergeFunctionTypes(QualType, QualType); + + //===--------------------------------------------------------------------===// + // Integer Predicates + //===--------------------------------------------------------------------===// + + // 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); + + // 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 + // corresponding unsigned integer type. + QualType getCorrespondingUnsignedType(QualType T); + + //===--------------------------------------------------------------------===// + // Type Iterators. + //===--------------------------------------------------------------------===// + + typedef std::vector<Type*>::iterator type_iterator; + typedef std::vector<Type*>::const_iterator const_type_iterator; + + type_iterator types_begin() { return Types.begin(); } + type_iterator types_end() { return Types.end(); } + const_type_iterator types_begin() const { return Types.begin(); } + const_type_iterator types_end() const { return Types.end(); } + + //===--------------------------------------------------------------------===// + // Integer Values + //===--------------------------------------------------------------------===// + + /// 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 Res(getIntWidth(Type), !Type->isSignedIntegerType()); + Res = Value; + return Res; + } + +private: + ASTContext(const ASTContext&); // DO NOT IMPLEMENT + void operator=(const ASTContext&); // DO NOT IMPLEMENT + + void InitBuiltinTypes(); + void InitBuiltinType(QualType &R, BuiltinType::Kind K); + + // Return the ObjC type encoding for a given type. + void getObjCEncodingForTypeImpl(QualType t, std::string &S, + bool ExpandPointedToStructures, + bool ExpandStructures, + const FieldDecl *Field, + bool OutermostType = false, + bool EncodingProperty = false); + + const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl); +}; + +} // end namespace clang + +// operator new and delete aren't allowed inside namespaces. +// The throw specifications are mandated by the standard. +/// @brief Placement new for using the ASTContext's allocator. +/// +/// This placement form of operator new uses the ASTContext's allocator for +/// obtaining memory. It is a non-throwing new, which means that it returns +/// null on error. (If that is what the allocator does. The current does, so if +/// this ever changes, this operator will have to be changed, too.) +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (16) +/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments); +/// // Specific alignment +/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments); +/// @endcode +/// Please note that you cannot use delete on the pointer; it must be +/// deallocated using an explicit destructor call followed by +/// @c Context.Deallocate(Ptr). +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @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, + size_t Alignment) throw () { + return C.Allocate(Bytes, Alignment); +} +/// @brief Placement delete companion to the new above. +/// +/// This operator is just a companion to the new above. There is no way of +/// 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) + throw () { + C.Deallocate(Ptr); +} + +/// This placement form of operator new[] uses the ASTContext's allocator for +/// obtaining memory. It is a non-throwing new[], which means that it returns +/// null on error. +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (16) +/// char *data = new (Context) char[10]; +/// // Specific alignment +/// char *data = new (Context, 8) char[10]; +/// @endcode +/// Please note that you cannot use delete on the pointer; it must be +/// deallocated using an explicit destructor call followed by +/// @c Context.Deallocate(Ptr). +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @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, + size_t Alignment = 16) throw () { + return C.Allocate(Bytes, Alignment); +} + +/// @brief Placement delete[] companion to the new[] above. +/// +/// This operator is just a companion to the new[] above. There is no way of +/// 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) throw () { + C.Deallocate(Ptr); +} + +#endif diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h new file mode 100644 index 000000000000..244ca9e10f3a --- /dev/null +++ b/include/clang/AST/ASTDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- 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_DIAGNOSTICAST_H +#define LLVM_CLANG_DIAGNOSTICAST_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define ASTSTART +#include "clang/Basic/DiagnosticASTKinds.inc" +#undef DIAG + NUM_BUILTIN_AST_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h new file mode 100644 index 000000000000..0427f0003a3a --- /dev/null +++ b/include/clang/AST/Attr.h @@ -0,0 +1,506 @@ +//===--- Attr.h - Classes for representing 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 the Attr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ATTR_H +#define LLVM_CLANG_AST_ATTR_H + +#include <cassert> +#include <cstring> +#include <string> +#include <algorithm> + +namespace clang { + class ASTContext; +} + + +// Defined in ASTContext.cpp +void *operator new(size_t Bytes, clang::ASTContext &C, + size_t Alignment = 16) throw (); + +namespace clang { + +/// Attr - This represents one attribute. +class Attr { +public: + enum Kind { + Alias, + Aligned, + AlwaysInline, + AnalyzerNoReturn, // Clang-specific. + Annotate, + AsmLabel, // Represent GCC asm label extension. + Blocks, + Cleanup, + Const, + Constructor, + DLLExport, + DLLImport, + Deprecated, + Destructor, + FastCall, + Format, + FormatArg, + GNUInline, + IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with + NoReturn, + NoThrow, + Nodebug, + Noinline, + NonNull, + ObjCException, + ObjCNSObject, + CFReturnsRetained, // Clang/Checker-specific. + NSReturnsRetained, // Clang/Checker-specific. + Overloadable, // Clang-specific + Packed, + Pure, + Regparm, + Section, + Sentinel, + StdCall, + TransparentUnion, + Unavailable, + Unused, + Used, + Visibility, + WarnUnusedResult, + Weak, + WeakImport + }; + +private: + Attr *Next; + Kind AttrKind; + bool Inherited : 1; + +protected: + void* operator new(size_t bytes) throw() { + assert(0 && "Attrs cannot be allocated with regular 'new'."); + return 0; + } + void operator delete(void* data) throw() { + assert(0 && "Attrs cannot be released with regular 'delete'."); + } + +protected: + Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {} + virtual ~Attr() { + assert(Next == 0 && "Destroy didn't work"); + } +public: + + void Destroy(ASTContext &C); + + /// \brief Whether this attribute should be merged to new + /// declarations. + virtual bool isMerged() const { return true; } + + Kind getKind() const { return AttrKind; } + + Attr *getNext() { return Next; } + const Attr *getNext() const { return Next; } + void setNext(Attr *next) { Next = next; } + + bool isInherited() const { return Inherited; } + void setInherited(bool value) { Inherited = value; } + + void addAttr(Attr *attr) { + assert((attr != 0) && "addAttr(): attr is null"); + + // FIXME: This doesn't preserve the order in any way. + attr->Next = Next; + Next = attr; + } + + // Clone this attribute. + virtual Attr* clone(ASTContext &C) const = 0; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *) { return true; } +}; + +#define DEF_SIMPLE_ATTR(ATTR) \ +class ATTR##Attr : public Attr { \ +public: \ + ATTR##Attr() : Attr(ATTR) {} \ + virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }\ + static bool classof(const Attr *A) { return A->getKind() == ATTR; } \ + static bool classof(const ATTR##Attr *A) { return true; } \ +} + +class PackedAttr : public Attr { + unsigned Alignment; + +public: + PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {} + + /// getAlignment - The specified alignment in bits. + unsigned getAlignment() const { return Alignment; } + + virtual Attr* clone(ASTContext &C) const { + return ::new (C) PackedAttr(Alignment); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == Packed; + } + static bool classof(const PackedAttr *A) { return true; } +}; + +class AlignedAttr : public Attr { + unsigned Alignment; +public: + AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} + + /// getAlignment - The specified alignment in bits. + unsigned getAlignment() const { return Alignment; } + + virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == Aligned; + } + static bool classof(const AlignedAttr *A) { return true; } +}; + +class AnnotateAttr : public Attr { + std::string Annotation; +public: + AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {} + + const std::string& getAnnotation() const { return Annotation; } + + virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == Annotate; + } + static bool classof(const AnnotateAttr *A) { return true; } +}; + +class AsmLabelAttr : public Attr { + std::string Label; +public: + AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {} + + const std::string& getLabel() const { return Label; } + + virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == AsmLabel; + } + static bool classof(const AsmLabelAttr *A) { return true; } +}; + +DEF_SIMPLE_ATTR(AlwaysInline); + +class AliasAttr : public Attr { + std::string Aliasee; +public: + AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {} + + const std::string& getAliasee() const { return Aliasee; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Alias; } + static bool classof(const AliasAttr *A) { return true; } +}; + +class ConstructorAttr : public Attr { + int priority; +public: + ConstructorAttr(int p) : Attr(Constructor), priority(p) {} + + int getPriority() const { return priority; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Constructor; } + static bool classof(const ConstructorAttr *A) { return true; } +}; + +class DestructorAttr : public Attr { + int priority; +public: + DestructorAttr(int p) : Attr(Destructor), priority(p) {} + + int getPriority() const { return priority; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Destructor; } + static bool classof(const DestructorAttr *A) { return true; } +}; + +class GNUInlineAttr : public Attr { +public: + GNUInlineAttr() : Attr(GNUInline) {} + + virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == GNUInline; + } + static bool classof(const GNUInlineAttr *A) { return true; } +}; + +class IBOutletAttr : public Attr { +public: + IBOutletAttr() : Attr(IBOutletKind) {} + + virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == IBOutletKind; + } + static bool classof(const IBOutletAttr *A) { return true; } +}; + +DEF_SIMPLE_ATTR(NoReturn); +DEF_SIMPLE_ATTR(AnalyzerNoReturn); +DEF_SIMPLE_ATTR(Deprecated); + +class SectionAttr : public Attr { + std::string Name; +public: + SectionAttr(const std::string &N) : Attr(Section), Name(N) {} + + const std::string& getName() const { return Name; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == Section; + } + static bool classof(const SectionAttr *A) { return true; } +}; + +DEF_SIMPLE_ATTR(Unavailable); +DEF_SIMPLE_ATTR(Unused); +DEF_SIMPLE_ATTR(Used); +DEF_SIMPLE_ATTR(Weak); +DEF_SIMPLE_ATTR(WeakImport); +DEF_SIMPLE_ATTR(NoThrow); +DEF_SIMPLE_ATTR(Const); +DEF_SIMPLE_ATTR(Pure); + +class NonNullAttr : public Attr { + unsigned* ArgNums; + unsigned Size; +public: + NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull), + ArgNums(0), Size(0) { + + if (size == 0) return; + assert(arg_nums); + ArgNums = new unsigned[size]; + Size = size; + memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); + } + + virtual ~NonNullAttr() { + delete [] ArgNums; + } + + typedef const unsigned *iterator; + iterator begin() const { return ArgNums; } + iterator end() const { return ArgNums + Size; } + unsigned size() const { return Size; } + + bool isNonNull(unsigned arg) const { + return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true; + } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); } + + static bool classof(const Attr *A) { return A->getKind() == NonNull; } + static bool classof(const NonNullAttr *A) { return true; } +}; + +class FormatAttr : public Attr { + std::string Type; + int formatIdx, firstArg; +public: + FormatAttr(const std::string &type, int idx, int first) : Attr(Format), + Type(type), formatIdx(idx), firstArg(first) {} + + const std::string& getType() const { return Type; } + void setType(const std::string &type) { Type = type; } + int getFormatIdx() const { return formatIdx; } + int getFirstArg() const { return firstArg; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) FormatAttr(Type, formatIdx, firstArg); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Format; } + static bool classof(const FormatAttr *A) { return true; } +}; + +class FormatArgAttr : public Attr { + int formatIdx; +public: + FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {} + int getFormatIdx() const { return formatIdx; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) FormatArgAttr(formatIdx); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == FormatArg; } + static bool classof(const FormatArgAttr *A) { return true; } +}; + +class SentinelAttr : public Attr { + int sentinel, NullPos; +public: + SentinelAttr(int sentinel_val, int nullPos) : Attr(Sentinel), + sentinel(sentinel_val), NullPos(nullPos) {} + int getSentinel() const { return sentinel; } + int getNullPos() const { return NullPos; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) SentinelAttr(sentinel, NullPos); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Sentinel; } + static bool classof(const SentinelAttr *A) { return true; } +}; + +class VisibilityAttr : public Attr { +public: + /// @brief An enumeration for the kinds of visibility of symbols. + enum VisibilityTypes { + DefaultVisibility = 0, + HiddenVisibility, + ProtectedVisibility + }; +private: + VisibilityTypes VisibilityType; +public: + VisibilityAttr(VisibilityTypes v) : Attr(Visibility), + VisibilityType(v) {} + + VisibilityTypes getVisibility() const { return VisibilityType; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Visibility; } + static bool classof(const VisibilityAttr *A) { return true; } +}; + +DEF_SIMPLE_ATTR(DLLImport); +DEF_SIMPLE_ATTR(DLLExport); +DEF_SIMPLE_ATTR(FastCall); +DEF_SIMPLE_ATTR(StdCall); +DEF_SIMPLE_ATTR(TransparentUnion); +DEF_SIMPLE_ATTR(ObjCNSObject); +DEF_SIMPLE_ATTR(ObjCException); + +class OverloadableAttr : public Attr { +public: + OverloadableAttr() : Attr(Overloadable) { } + + virtual bool isMerged() const { return false; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) OverloadableAttr; + } + + static bool classof(const Attr *A) { return A->getKind() == Overloadable; } + static bool classof(const OverloadableAttr *) { return true; } +}; + +class BlocksAttr : public Attr { +public: + enum BlocksAttrTypes { + ByRef = 0 + }; +private: + BlocksAttrTypes BlocksAttrType; +public: + BlocksAttr(BlocksAttrTypes t) : Attr(Blocks), BlocksAttrType(t) {} + + BlocksAttrTypes getType() const { return BlocksAttrType; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Blocks; } + static bool classof(const BlocksAttr *A) { return true; } +}; + +class FunctionDecl; + +class CleanupAttr : public Attr { + FunctionDecl *FD; + +public: + CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {} + + const FunctionDecl *getFunctionDecl() const { return FD; } + + virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Cleanup; } + static bool classof(const CleanupAttr *A) { return true; } +}; + +DEF_SIMPLE_ATTR(Nodebug); +DEF_SIMPLE_ATTR(WarnUnusedResult); +DEF_SIMPLE_ATTR(Noinline); + +class RegparmAttr : public Attr { + unsigned NumParams; + +public: + RegparmAttr(unsigned np) : Attr(Regparm), NumParams(np) {} + + unsigned getNumParams() const { return NumParams; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) RegparmAttr(NumParams); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Regparm; } + static bool classof(const RegparmAttr *A) { return true; } +}; + +// Checker-specific attributes. +DEF_SIMPLE_ATTR(CFReturnsRetained); +DEF_SIMPLE_ATTR(NSReturnsRetained); + +#undef DEF_SIMPLE_ATTR + +} // end namespace clang + +#endif diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def new file mode 100644 index 000000000000..671c4bd6cd4a --- /dev/null +++ b/include/clang/AST/Builtins.def @@ -0,0 +1,389 @@ +//===--- Builtins.def - Builtin function info database ----------*- 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 standard builtin function database. Users of this file +// must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: this needs to be the full list supported by GCC. Right now, I'm just +// adding stuff on demand. +// +// FIXME: This should really be a .td file, but that requires modifying tblgen. +// Perhaps tblgen should have plugins. + +// The first value provided to the macro specifies the function name of the +// builtin, and results in a clang::builtin::BIXX enum value for XX. + +// The second value provided to the macro specifies the type of the function +// (result value, then each argument) as follows: +// v -> void +// b -> boolean +// c -> char +// s -> short +// i -> int +// f -> float +// d -> double +// z -> size_t +// F -> constant CFString +// a -> __builtin_va_list +// A -> "reference" to __builtin_va_list +// V -> Vector, following num elements and a base type. +// P -> FILE +// . -> "...". This may only occur at the end of the function list. +// +// Types maybe 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 +// +// Types may be postfixed with the following modifiers: +// * -> pointer +// & -> reference +// C -> const + +// The third value provided to the macro specifies information about attributes +// of the function. These must be kept in sync with the predicates in the +// Builtin::Context class. Currently we have: +// n -> nothrow +// c -> const +// F -> this is a libc/libm function with a '__builtin_' prefix added. +// f -> this is a libc/libm function without the '__builtin_' prefix. It can +// be followed by ':headername:' to state which header this function +// comes from. +// p:N: -> this is a printf-like function whose Nth argument is the format +// string. +// P:N: -> similar to the p:N: attribute, but the function is like vprintf +// in that it accepts its arguments as a va_list rather than +// through an ellipsis +// e -> const, but only when -fmath-errno=0 +// FIXME: gcc has nonnull + +#if defined(BUILTIN) && !defined(LIBBUILTIN) +# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Standard libc/libm functions: +BUILTIN(__builtin_huge_val, "d", "nc") +BUILTIN(__builtin_huge_valf, "f", "nc") +BUILTIN(__builtin_huge_vall, "Ld", "nc") +BUILTIN(__builtin_inf , "d" , "nc") +BUILTIN(__builtin_inff , "f" , "nc") +BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_nan, "dcC*" , "ncF") +BUILTIN(__builtin_nanf, "fcC*" , "ncF") +BUILTIN(__builtin_nanl, "LdcC*", "ncF") +BUILTIN(__builtin_nans, "dcC*" , "ncF") +BUILTIN(__builtin_nansf, "fcC*" , "ncF") +BUILTIN(__builtin_nansl, "LdcC*", "ncF") +BUILTIN(__builtin_abs , "ii" , "ncF") +BUILTIN(__builtin_fabs , "dd" , "ncF") +BUILTIN(__builtin_fabsf, "ff" , "ncF") +BUILTIN(__builtin_fabsl, "LdLd", "ncF") +BUILTIN(__builtin_copysign, "ddd", "ncF") +BUILTIN(__builtin_copysignf, "fff", "ncF") +BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") +BUILTIN(__builtin_powi , "ddi" , "nc") +BUILTIN(__builtin_powif, "ffi" , "nc") +BUILTIN(__builtin_powil, "LdLdi", "nc") + +// FP Comparisons. +BUILTIN(__builtin_isgreater , "i.", "nc") +BUILTIN(__builtin_isgreaterequal, "i.", "nc") +BUILTIN(__builtin_isless , "i.", "nc") +BUILTIN(__builtin_islessequal , "i.", "nc") +BUILTIN(__builtin_islessgreater , "i.", "nc") +BUILTIN(__builtin_isunordered , "i.", "nc") + +// Builtins for arithmetic. +BUILTIN(__builtin_clz , "iUi" , "nc") +BUILTIN(__builtin_clzl , "iULi" , "nc") +BUILTIN(__builtin_clzll, "iULLi", "nc") +// TODO: int clzimax(uintmax_t) +BUILTIN(__builtin_ctz , "iUi" , "nc") +BUILTIN(__builtin_ctzl , "iULi" , "nc") +BUILTIN(__builtin_ctzll, "iULLi", "nc") +// TODO: int ctzimax(uintmax_t) +BUILTIN(__builtin_ffs , "iUi" , "nc") +BUILTIN(__builtin_ffsl , "iULi" , "nc") +BUILTIN(__builtin_ffsll, "iULLi", "nc") +BUILTIN(__builtin_parity , "iUi" , "nc") +BUILTIN(__builtin_parityl , "iULi" , "nc") +BUILTIN(__builtin_parityll, "iULLi", "nc") +BUILTIN(__builtin_popcount , "iUi" , "nc") +BUILTIN(__builtin_popcountl , "iULi" , "nc") +BUILTIN(__builtin_popcountll, "iULLi", "nc") + +// FIXME: These type signatures are not correct for targets with int != 32-bits +// or with ULL != 64-bits. +BUILTIN(__builtin_bswap32, "UiUi", "nc") +BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") + +// Random GCC builtins +BUILTIN(__builtin_constant_p, "Us.", "nc") +BUILTIN(__builtin_classify_type, "i.", "nc") +BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin_va_start, "vA.", "n") +BUILTIN(__builtin_va_end, "vA", "n") +BUILTIN(__builtin_va_copy, "vAA", "n") +BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_bcmp, "iv*v*z", "n") +BUILTIN(__builtin_bcopy, "vv*v*z", "n") +BUILTIN(__builtin_bzero, "vv*z", "n") +BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") +BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memmove, "v*v*vC*z", "nF") +BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memset, "v*v*iz", "nF") +BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcat, "c*c*cC*", "nF") +BUILTIN(__builtin_strchr, "c*cC*i", "nF") +BUILTIN(__builtin_strcmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_strcspn, "zcC*cC*", "nF") +BUILTIN(__builtin_strdup, "c*cC*", "nF") +BUILTIN(__builtin_strlen, "zcC*", "nF") +BUILTIN(__builtin_strncasecmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncat, "c*c*cC*z", "nF") +BUILTIN(__builtin_strncmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strndup, "c*cC*z", "nF") +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_extract_return_addr, "v*v*", "n") +BUILTIN(__builtin_frame_address, "v*Ui", "n") +BUILTIN(__builtin_flt_rounds, "i", "nc") +BUILTIN(__builtin_setjmp, "iv**", "") +BUILTIN(__builtin_longjmp, "vv**i", "") +BUILTIN(__builtin_unwind_init, "v", "") + +// GCC Object size checking builtins +BUILTIN(__builtin_object_size, "zv*i", "n") +BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memset_chk, "v*v*izz", "nF") +BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:") +BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:") +BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:") +BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:") +BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:") +BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:") +BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:") +BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") + +BUILTIN(__builtin_expect, "iii" , "nc") +BUILTIN(__builtin_prefetch, "vvC*.", "nc") +BUILTIN(__builtin_trap, "v", "n") + +BUILTIN(__builtin_shufflevector, "v." , "nc") + +BUILTIN(__builtin_alloca, "v*z" , "n") + +// "Overloaded" Atomic operator builtins. These are overloaded to support data +// types of i8, i16, i32, i64, and i128. The front-end sees calls to the +// non-suffixed version of these (which has a bogus type) and transforms them to +// the right overloaded version in Sema (plus casts). + +// FIXME: These assume that char -> i8, short -> i16, int -> i32, +// long long -> i64. + +BUILTIN(__sync_fetch_and_add, "v.", "") +BUILTIN(__sync_fetch_and_add_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_add_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_add_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_add_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_add_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_fetch_and_sub, "v.", "") +BUILTIN(__sync_fetch_and_sub_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_sub_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_sub_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_sub_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_fetch_and_or, "v.", "") +BUILTIN(__sync_fetch_and_or_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_or_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_or_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_or_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_or_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_fetch_and_and, "v.", "") +BUILTIN(__sync_fetch_and_and_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_and_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_and_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_and_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_and_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_fetch_and_xor, "v.", "") +BUILTIN(__sync_fetch_and_xor_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_xor_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_fetch_and_nand, "v.", "") +BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n") +BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n") +BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n") +BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n") + + +BUILTIN(__sync_add_and_fetch, "v.", "") +BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_add_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_add_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_add_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_add_and_fetch_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_sub_and_fetch, "v.", "") +BUILTIN(__sync_sub_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_sub_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_sub_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_sub_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_or_and_fetch, "v.", "") +BUILTIN(__sync_or_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_or_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_or_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_or_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_or_and_fetch_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_and_and_fetch, "v.", "") +BUILTIN(__sync_and_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_and_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_and_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_and_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_and_and_fetch_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_xor_and_fetch, "v.", "") +BUILTIN(__sync_xor_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_xor_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_nand_and_fetch, "v.", "") +BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n") +BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n") +BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n") +BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n") + + +BUILTIN(__sync_bool_compare_and_swap, "v.", "") +BUILTIN(__sync_bool_compare_and_swap_1, "bc*cc.", "n") +BUILTIN(__sync_bool_compare_and_swap_2, "bs*ss.", "n") +BUILTIN(__sync_bool_compare_and_swap_4, "bi*ii.", "n") +BUILTIN(__sync_bool_compare_and_swap_8, "bLLi*LLi.", "n") +BUILTIN(__sync_bool_compare_and_swap_16, "bLLLi*LLLiLLLi.", "n") + +BUILTIN(__sync_val_compare_and_swap, "v.", "") +BUILTIN(__sync_val_compare_and_swap_1, "cc*cc.", "n") +BUILTIN(__sync_val_compare_and_swap_2, "ss*ss.", "n") +BUILTIN(__sync_val_compare_and_swap_4, "ii*ii.", "n") +BUILTIN(__sync_val_compare_and_swap_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLi*LLLiLLLi.", "n") + +BUILTIN(__sync_lock_test_and_set, "v.", "") +BUILTIN(__sync_lock_test_and_set_1, "cc*c.", "n") +BUILTIN(__sync_lock_test_and_set_2, "ss*s.", "n") +BUILTIN(__sync_lock_test_and_set_4, "ii*i.", "n") +BUILTIN(__sync_lock_test_and_set_8, "LLiLLi*LLi.", "n") +BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLi*LLLi.", "n") + +BUILTIN(__sync_lock_release, "v.", "") +BUILTIN(__sync_lock_release_1, "vc*.", "n") +BUILTIN(__sync_lock_release_2, "vs*.", "n") +BUILTIN(__sync_lock_release_4, "vi*.", "n") +BUILTIN(__sync_lock_release_8, "vLLi*.", "n") +BUILTIN(__sync_lock_release_16, "vLLLi*.", "n") + + + +// Non-overloaded atomic builtins. +BUILTIN(__sync_synchronize, "v.", "n") +// LLVM instruction builtin [Clang extension]. +BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n") +// GCC does not support these, they are a Clang extension. +BUILTIN(__sync_fetch_and_min, "ii*i", "n") +BUILTIN(__sync_fetch_and_max, "ii*i", "n") +BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n") +BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n") + +// Builtin library functions +LIBBUILTIN(alloca, "v*z", "f", "stdlib.h") +LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h") +LIBBUILTIN(malloc, "v*z", "f", "stdlib.h") +LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h") +LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h") +LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h") +LIBBUILTIN(memset, "v*v*iz", "f", "string.h") +LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h") +LIBBUILTIN(strchr, "c*cC*i", "f", "string.h") +LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h") +LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h") +LIBBUILTIN(strlen, "zcC*", "f", "string.h") +LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h") +LIBBUILTIN(strncpy, "c*c*cC*z", "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(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, "iP*cC*a", "fP:1:", "stdio.h") +LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h") +LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h") + +// FIXME: This type isn't very correct, it should be +// id objc_msgSend(id, SEL) +// but we need new type letters for that. +LIBBUILTIN(objc_msgSend, "v*.", "f", "objc/message.h") + +// FIXME: asprintf and vasprintf aren't C99 functions. Should they be +// target-specific builtins, perhaps? + +// Builtin math library functions +LIBBUILTIN(pow, "ddd", "fe", "math.h") +LIBBUILTIN(powl, "LdLdLd", "fe", "math.h") +LIBBUILTIN(powf, "fff", "fe", "math.h") + +LIBBUILTIN(sqrt, "dd", "fe", "math.h") +LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h") +LIBBUILTIN(sqrtf, "ff", "fe", "math.h") + +LIBBUILTIN(sin, "dd", "fe", "math.h") +LIBBUILTIN(sinl, "LdLd", "fe", "math.h") +LIBBUILTIN(sinf, "ff", "fe", "math.h") + +LIBBUILTIN(cos, "dd", "fe", "math.h") +LIBBUILTIN(cosl, "LdLd", "fe", "math.h") +LIBBUILTIN(cosf, "ff", "fe", "math.h") + +#undef BUILTIN +#undef LIBBUILTIN diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h new file mode 100644 index 000000000000..b16d3bf34139 --- /dev/null +++ b/include/clang/AST/Builtins.h @@ -0,0 +1,137 @@ +//===--- Builtins.h - Builtin function header -------------------*- 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 enum values for all the target-independent builtin +// functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_BUILTINS_H +#define LLVM_CLANG_AST_BUILTINS_H + +#include <cstring> +#include <string> +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class TargetInfo; + class IdentifierTable; + class ASTContext; + class QualType; + +namespace Builtin { +enum ID { + NotBuiltin = 0, // This is not a builtin function. +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/AST/Builtins.def" + FirstTSBuiltin +}; + +struct Info { + const char *Name, *Type, *Attributes, *HeaderName; + bool Suppressed; + + bool operator==(const Info &RHS) const { + return !strcmp(Name, RHS.Name) && + !strcmp(Type, RHS.Type) && + !strcmp(Attributes, RHS.Attributes); + } + bool operator!=(const Info &RHS) const { return !(*this == RHS); } +}; + +/// Builtin::Context - This holds information about target-independent and +/// target-specific builtins, allowing easy queries by clients. +class Context { + const Info *TSRecords; + unsigned NumTSRecords; +public: + Context() : TSRecords(0), NumTSRecords(0) {} + + /// \brief Load all of the target builtins. This should be called + /// prior to initializing the builtin identifiers. + void InitializeTargetBuiltins(const TargetInfo &Target); + + /// 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); + + /// \brief Popular the vector with the names of all of the builtins. + void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, + bool NoBuiltins); + + /// Builtin::GetName - Return the identifier name for the specified builtin, + /// e.g. "__builtin_abs". + const char *GetName(unsigned ID) const { + return GetRecord(ID).Name; + } + + /// isConst - Return true if this function has no side effects and doesn't + /// read memory. + bool isConst(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'c') != 0; + } + + /// isNoThrow - Return true if we know this builtin never throws an exception. + bool isNoThrow(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'n') != 0; + } + + /// isLibFunction - Return true if this is a builtin for a libc/libm function, + /// with a "__builtin_" prefix (e.g. __builtin_abs). + bool isLibFunction(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'F') != 0; + } + + /// \brief Determines whether this builtin is a predefined libc/libm + /// function, such as "malloc", where we know the signature a + /// priori. + bool isPredefinedLibFunction(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'f') != 0; + } + + /// \brief If this is a library function that comes from a specific + /// header, retrieve that header name. + const char *getHeaderName(unsigned ID) const { + return GetRecord(ID).HeaderName; + } + + /// \brief Determine whether this builtin is like printf in its + /// formatting rules and, if so, set the index to the format string + /// argument and whether this function as a va_list argument. + bool isPrintfLike(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 + /// disabled. + bool isConstWithoutErrno(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'e') != 0; + } + + /// GetBuiltinType - Return the type for the specified builtin. + enum GetBuiltinTypeError { + GE_None, //< No error + GE_Missing_FILE //< Missing the FILE type from <stdio.h> + }; + QualType GetBuiltinType(unsigned ID, ASTContext &Context, + GetBuiltinTypeError &Error) const; +private: + const Info &GetRecord(unsigned ID) const; +}; + +} +} // end namespace clang +#endif diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h new file mode 100644 index 000000000000..7a9ee01d4f62 --- /dev/null +++ b/include/clang/AST/CFG.h @@ -0,0 +1,405 @@ +//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CFG_H +#define LLVM_CLANG_CFG_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" +#include <list> +#include <vector> +#include <cassert> + +namespace clang { + class Stmt; + class Expr; + class CFG; + class PrinterHelper; + class BlockEdge; + +/// CFGBlock - Represents a single basic block in a source-level CFG. +/// It consists of: +/// +/// (1) A set of statements/expressions (which may contain subexpressions). +/// (2) A "terminator" statement (not in the set of statements). +/// (3) A list of successors and predecessors. +/// +/// Terminator: The terminator represents the type of control-flow that occurs +/// at the end of the basic block. The terminator is a Stmt* referring to an +/// AST node that has control-flow: if-statements, breaks, loops, etc. +/// If the control-flow is conditional, the condition expression will appear +/// within the set of statements in the block (usually the last statement). +/// +/// Predecessors: the order in the set of predecessors is arbitrary. +/// +/// Successors: the order in the set of successors is NOT arbitrary. We +/// currently have the following orderings based on the terminator: +/// +/// Terminator Successor Ordering +/// ----------------------------------------------------- +/// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS +/// +class CFGBlock { + typedef std::vector<Stmt*> StatementListTy; + /// Stmts - The set of statements in the basic block. + StatementListTy Stmts; + + /// Label - An (optional) label that prefixes the executable + /// statements in the block. When this variable is non-NULL, it is + /// either an instance of LabelStmt or SwitchCase. + Stmt *Label; + + /// Terminator - The terminator for a basic block that + /// indicates the type of control-flow that occurs between a block + /// and its successors. + Stmt *Terminator; + + /// LoopTarget - Some blocks are used to represent the "loop edge" to + /// the start of a loop from within the loop body. This Stmt* will be + /// refer to the loop statement for such blocks (and be null otherwise). + const Stmt *LoopTarget; + + /// BlockID - A numerical ID assigned to a CFGBlock during construction + /// of the CFG. + unsigned BlockID; + + /// Predecessors/Successors - Keep track of the predecessor / successor + /// CFG blocks. + typedef std::vector<CFGBlock*> AdjacentBlocks; + AdjacentBlocks Preds; + AdjacentBlocks Succs; + +public: + explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL), + LoopTarget(NULL), BlockID(blockid) {} + ~CFGBlock() {}; + + // Statement iterators + typedef StatementListTy::iterator iterator; + typedef StatementListTy::const_iterator const_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + Stmt* front() const { return Stmts.front(); } + Stmt* back() const { return Stmts.back(); } + + iterator begin() { return Stmts.begin(); } + iterator end() { return Stmts.end(); } + const_iterator begin() const { return Stmts.begin(); } + const_iterator end() const { return Stmts.end(); } + + reverse_iterator rbegin() { return Stmts.rbegin(); } + reverse_iterator rend() { return Stmts.rend(); } + const_reverse_iterator rbegin() const { return Stmts.rbegin(); } + const_reverse_iterator rend() const { return Stmts.rend(); } + + unsigned size() const { return Stmts.size(); } + bool empty() const { return Stmts.empty(); } + + Stmt* operator[](size_t i) const { assert (i < size()); return Stmts[i]; } + + // CFG iterators + typedef AdjacentBlocks::iterator pred_iterator; + typedef AdjacentBlocks::const_iterator const_pred_iterator; + typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; + + typedef AdjacentBlocks::iterator succ_iterator; + typedef AdjacentBlocks::const_iterator const_succ_iterator; + typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + const_pred_iterator pred_begin() const { return Preds.begin(); } + const_pred_iterator pred_end() const { return Preds.end(); } + + pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); } + pred_reverse_iterator pred_rend() { return Preds.rend(); } + const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } + const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + const_succ_iterator succ_begin() const { return Succs.begin(); } + const_succ_iterator succ_end() const { return Succs.end(); } + + succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); } + succ_reverse_iterator succ_rend() { return Succs.rend(); } + const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } + const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } + + unsigned succ_size() const { return Succs.size(); } + bool succ_empty() const { return Succs.empty(); } + + unsigned pred_size() const { return Preds.size(); } + bool pred_empty() const { return Preds.empty(); } + + // Manipulation of block contents + + void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); } + void setTerminator(Stmt* Statement) { Terminator = Statement; } + void setLabel(Stmt* Statement) { Label = Statement; } + void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + + Stmt* getTerminator() { return Terminator; } + const Stmt* getTerminator() const { return Terminator; } + + Stmt* getTerminatorCondition(); + + const Stmt* getTerminatorCondition() const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(); + } + + const Stmt *getLoopTarget() const { return LoopTarget; } + + bool hasBinaryBranchTerminator() const; + + Stmt* getLabel() { return Label; } + const Stmt* getLabel() const { return Label; } + + void reverseStmts(); + + void addSuccessor(CFGBlock* Block) { + Block->Preds.push_back(this); + Succs.push_back(Block); + } + + unsigned getBlockID() const { return BlockID; } + + void dump(const CFG* cfg) const; + void print(llvm::raw_ostream& OS, const CFG* cfg) const; + void printTerminator(llvm::raw_ostream& OS) const; +}; + + +/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// control-flow of a Stmt. The Stmt can represent an entire function body, +/// or a single expression. A CFG will always contain one empty block that +/// represents the Exit point of the CFG. A CFG will also contain a designated +/// Entry block. The CFG solely represents control-flow; it consists of +/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG +/// was constructed from. +class CFG { +public: + //===--------------------------------------------------------------------===// + // CFG Construction & Manipulation. + //===--------------------------------------------------------------------===// + + /// buildCFG - Builds a CFG from an AST. The responsibility to free the + /// constructed CFG belongs to the caller. + static CFG* buildCFG(Stmt* AST); + + /// createBlock - Create a new block in the CFG. The CFG owns the block; + /// the caller should not directly free it. + CFGBlock* createBlock(); + + /// setEntry - Set the entry block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// entry block has no predecessors and contains no statements. + void setEntry(CFGBlock *B) { Entry = B; } + + /// setExit - Set the exit block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// exit block has no successors and contains no statements. + void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; } + + //===--------------------------------------------------------------------===// + // Block Iterators + //===--------------------------------------------------------------------===// + + typedef std::list<CFGBlock> CFGBlockListTy; + + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + CFGBlock& front() { return Blocks.front(); } + CFGBlock& back() { return Blocks.back(); } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + const_iterator begin() const { return Blocks.begin(); } + const_iterator end() const { return Blocks.end(); } + + reverse_iterator rbegin() { return Blocks.rbegin(); } + reverse_iterator rend() { return Blocks.rend(); } + const_reverse_iterator rbegin() const { return Blocks.rbegin(); } + const_reverse_iterator rend() const { return Blocks.rend(); } + + CFGBlock& getEntry() { return *Entry; } + const CFGBlock& getEntry() const { return *Entry; } + CFGBlock& getExit() { return *Exit; } + const CFGBlock& getExit() const { return *Exit; } + + CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; } + + //===--------------------------------------------------------------------===// + // Member templates useful for various batch operations over CFGs. + //===--------------------------------------------------------------------===// + + template <typename CALLBACK> + void VisitBlockStmts(CALLBACK& O) const { + for (const_iterator I=begin(), E=end(); I != E; ++I) + for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI != BE; ++BI) + O(*BI); + } + + //===--------------------------------------------------------------------===// + // CFG Introspection. + //===--------------------------------------------------------------------===// + + struct BlkExprNumTy { + const signed Idx; + explicit BlkExprNumTy(signed idx) : Idx(idx) {} + explicit BlkExprNumTy() : Idx(-1) {} + operator bool() const { return Idx >= 0; } + operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } + }; + + bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + BlkExprNumTy getBlkExprNum(const Stmt* S); + unsigned getNumBlkExprs(); + + unsigned getNumBlockIDs() const { return NumBlockIDs; } + + //===--------------------------------------------------------------------===// + // CFG Debugging: Pretty-Printing and Visualization. + //===--------------------------------------------------------------------===// + + void viewCFG() const; + void print(llvm::raw_ostream& OS) const; + void dump() const; + + //===--------------------------------------------------------------------===// + // Internal: constructors and data. + //===--------------------------------------------------------------------===// + + CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), + BlkExprMap(NULL) {}; + + ~CFG(); + + llvm::BumpPtrAllocator& getAllocator() { + return Alloc; + } + +private: + CFGBlock* Entry; + CFGBlock* Exit; + CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch + // for indirect gotos + CFGBlockListTy Blocks; + unsigned NumBlockIDs; + + // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. + // It represents a map from Expr* to integers to record the set of + // block-level expressions and their "statement number" in the CFG. + void* BlkExprMap; + + /// Alloc - An internal allocator. + llvm::BumpPtrAllocator Alloc; +}; +} // end namespace clang + +//===----------------------------------------------------------------------===// +// GraphTraits specializations for CFG basic block graphs (source-level CFGs) +//===----------------------------------------------------------------------===// + +namespace llvm { + +// Traits for: CFGBlock + +template <> struct GraphTraits<clang::CFGBlock* > { + typedef clang::CFGBlock NodeType; + typedef clang::CFGBlock::succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<const clang::CFGBlock* > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(const clang::CFGBlock* BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > { + typedef const clang::CFGBlock NodeType; + typedef clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +// Traits for: CFG + +template <> struct GraphTraits<clang::CFG* > + : public GraphTraits<clang::CFGBlock* > { + + typedef clang::CFG::iterator nodes_iterator; + + static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits< const clang::CFG* > + : public GraphTraits< const clang::CFGBlock* > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); } +}; + +template <> struct GraphTraits<Inverse<const clang::CFG*> > + : public GraphTraits<Inverse<const clang::CFGBlock*> > { + + typedef clang::CFG::const_iterator nodes_iterator; + + static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();} + static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h new file mode 100644 index 000000000000..e134aed73d77 --- /dev/null +++ b/include/clang/AST/Decl.h @@ -0,0 +1,1409 @@ +//===--- Decl.h - Classes for representing declarations ---------*- 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 Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECL_H +#define LLVM_CLANG_AST_DECL_H + +#include "clang/AST/APValue.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" + +namespace clang { +class Expr; +class FunctionTemplateDecl; +class Stmt; +class CompoundStmt; +class StringLiteral; + +/// TranslationUnitDecl - The top declaration context. +class TranslationUnitDecl : public Decl, public DeclContext { + TranslationUnitDecl() + : Decl(TranslationUnit, 0, SourceLocation()), + DeclContext(TranslationUnit) {} +public: + static TranslationUnitDecl *Create(ASTContext &C); + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; } + static bool classof(const TranslationUnitDecl *D) { return true; } + static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { + return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D)); + } + static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// NamedDecl - This represents a decl with a name. Many decls have names such +/// as ObjCMethodDecl, but not @class, etc. +class NamedDecl : public Decl { + /// Name - The name of this declaration, which is typically a normal + /// identifier but may also be a special kind of name (C++ + /// constructor, Objective-C selector, etc.) + DeclarationName Name; + +protected: + NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) + : Decl(DK, DC, L), Name(N) { } + +public: + /// getIdentifier - Get the identifier that names this declaration, + /// if there is one. This will return NULL if this declaration has + /// no name (e.g., for an unnamed class) or if the name is a special + /// name (C++ constructor, Objective-C selector, etc.). + IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); } + + /// getNameAsCString - Get the name of identifier for this declaration as a + /// C string (const char*). This requires that the declaration have a name + /// and that it be a simple identifier. + const char *getNameAsCString() const { + assert(getIdentifier() && "Name is not a simple identifier"); + return getIdentifier()->getName(); + } + + /// getDeclName - Get the actual, stored name of the declaration, + /// which may be a special name. + DeclarationName getDeclName() const { return Name; } + + /// \brief Set the name of this declaration. + void setDeclName(DeclarationName N) { Name = N; } + + /// getNameAsString - Get a human-readable name for the declaration, even if + /// it is one of the special kinds of names (C++ constructor, Objective-C + /// selector, etc). Creating this name requires expensive string + /// manipulation, so it should be called only when performance doesn't matter. + /// For simple declarations, getNameAsCString() should suffice. + std::string getNameAsString() const { return Name.getAsString(); } + + /// getQualifiedNameAsString - Returns human-readable qualified name for + /// declaration, like A::B::i, for i being member of namespace A::B. + /// If declaration is not member of context which can be named (record, + /// namespace), it will return same result as getNameAsString(). + /// Creating this name is expensive, so it should be called only when + /// performance doesn't matter. + std::string getQualifiedNameAsString() const; + + /// declarationReplaces - Determine whether this declaration, if + /// known to be well-formed within its context, will replace the + /// declaration OldD if introduced into scope. A declaration will + /// replace another declaration if, for example, it is a + /// redeclaration of the same variable or function, but not if it is + /// a declaration of a different kind (function vs. class) or an + /// overloaded function. + bool declarationReplaces(NamedDecl *OldD) const; + + /// \brief Determine whether this declaration has linkage. + bool hasLinkage() const; + + static bool classof(const Decl *D) { + return D->getKind() >= NamedFirst && D->getKind() <= NamedLast; + } + static bool classof(const NamedDecl *D) { return true; } +}; + +/// NamespaceDecl - Represent a C++ namespace. +class NamespaceDecl : public NamedDecl, public DeclContext { + SourceLocation LBracLoc, RBracLoc; + + // For extended namespace definitions: + // + // namespace A { int x; } + // namespace A { int y; } + // + // there will be one NamespaceDecl for each declaration. + // NextNamespace points to the next extended declaration. + // OrigNamespace points to the original namespace declaration. + // OrigNamespace of the first namespace decl points to itself. + NamespaceDecl *OrigNamespace, *NextNamespace; + + NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) + : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) { + OrigNamespace = this; + NextNamespace = 0; + } +public: + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + + virtual void Destroy(ASTContext& C); + + NamespaceDecl *getNextNamespace() { return NextNamespace; } + const NamespaceDecl *getNextNamespace() const { return NextNamespace; } + void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } + + NamespaceDecl *getOriginalNamespace() const { + return OrigNamespace; + } + void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; } + + SourceRange getSourceRange() const { + return SourceRange(LBracLoc, RBracLoc); + } + + SourceLocation getLBracLoc() const { return LBracLoc; } + SourceLocation getRBracLoc() const { return RBracLoc; } + void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; } + void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == Namespace; } + static bool classof(const NamespaceDecl *D) { return true; } + static DeclContext *castToDeclContext(const NamespaceDecl *D) { + return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D)); + } + static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ValueDecl - Represent the declaration of a variable (in which case it is +/// an lvalue) a function (in which case it is a function designator) or +/// an enum constant. +class ValueDecl : public NamedDecl { + QualType DeclType; + +protected: + ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T) + : NamedDecl(DK, DC, L, N), DeclType(T) {} +public: + QualType getType() const { return DeclType; } + void setType(QualType newType) { DeclType = newType; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= ValueFirst && D->getKind() <= ValueLast; + } + static bool classof(const ValueDecl *D) { return true; } +}; + +/// \brief Structure used to store a statement, the constant value to +/// which it was evaluated (if any), and whether or not the statement +/// is an integral constant expression (if known). +struct EvaluatedStmt { + EvaluatedStmt() : WasEvaluated(false), CheckedICE(false), IsICE(false) { } + + /// \brief Whether this statement was already evaluated. + bool WasEvaluated : 1; + + /// \brief Whether we already checked whether this statement was an + /// integral constant expression. + bool CheckedICE : 1; + + /// \brief Whether this statement is an integral constant + /// expression. Only valid if CheckedICE is true. + bool IsICE : 1; + + Stmt *Value; + APValue Evaluated; +}; + +/// VarDecl - An instance of this class is created to represent a variable +/// declaration or definition. +class VarDecl : public ValueDecl { +public: + enum StorageClass { + None, Auto, Register, Extern, Static, PrivateExtern + }; + + /// getStorageClassSpecifierString - Return the string used to + /// specify the storage class \arg SC. + /// + /// It is illegal to call this function with SC == None. + static const char *getStorageClassSpecifierString(StorageClass SC); + +private: + mutable llvm::PointerUnion<Stmt *, EvaluatedStmt *> Init; + // FIXME: This can be packed into the bitfields in Decl. + unsigned SClass : 3; + bool ThreadSpecified : 1; + bool HasCXXDirectInit : 1; + + /// DeclaredInCondition - Whether this variable was declared in a + /// condition, e.g., if (int x = foo()) { ... }. + bool DeclaredInCondition : 1; + + /// \brief The previous declaration of this variable. + VarDecl *PreviousDeclaration; + + // Move to DeclGroup when it is implemented. + SourceLocation TypeSpecStartLoc; + friend class StmtIteratorBase; +protected: + VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + QualType T, StorageClass SC, SourceLocation TSSL = SourceLocation()) + : ValueDecl(DK, DC, L, Id, T), Init(), + ThreadSpecified(false), HasCXXDirectInit(false), + DeclaredInCondition(false), PreviousDeclaration(0), + TypeSpecStartLoc(TSSL) { + SClass = SC; + } +public: + static VarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, StorageClass S, + SourceLocation TypeSpecStartLoc = SourceLocation()); + + virtual ~VarDecl(); + virtual void Destroy(ASTContext& C); + + StorageClass getStorageClass() const { return (StorageClass)SClass; } + void setStorageClass(StorageClass SC) { SClass = SC; } + + SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; } + void setTypeSpecStartLoc(SourceLocation SL) { + TypeSpecStartLoc = SL; + } + + const Expr *getInit() const { + if (Init.isNull()) + return 0; + + const Stmt *S = Init.dyn_cast<Stmt *>(); + if (!S) + S = Init.get<EvaluatedStmt *>()->Value; + + return (const Expr*) S; + } + Expr *getInit() { + if (Init.isNull()) + return 0; + + Stmt *S = Init.dyn_cast<Stmt *>(); + if (!S) + S = Init.get<EvaluatedStmt *>()->Value; + + return (Expr*) S; + } + + /// \brief Retrieve the address of the initializer expression. + Stmt **getInitAddress() { + if (Init.is<Stmt *>()) + return reinterpret_cast<Stmt **>(&Init); // FIXME: ugly hack + return &Init.get<EvaluatedStmt *>()->Value; + } + + void setInit(ASTContext &C, Expr *I); + + /// \brief Note that constant evaluation has computed the given + /// value for this variable's initializer. + void setEvaluatedValue(ASTContext &C, const APValue &Value) const { + EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); + if (!Eval) { + Stmt *S = Init.get<Stmt *>(); + Eval = new (C) EvaluatedStmt; + Eval->Value = S; + Init = Eval; + } + + Eval->WasEvaluated = true; + Eval->Evaluated = Value; + } + + /// \brief Return the already-evaluated value of this variable's + /// initializer, or NULL if the value is not yet known. + APValue *getEvaluatedValue() const { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) + if (Eval->WasEvaluated) + return &Eval->Evaluated; + + return 0; + } + + /// \brief Determines whether it is already known whether the + /// initializer is an integral constant expression or not. + bool isInitKnownICE() const { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) + return Eval->CheckedICE; + + return false; + } + + /// \brief Determines whether the initializer is an integral + /// constant expression. + /// + /// \pre isInitKnownICE() + bool isInitICE() const { + assert(isInitKnownICE() && + "Check whether we already know that the initializer is an ICE"); + return Init.get<EvaluatedStmt *>()->IsICE; + } + + /// \brief Note that we now know whether the initializer is an + /// integral constant expression. + void setInitKnownICE(ASTContext &C, bool IsICE) const { + EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); + if (!Eval) { + Stmt *S = Init.get<Stmt *>(); + Eval = new (C) EvaluatedStmt; + Eval->Value = S; + Init = Eval; + } + + Eval->CheckedICE = true; + Eval->IsICE = IsICE; + } + + /// \brief Retrieve the definition of this variable, which may come + /// from a previous declaration. Def will be set to the VarDecl that + /// contains the initializer, and the result will be that + /// initializer. + const Expr *getDefinition(const VarDecl *&Def) const; + + void setThreadSpecified(bool T) { ThreadSpecified = T; } + bool isThreadSpecified() const { + return ThreadSpecified; + } + + void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; } + + /// hasCXXDirectInitializer - If true, the initializer was a direct + /// initializer, e.g: "int x(1);". The Init expression will be the expression + /// inside the parens or a "ClassType(a,b,c)" class constructor expression for + /// class types. Clients can distinguish between "int x(1);" and "int x=1;" + /// by checking hasCXXDirectInitializer. + /// + bool hasCXXDirectInitializer() const { + return HasCXXDirectInit; + } + + /// isDeclaredInCondition - Whether this variable was declared as + /// part of a condition in an if/switch/while statement, e.g., + /// @code + /// if (int x = foo()) { ... } + /// @endcode + bool isDeclaredInCondition() const { + return DeclaredInCondition; + } + void setDeclaredInCondition(bool InCondition) { + DeclaredInCondition = InCondition; + } + + /// getPreviousDeclaration - Return the previous declaration of this + /// variable. + const VarDecl *getPreviousDeclaration() const { return PreviousDeclaration; } + + void setPreviousDeclaration(VarDecl *PrevDecl) { + PreviousDeclaration = PrevDecl; + } + + /// hasLocalStorage - Returns true if a variable with function scope + /// is a non-static local variable. + bool hasLocalStorage() const { + if (getStorageClass() == None) + return !isFileVarDecl(); + + // Return true for: Auto, Register. + // Return false for: Extern, Static, PrivateExtern. + + return getStorageClass() <= Register; + } + + /// hasExternStorage - Returns true if a variable has extern or + /// __private_extern__ storage. + bool hasExternalStorage() const { + return getStorageClass() == Extern || getStorageClass() == PrivateExtern; + } + + /// hasGlobalStorage - Returns true for all variables that do not + /// have local storage. This includs all global variables as well + /// as static variables declared within a function. + bool hasGlobalStorage() const { return !hasLocalStorage(); } + + /// isBlockVarDecl - Returns true for local variable declarations. Note that + /// this includes static variables inside of functions. + /// + /// void foo() { int x; static int y; extern int z; } + /// + bool isBlockVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getDeclContext()) + return DC->getLookupContext()->isFunctionOrMethod(); + return false; + } + + /// \brief Determines whether this is a static data member. + /// + /// This will only be true in C++, and applies to, e.g., the + /// variable 'x' in: + /// \code + /// struct S { + /// static int x; + /// }; + /// \endcode + bool isStaticDataMember() const { + return getDeclContext()->isRecord(); + } + + /// isFileVarDecl - Returns true for file scoped variable declaration. + bool isFileVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *Ctx = getDeclContext()) { + Ctx = Ctx->getLookupContext(); + if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) ) + return true; + } + return false; + } + + /// \brief Determine whether this is a tentative definition of a + /// variable in C. + bool isTentativeDefinition(ASTContext &Context) const; + + /// \brief Determines whether this variable is a variable with + /// external, C linkage. + bool isExternC(ASTContext &Context) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= VarFirst && D->getKind() <= VarLast; + } + static bool classof(const VarDecl *D) { return true; } +}; + +class ImplicitParamDecl : public VarDecl { +protected: + ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType Tw) + : VarDecl(DK, DC, L, Id, Tw, VarDecl::None) {} +public: + static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T); + // Implement isa/cast/dyncast/etc. + static bool classof(const ImplicitParamDecl *D) { return true; } + static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; } +}; + +/// ParmVarDecl - Represent a parameter to a function. +class ParmVarDecl : public VarDecl { + // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum + /// FIXME: Also can be paced into the bitfields in Decl. + /// in, inout, etc. + unsigned objcDeclQualifier : 6; + + /// Default argument, if any. [C++ Only] + Expr *DefaultArg; +protected: + ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + Expr *DefArg) + : VarDecl(DK, DC, L, Id, T, S), + objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {} + +public: + static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L,IdentifierInfo *Id, + QualType T, StorageClass S, Expr *DefArg); + + ObjCDeclQualifier getObjCDeclQualifier() const { + return ObjCDeclQualifier(objcDeclQualifier); + } + void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { + objcDeclQualifier = QTVal; + } + + const Expr *getDefaultArg() const { return DefaultArg; } + Expr *getDefaultArg() { return DefaultArg; } + void setDefaultArg(Expr *defarg) { DefaultArg = defarg; } + + /// hasUnparsedDefaultArg - Determines whether this parameter has a + /// default argument that has not yet been parsed. This will occur + /// during the processing of a C++ class whose member functions have + /// default arguments, e.g., + /// @code + /// class X { + /// public: + /// void f(int x = 17); // x has an unparsed default argument now + /// }; // x has a regular default argument now + /// @endcode + bool hasUnparsedDefaultArg() const { + return DefaultArg == reinterpret_cast<Expr *>(-1); + } + + /// setUnparsedDefaultArg - Specify that this parameter has an + /// unparsed default argument. The argument will be replaced with a + /// real default argument via setDefaultArg when the class + /// definition enclosing the function declaration that owns this + /// default argument is completed. + void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); } + + QualType getOriginalType() const; + + /// setOwningFunction - Sets the function declaration that owns this + /// ParmVarDecl. Since ParmVarDecls are often created before the + /// FunctionDecls that own them, this routine is required to update + /// the DeclContext appropriately. + void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return (D->getKind() == ParmVar || + D->getKind() == OriginalParmVar); + } + static bool classof(const ParmVarDecl *D) { return true; } +}; + +/// OriginalParmVarDecl - Represent a parameter to a function, when +/// the type of the parameter has been promoted. This node represents the +/// parameter to the function with its original type. +/// +class OriginalParmVarDecl : public ParmVarDecl { + friend class ParmVarDecl; +protected: + QualType OriginalType; +private: + OriginalParmVarDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + QualType OT, StorageClass S, + Expr *DefArg) + : ParmVarDecl(OriginalParmVar, DC, L, Id, T, S, DefArg), OriginalType(OT) {} +public: + static OriginalParmVarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L,IdentifierInfo *Id, + QualType T, QualType OT, + StorageClass S, Expr *DefArg); + + void setOriginalType(QualType T) { OriginalType = T; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == OriginalParmVar; } + static bool classof(const OriginalParmVarDecl *D) { return true; } +}; + +/// FunctionDecl - An instance of this class is created to represent a +/// function declaration or definition. +/// +/// Since a given function can be declared several times in a program, +/// there may be several FunctionDecls that correspond to that +/// function. Only one of those FunctionDecls will be found when +/// traversing the list of declarations in the context of the +/// FunctionDecl (e.g., the translation unit); this FunctionDecl +/// contains all of the information known about the function. Other, +/// previous declarations of the function are available via the +/// getPreviousDeclaration() chain. +class FunctionDecl : public ValueDecl, public DeclContext { +public: + enum StorageClass { + None, Extern, Static, PrivateExtern + }; +private: + /// ParamInfo - new[]'d array of pointers to VarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. TODO: we could allocate this space immediately after the + /// FunctionDecl object to save an allocation like FunctionType does. + ParmVarDecl **ParamInfo; + + LazyDeclStmtPtr Body; + + /// PreviousDeclaration - A link to the previous declaration of this + /// same function, NULL if this is the first declaration. For + /// example, in the following code, the PreviousDeclaration can be + /// traversed several times to see all three declarations of the + /// function "f", the last of which is also a definition. + /// + /// int f(int x, int y = 1); + /// int f(int x = 0, int y); + /// int f(int x, int y) { return x + y; } + FunctionDecl *PreviousDeclaration; + + // FIXME: This can be packed into the bitfields in Decl. + // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum + unsigned SClass : 2; + bool IsInline : 1; + bool C99InlineDefinition : 1; + bool IsVirtualAsWritten : 1; + bool IsPure : 1; + bool HasInheritedPrototype : 1; + bool HasWrittenPrototype : 1; + bool IsDeleted : 1; + + // Move to DeclGroup when it is implemented. + SourceLocation TypeSpecStartLoc; + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For function + /// declarations that describe a function template, this will be a + /// pointer to a FunctionTemplateDecl. For member functions + /// of class template specializations, this will be the + /// FunctionDecl from which the member function was instantiated. + llvm::PointerUnion<FunctionTemplateDecl*, FunctionDecl*> + TemplateOrInstantiation; + +protected: + FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + StorageClass S, bool isInline, + SourceLocation TSSL = SourceLocation()) + : ValueDecl(DK, DC, L, N, T), + DeclContext(DK), + ParamInfo(0), Body(), PreviousDeclaration(0), + SClass(S), IsInline(isInline), C99InlineDefinition(false), + IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), + HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL), + TemplateOrInstantiation() {} + + virtual ~FunctionDecl() {} + virtual void Destroy(ASTContext& C); + +public: + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + StorageClass S = None, bool isInline = false, + bool hasWrittenPrototype = true, + SourceLocation TSStartLoc = SourceLocation()); + + SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; } + void setTypeSpecStartLoc(SourceLocation TS) { TypeSpecStartLoc = TS; } + + /// getBody - Retrieve the body (definition) of the function. The + /// function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will + /// set that function declaration to the actual declaration + /// containing the body (if there is one). + Stmt *getBody(ASTContext &Context, const FunctionDecl *&Definition) const; + + virtual Stmt *getBody(ASTContext &Context) const { + const FunctionDecl* Definition; + return getBody(Context, Definition); + } + + /// \brief If the function has a body that is immediately available, + /// return it. + Stmt *getBodyIfAvailable() const; + + /// isThisDeclarationADefinition - Returns whether this specific + /// declaration of the function is also a definition. This does not + /// determine whether the function has been defined (e.g., in a + /// previous definition); for that information, use getBody. + /// FIXME: Should return true if function is deleted or defaulted. However, + /// CodeGenModule.cpp uses it, and I don't know if this would break it. + bool isThisDeclarationADefinition() const { return Body; } + + void setBody(Stmt *B) { Body = B; } + void setLazyBody(uint64_t Offset) { Body = Offset; } + + /// Whether this function is marked as virtual explicitly. + bool isVirtualAsWritten() const { return IsVirtualAsWritten; } + void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } + + /// 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; } + + /// \brief Whether this function has a prototype, either because one + /// was explicitly written or because it was "inherited" by merging + /// a declaration without a prototype with a declaration that has a + /// prototype. + bool hasPrototype() const { + return HasWrittenPrototype || HasInheritedPrototype; + } + + bool hasWrittenPrototype() const { return HasWrittenPrototype; } + void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; } + + /// \brief Whether this function inherited its prototype from a + /// previous declaration. + bool hasInheritedPrototype() const { return HasInheritedPrototype; } + void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; } + + /// \brief Whether this function has been deleted. + /// + /// A function that is "deleted" (via the C++0x "= delete" syntax) + /// acts like a normal function, except that it cannot actually be + /// called or have its address taken. Deleted functions are + /// typically used in C++ overload resolution to attract arguments + /// whose type or lvalue/rvalue-ness would permit the use of a + /// different overload that would behave incorrectly. For example, + /// one might use deleted functions to ban implicit conversion from + /// a floating-point number to an Integer type: + /// + /// @code + /// struct Integer { + /// Integer(long); // construct from a long + /// Integer(double) = delete; // no construction from float or double + /// Integer(long double) = delete; // no construction from long double + /// }; + /// @endcode + bool isDeleted() const { return IsDeleted; } + void setDeleted(bool D = true) { IsDeleted = D; } + + /// \brief Determines whether this is a function "main", which is + /// the entry point into an executable program. + bool isMain() const; + + /// \brief Determines whether this function is a function with + /// external, C linkage. + bool isExternC(ASTContext &Context) const; + + /// \brief Determines whether this is a global function. + bool isGlobal() const; + + /// getPreviousDeclaration - Return the previous declaration of this + /// function. + const FunctionDecl *getPreviousDeclaration() const { + return PreviousDeclaration; + } + + void setPreviousDeclaration(FunctionDecl * PrevDecl) { + PreviousDeclaration = PrevDecl; + } + + unsigned getBuiltinID(ASTContext &Context) const; + + unsigned getNumParmVarDeclsFromType() const; + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + + param_iterator param_begin() { return ParamInfo; } + param_iterator param_end() { return ParamInfo+param_size(); } + + param_const_iterator param_begin() const { return ParamInfo; } + param_const_iterator param_end() const { return ParamInfo+param_size(); } + + /// getNumParams - Return the number of parameters this function must have + /// based on its functiontype. This is the length of the PararmInfo array + /// after it has been created. + unsigned getNumParams() const; + + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams); + + /// getMinRequiredArguments - Returns the minimum number of arguments + /// needed to call this function. This may be fewer than the number of + /// function parameters, if some of the parameters have default + /// arguments (in C++). + unsigned getMinRequiredArguments() const; + + QualType getResultType() const { + return getType()->getAsFunctionType()->getResultType(); + } + StorageClass getStorageClass() const { return StorageClass(SClass); } + void setStorageClass(StorageClass SC) { SClass = SC; } + + bool isInline() const { return IsInline; } + void setInline(bool I) { IsInline = I; } + + /// \brief Whether this function is an "inline definition" as + /// defined by C99. + bool isC99InlineDefinition() const { return C99InlineDefinition; } + void setC99InlineDefinition(bool I) { C99InlineDefinition = I; } + + /// \brief Determines whether this function has a gnu_inline + /// attribute that affects its semantics. + /// + /// The gnu_inline attribute only introduces GNU inline semantics + /// when all of the inline declarations of the function are marked + /// gnu_inline. + bool hasActiveGNUInlineAttribute() const; + + /// \brief Determines whether this function is a GNU "extern + /// inline", which is roughly the opposite of a C99 "extern inline" + /// function. + bool isExternGNUInline() const; + + /// isOverloadedOperator - Whether this function declaration + /// represents an C++ overloaded operator, e.g., "operator+". + bool isOverloadedOperator() const { + return getOverloadedOperator() != OO_None; + }; + + OverloadedOperatorKind getOverloadedOperator() const; + + /// \brief If this function is an instantiation of a member function + /// of a class template specialization, retrieves the function from + /// which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// functions of class templates and for instantiations of function + /// templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// void f(T); + /// }; + /// \endcode + /// + /// The declaration for X<int>::f is a (non-templated) FunctionDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromFunction() will return + /// the FunctionDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberFunction(). + FunctionDecl *getInstantiatedFromMemberFunction() const { + return TemplateOrInstantiation.dyn_cast<FunctionDecl*>(); + } + + /// \brief Specify that this record is an instantiation of the + /// member function RD. + void setInstantiationOfMemberFunction(FunctionDecl *RD) { + TemplateOrInstantiation = RD; + } + + /// \brief Retrieves the function template that is described by this + /// function declaration. + /// + /// Every function template is represented as a FunctionTemplateDecl + /// and a FunctionDecl (or something derived from FunctionDecl). The + /// former contains template properties (such as the template + /// parameter lists) while the latter contains the actual + /// description of the template's + /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the + /// FunctionDecl that describes the function template, + /// getDescribedFunctionTemplate() retrieves the + /// FunctionTemplateDecl from a FunctionDecl. + FunctionTemplateDecl *getDescribedFunctionTemplate() const { + return TemplateOrInstantiation.dyn_cast<FunctionTemplateDecl*>(); + } + + void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + TemplateOrInstantiation = Template; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; + } + static bool classof(const FunctionDecl *D) { return true; } + static DeclContext *castToDeclContext(const FunctionDecl *D) { + return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D)); + } + static FunctionDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC)); + } +}; + + +/// FieldDecl - An instance of this class is created by Sema::ActOnField to +/// represent a member of a struct/union/class. +class FieldDecl : public ValueDecl { + // FIXME: This can be packed into the bitfields in Decl. + bool Mutable : 1; + Expr *BitWidth; +protected: + FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, bool Mutable) + : ValueDecl(DK, DC, L, Id, T), Mutable(Mutable), BitWidth(BW) + { } + +public: + static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, + bool Mutable); + + /// isMutable - Determines whether this field is mutable (C++ only). + bool isMutable() const { return Mutable; } + + /// \brief Set whether this field is mutable (C++ only). + void setMutable(bool M) { Mutable = M; } + + /// isBitfield - Determines whether this field is a bitfield. + bool isBitField() const { return BitWidth != NULL; } + + /// @brief Determines whether this is an unnamed bitfield. + bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); } + + /// isAnonymousStructOrUnion - Determines whether this field is a + /// representative for an anonymous struct or union. Such fields are + /// unnamed and are implicitly generated by the implementation to + /// store the data for the anonymous union or struct. + bool isAnonymousStructOrUnion() const; + + Expr *getBitWidth() const { return BitWidth; } + void setBitWidth(Expr *BW) { BitWidth = BW; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= FieldFirst && D->getKind() <= FieldLast; + } + static bool classof(const FieldDecl *D) { return true; } +}; + +/// EnumConstantDecl - An instance of this object exists for each enum constant +/// that is defined. For example, in "enum X {a,b}", each of a/b are +/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a +/// TagType for the X EnumDecl. +class EnumConstantDecl : public ValueDecl { + Stmt *Init; // an integer constant expression + llvm::APSInt Val; // The value. +protected: + EnumConstantDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *E, + const llvm::APSInt &V) + : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {} + + virtual ~EnumConstantDecl() {} +public: + + static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *E, + const llvm::APSInt &V); + + virtual void Destroy(ASTContext& C); + + const Expr *getInitExpr() const { return (const Expr*) Init; } + Expr *getInitExpr() { return (Expr*) Init; } + const llvm::APSInt &getInitVal() const { return Val; } + + void setInitExpr(Expr *E) { Init = (Stmt*) E; } + void setInitVal(const llvm::APSInt &V) { Val = V; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == EnumConstant; } + static bool classof(const EnumConstantDecl *D) { return true; } + + friend class StmtIteratorBase; +}; + + +/// TypeDecl - Represents a declaration of a type. +/// +class TypeDecl : public NamedDecl { + /// TypeForDecl - This indicates the Type object that represents + /// this TypeDecl. It is a cache maintained by + /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and + /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. + mutable Type *TypeForDecl; + friend class ASTContext; + friend class DeclContext; + friend class TagDecl; + friend class TemplateTypeParmDecl; + friend class ClassTemplateSpecializationDecl; + friend class TagType; + +protected: + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : NamedDecl(DK, DC, L, Id), TypeForDecl(0) {} + +public: + // Low-level accessor + Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(Type *TD) { TypeForDecl = TD; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= TypeFirst && D->getKind() <= TypeLast; + } + static bool classof(const TypeDecl *D) { return true; } +}; + + +class TypedefDecl : public TypeDecl { + /// UnderlyingType - This is the type the typedef is set to. + QualType UnderlyingType; + TypedefDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T) + : TypeDecl(Typedef, DC, L, Id), UnderlyingType(T) {} + + virtual ~TypedefDecl() {} +public: + + static TypedefDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L,IdentifierInfo *Id, + QualType T); + + QualType getUnderlyingType() const { return UnderlyingType; } + void setUnderlyingType(QualType newType) { UnderlyingType = newType; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == Typedef; } + static bool classof(const TypedefDecl *D) { return true; } +}; + +class TypedefDecl; + +/// TagDecl - Represents the declaration of a struct/union/class/enum. +class TagDecl : public TypeDecl, public DeclContext { +public: + enum TagKind { + TK_struct, + TK_union, + TK_class, + TK_enum + }; + +private: + // FIXME: This can be packed into the bitfields in Decl. + /// TagDeclKind - The TagKind enum. + unsigned TagDeclKind : 2; + + /// IsDefinition - True if this is a definition ("struct foo {};"), false if + /// it is a declaration ("struct foo;"). + bool IsDefinition : 1; + + /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef, + /// this points to the TypedefDecl. Used for mangling. + TypedefDecl *TypedefForAnonDecl; + +protected: + TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0) { + assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum"); + TagDeclKind = TK; + IsDefinition = false; + } +public: + + /// isDefinition - Return true if this decl has its body specified. + bool isDefinition() const { + return IsDefinition; + } + + /// \brief Whether this declaration declares a type that is + /// dependent, i.e., a type that somehow depends on template + /// parameters. + bool isDependentType() const { return isDependentContext(); } + + /// @brief Starts the definition of this tag declaration. + /// + /// This method should be invoked at the beginning of the definition + /// of this tag declaration. It will set the tag type into a state + /// where it is in the process of being defined. + 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 + /// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a + /// specific TagDecl is defining declaration, not whether or not the + /// struct/union/class/enum type is defined. This method returns NULL if + /// there is no TagDecl that defines the struct/union/class/enum. + TagDecl* getDefinition(ASTContext& C) const; + + const char *getKindName() const { + switch (getTagKind()) { + default: assert(0 && "Unknown TagKind!"); + case TK_struct: return "struct"; + case TK_union: return "union"; + case TK_class: return "class"; + case TK_enum: return "enum"; + } + } + + TagKind getTagKind() const { + return TagKind(TagDeclKind); + } + + void setTagKind(TagKind TK) { TagDeclKind = TK; } + + bool isStruct() const { return getTagKind() == TK_struct; } + bool isClass() const { return getTagKind() == TK_class; } + bool isUnion() const { return getTagKind() == TK_union; } + bool isEnum() const { return getTagKind() == TK_enum; } + + TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; } + void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= TagFirst && D->getKind() <= TagLast; + } + static bool classof(const TagDecl *D) { return true; } + + static DeclContext *castToDeclContext(const TagDecl *D) { + return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); + } + static TagDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); + } + + void setDefinition(bool V) { IsDefinition = V; } +}; + +/// EnumDecl - Represents an enum. As an extension, we allow forward-declared +/// enums. +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; + + /// \brief If the enumeration was instantiated from an enumeration + /// within a class or function template, this pointer refers to the + /// enumeration declared within the template. + EnumDecl *InstantiatedFrom; + + EnumDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : TagDecl(Enum, TK_enum, DC, L, Id), InstantiatedFrom(0) { + IntegerType = QualType(); + } +public: + static EnumDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + EnumDecl *PrevDecl); + + virtual void Destroy(ASTContext& C); + + /// completeDefinition - When created, the EnumDecl corresponds to a + /// forward-declared enum. This method is used to mark the + /// declaration as being defined; it's enumerators have already been + /// added (via DeclContext::addDecl). NewType is the new underlying + /// type of the enumeration type. + void completeDefinition(ASTContext &C, QualType NewType); + + // enumerator_iterator - Iterates through the enumerators of this + // enumeration. + typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; + + enumerator_iterator enumerator_begin(ASTContext &Context) const { + return enumerator_iterator(this->decls_begin(Context)); + } + + enumerator_iterator enumerator_end(ASTContext &Context) const { + return enumerator_iterator(this->decls_end(Context)); + } + + /// 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; } + + /// \brief Set the underlying integer type. + void setIntegerType(QualType T) { IntegerType = T; } + + /// \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. + EnumDecl *getInstantiatedFromMemberEnum() const { + return InstantiatedFrom; + } + + void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; } + + static bool classof(const Decl *D) { return D->getKind() == Enum; } + static bool classof(const EnumDecl *D) { return true; } +}; + + +/// RecordDecl - Represents a struct/union/class. For example: +/// struct X; // Forward declaration, no "body". +/// union Y { int A, B; }; // Has body with members A and B (FieldDecls). +/// This decl will be marked invalid if *any* members are invalid. +/// +class RecordDecl : public TagDecl { + // FIXME: This can be packed into the bitfields in Decl. + /// HasFlexibleArrayMember - This is true if this struct ends with a flexible + /// array member (e.g. int X[]) or if this union contains a struct that does. + /// If so, this cannot be contained in arrays or other structs as a member. + bool HasFlexibleArrayMember : 1; + + /// AnonymousStructOrUnion - Whether this is the type of an + /// anonymous struct or union. + bool AnonymousStructOrUnion : 1; + +protected: + RecordDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + virtual ~RecordDecl(); + +public: + static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + RecordDecl* PrevDecl = 0); + + virtual void Destroy(ASTContext& C); + + bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } + void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } + + /// isAnonymousStructOrUnion - Whether this is an anonymous struct + /// or union. To be an anonymous struct or union, it must have been + /// declared without a name and there must be no objects of this + /// type declared, e.g., + /// @code + /// union { int i; float f; }; + /// @endcode + /// is an anonymous union but neither of the following are: + /// @code + /// union X { int i; float f; }; + /// union { int i; float f; } obj; + /// @endcode + bool isAnonymousStructOrUnion() const { return AnonymousStructOrUnion; } + void setAnonymousStructOrUnion(bool Anon) { + AnonymousStructOrUnion = Anon; + } + + /// \brief Determines whether this declaration represents the + /// injected class name. + /// + /// The injected class name in C++ is the name of the class that + /// appears inside the class itself. For example: + /// + /// \code + /// struct C { + /// // C is implicitly declared here as a synonym for the class name. + /// }; + /// + /// C::C c; // same as "C c;" + /// \endcode + bool isInjectedClassName() const; + + /// getDefinition - Returns the RecordDecl that actually defines this + /// struct/union/class. When determining whether or not a struct/union/class + /// is completely defined, one should use this method as opposed to + /// 'isDefinition'. 'isDefinition' indicates whether or not a specific + /// RecordDecl is defining declaration, not whether or not the record + /// type is defined. This method returns NULL if there is no RecordDecl + /// that defines the struct/union/tag. + RecordDecl* getDefinition(ASTContext& C) const { + return cast_or_null<RecordDecl>(TagDecl::getDefinition(C)); + } + + // Iterator access to field members. The field iterator only visits + // the non-static data members of this class, ignoring any static + // data members, functions, constructors, destructors, etc. + typedef specific_decl_iterator<FieldDecl> field_iterator; + + field_iterator field_begin(ASTContext &Context) const { + return field_iterator(decls_begin(Context)); + } + field_iterator field_end(ASTContext &Context) const { + return field_iterator(decls_end(Context)); + } + + // field_empty - Whether there are any fields (non-static data + // members) in this record. + bool field_empty(ASTContext &Context) const { + return field_begin(Context) == field_end(Context); + } + + /// completeDefinition - Notes that the definition of this type is + /// now complete. + void completeDefinition(ASTContext& C); + + static bool classof(const Decl *D) { + return D->getKind() >= RecordFirst && D->getKind() <= RecordLast; + } + static bool classof(const RecordDecl *D) { return true; } +}; + +class FileScopeAsmDecl : public Decl { + StringLiteral *AsmString; + FileScopeAsmDecl(DeclContext *DC, SourceLocation L, StringLiteral *asmstring) + : Decl(FileScopeAsm, DC, L), AsmString(asmstring) {} +public: + static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, StringLiteral *Str); + + const StringLiteral *getAsmString() const { return AsmString; } + StringLiteral *getAsmString() { return AsmString; } + void setAsmString(StringLiteral *Asm) { AsmString = Asm; } + + static bool classof(const Decl *D) { + return D->getKind() == FileScopeAsm; + } + static bool classof(const FileScopeAsmDecl *D) { return true; } +}; + +/// BlockDecl - This represents a block literal declaration, which is like an +/// unnamed FunctionDecl. For example: +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +/// +class BlockDecl : public Decl, public DeclContext { + // FIXME: This can be packed into the bitfields in Decl. + bool isVariadic : 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. + ParmVarDecl **ParamInfo; + unsigned NumParams; + + Stmt *Body; + +protected: + BlockDecl(DeclContext *DC, SourceLocation CaretLoc) + : Decl(Block, DC, CaretLoc), DeclContext(Block), + isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {} + + virtual ~BlockDecl(); + virtual void Destroy(ASTContext& C); + +public: + static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); + + SourceLocation getCaretLocation() const { return getLocation(); } + + bool IsVariadic() const { return isVariadic; } + void setIsVariadic(bool value) { isVariadic = value; } + + CompoundStmt *getBody() const { return (CompoundStmt*) Body; } + Stmt *getBody(ASTContext &C) const { return (Stmt*) Body; } + void setBody(CompoundStmt *B) { Body = (Stmt*) B; } + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + + bool param_empty() const { return NumParams == 0; } + param_iterator param_begin() { return ParamInfo; } + param_iterator param_end() { return ParamInfo+param_size(); } + + param_const_iterator param_begin() const { return ParamInfo; } + param_const_iterator param_end() const { return ParamInfo+param_size(); } + + unsigned getNumParams() const; + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == Block; } + static bool classof(const BlockDecl *D) { return true; } + static DeclContext *castToDeclContext(const BlockDecl *D) { + return static_cast<DeclContext *>(const_cast<BlockDecl*>(D)); + } + static BlockDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<BlockDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// Insertion operator for diagnostics. This allows sending NamedDecl's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + NamedDecl* ND) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), Diagnostic::ak_nameddecl); + return DB; +} + +} // end namespace clang + +#endif diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h new file mode 100644 index 000000000000..c061b857063a --- /dev/null +++ b/include/clang/AST/DeclBase.h @@ -0,0 +1,900 @@ +//===-- DeclBase.h - Base Classes for representing declarations -*- 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 Decl and DeclContext interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLBASE_H +#define LLVM_CLANG_AST_DECLBASE_H + +#include "clang/AST/Attr.h" +#include "clang/AST/Type.h" +// FIXME: Layering violation +#include "clang/Parse/AccessSpecifier.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { +class DeclContext; +class TranslationUnitDecl; +class NamespaceDecl; +class UsingDirectiveDecl; +class NamedDecl; +class FunctionDecl; +class CXXRecordDecl; +class EnumDecl; +class ObjCMethodDecl; +class ObjCContainerDecl; +class ObjCInterfaceDecl; +class ObjCCategoryDecl; +class ObjCProtocolDecl; +class ObjCImplementationDecl; +class ObjCCategoryImplDecl; +class LinkageSpecDecl; +class BlockDecl; +class DeclarationName; +class CompoundStmt; +} + +namespace llvm { +// DeclContext* is only 4-byte aligned on 32-bit systems. +template<> + class PointerLikeTypeTraits<clang::DeclContext*> { + typedef clang::DeclContext* PT; +public: + static inline void *getAsVoidPointer(PT P) { return P; } + static inline PT getFromVoidPointer(void *P) { + return static_cast<PT>(P); + } + enum { NumLowBitsAvailable = 2 }; +}; +} + +namespace clang { + +/// Decl - This represents one declaration (or definition), e.g. a variable, +/// typedef, function, struct, etc. +/// +class Decl { +public: + /// \brief Lists the kind of concrete classes of Decl. + enum Kind { +#define DECL(Derived, Base) Derived, +#define DECL_RANGE(CommonBase, Start, End) \ + CommonBase##First = Start, CommonBase##Last = End, +#define LAST_DECL_RANGE(CommonBase, Start, End) \ + CommonBase##First = Start, CommonBase##Last = End +#include "clang/AST/DeclNodes.def" + }; + + /// IdentifierNamespace - According to C99 6.2.3, there are four + /// namespaces, labels, tags, members and ordinary + /// identifiers. These are meant as bitmasks, so that searches in + /// C++ can look into the "tag" namespace during ordinary lookup. We + /// use additional namespaces for Objective-C entities. + enum IdentifierNamespace { + IDNS_Label = 0x1, + IDNS_Tag = 0x2, + IDNS_Member = 0x4, + IDNS_Ordinary = 0x8, + IDNS_ObjCProtocol = 0x10, + IDNS_ObjCImplementation = 0x20, + IDNS_ObjCCategoryImpl = 0x40 + }; + + /// ObjCDeclQualifier - Qualifier used on types in method declarations + /// for remote messaging. They are meant for the arguments though and + /// applied to the Decls (ObjCMethodDecl and ParmVarDecl). + enum ObjCDeclQualifier { + OBJC_TQ_None = 0x0, + OBJC_TQ_In = 0x1, + OBJC_TQ_Inout = 0x2, + OBJC_TQ_Out = 0x4, + OBJC_TQ_Bycopy = 0x8, + OBJC_TQ_Byref = 0x10, + OBJC_TQ_Oneway = 0x20 + }; + +private: + /// NextDeclInContext - The next declaration within the same lexical + /// DeclContext. These pointers form the linked list that is + /// traversed via DeclContext's decls_begin()/decls_end(). + Decl *NextDeclInContext; + + friend class DeclContext; + + struct MultipleDC { + DeclContext *SemanticDC; + DeclContext *LexicalDC; + }; + + + /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. + /// For declarations that don't contain C++ scope specifiers, it contains + /// the DeclContext where the Decl was declared. + /// For declarations with C++ scope specifiers, it contains a MultipleDC* + /// with the context where it semantically belongs (SemanticDC) and the + /// context where it was lexically declared (LexicalDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx; + + inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); } + inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); } + inline MultipleDC *getMultipleDC() const { + return DeclCtx.get<MultipleDC*>(); + } + inline DeclContext *getSemanticDC() const { + return DeclCtx.get<DeclContext*>(); + } + + /// Loc - The location that this decl. + SourceLocation Loc; + + /// DeclKind - This indicates which class this is. + Kind DeclKind : 8; + + /// InvalidDecl - This indicates a semantic error occurred. + unsigned int InvalidDecl : 1; + + /// HasAttrs - This indicates whether the decl has attributes or not. + unsigned int HasAttrs : 1; + + /// Implicit - Whether this declaration was implicitly generated by + /// the implementation rather than explicitly written by the user. + bool Implicit : 1; + + /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. + unsigned IdentifierNamespace : 8; + +#ifndef NDEBUG + void CheckAccessDeclContext() const; +#else + void CheckAccessDeclContext() const { } +#endif + +protected: + /// Access - Used by C++ decls for the access specifier. + // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum + unsigned Access : 2; + friend class CXXClassMemberWrapper; + + Decl(Kind DK, DeclContext *DC, SourceLocation L) + : NextDeclInContext(0), DeclCtx(DC), + Loc(L), DeclKind(DK), InvalidDecl(0), + HasAttrs(false), Implicit(false), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) { + if (Decl::CollectingStats()) addDeclKind(DK); + } + + virtual ~Decl(); + +public: + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + Kind getKind() const { return DeclKind; } + const char *getDeclKindName() const; + + Decl *getNextDeclInContext() { return NextDeclInContext; } + const Decl *getNextDeclInContext() const { return NextDeclInContext; } + + DeclContext *getDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->SemanticDC; + } + const DeclContext *getDeclContext() const { + return const_cast<Decl*>(this)->getDeclContext(); + } + + void setAccess(AccessSpecifier AS) { + Access = AS; + CheckAccessDeclContext(); + } + + AccessSpecifier getAccess() const { + CheckAccessDeclContext(); + return AccessSpecifier(Access); + } + + bool hasAttrs() const { return HasAttrs; } + void addAttr(Attr *attr); + const Attr *getAttrs() const { + if (!HasAttrs) return 0; // common case, no attributes. + return getAttrsImpl(); // Uncommon case, out of line hash lookup. + } + void swapAttrs(Decl *D); + void invalidateAttrs(); + + template<typename T> const T *getAttr() const { + for (const Attr *attr = getAttrs(); attr; attr = attr->getNext()) + if (const T *V = dyn_cast<T>(attr)) + return V; + return 0; + } + + template<typename T> bool hasAttr() const { + return getAttr<T>() != 0; + } + + /// setInvalidDecl - Indicates the Decl had a semantic error. This + /// allows for graceful error recovery. + void setInvalidDecl(bool Invalid = true) { InvalidDecl = Invalid; } + bool isInvalidDecl() const { return (bool) InvalidDecl; } + + /// isImplicit - Indicates whether the declaration was implicitly + /// generated by the implementation. If false, this declaration + /// was written explicitly in the source code. + bool isImplicit() const { return Implicit; } + void setImplicit(bool I = true) { Implicit = I; } + + unsigned getIdentifierNamespace() const { + return IdentifierNamespace; + } + bool isInIdentifierNamespace(unsigned NS) const { + return getIdentifierNamespace() & NS; + } + static unsigned getIdentifierNamespaceForKind(Kind DK); + + + /// getLexicalDeclContext - The declaration context where this Decl was + /// lexically declared (LexicalDC). May be different from + /// getDeclContext() (SemanticDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + DeclContext *getLexicalDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->LexicalDC; + } + const DeclContext *getLexicalDeclContext() const { + return const_cast<Decl*>(this)->getLexicalDeclContext(); + } + + /// setDeclContext - Set both the semantic and lexical DeclContext + /// to DC. + void setDeclContext(DeclContext *DC); + + void setLexicalDeclContext(DeclContext *DC); + + // isDefinedOutsideFunctionOrMethod - This predicate returns true if this + // scoped decl is defined outside the current function or method. This is + // roughly global variables and functions, but also handles enums (which could + // be defined inside or outside a function etc). + bool isDefinedOutsideFunctionOrMethod() const; + + /// getBody - If this Decl represents a declaration for a body of code, + /// such as a function or method definition, this method returns the + /// top-level Stmt* of that body. Otherwise this method returns null. + virtual Stmt* getBody(ASTContext &Context) const { return 0; } + + /// getCompoundBody - Returns getBody(), dyn_casted to a CompoundStmt. + CompoundStmt* getCompoundBody(ASTContext &Context) const; + + /// getBodyRBrace - Gets the right brace of the body, if a body exists. + /// This works whether the body is a CompoundStmt or a CXXTryStmt. + SourceLocation getBodyRBrace(ASTContext &Context) const; + + // global temp stats (until we have a per-module visitor) + static void addDeclKind(Kind k); + static bool CollectingStats(bool Enable = false); + static void PrintStats(); + + /// isTemplateParameter - Determines whether this declartion is a + /// template parameter. + bool isTemplateParameter() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *) { return true; } + static DeclContext *castToDeclContext(const Decl *); + static Decl *castFromDeclContext(const DeclContext *); + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + void print(llvm::raw_ostream &Out, ASTContext &Context, + unsigned Indentation = 0); + void print(llvm::raw_ostream &Out, ASTContext &Context, + const PrintingPolicy &Policy, unsigned Indentation = 0); + static void printGroup(Decl** Begin, unsigned NumDecls, + llvm::raw_ostream &Out, ASTContext &Context, + const PrintingPolicy &Policy, + unsigned Indentation = 0); + void dump(ASTContext &Context); + +private: + const Attr *getAttrsImpl() const; + +}; + +/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when +/// doing something to a specific decl. +class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { + Decl *TheDecl; + SourceLocation Loc; + SourceManager &SM; + const char *Message; +public: + PrettyStackTraceDecl(Decl *theDecl, SourceLocation L, + SourceManager &sm, const char *Msg) + : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} + + virtual void print(llvm::raw_ostream &OS) const; +}; + + +/// DeclContext - This is used only as base class of specific decl types that +/// can act as declaration contexts. These decls are (only the top classes +/// that directly derive from DeclContext are mentioned, not their subclasses): +/// +/// TranslationUnitDecl +/// NamespaceDecl +/// FunctionDecl +/// TagDecl +/// ObjCMethodDecl +/// ObjCContainerDecl +/// ObjCCategoryImplDecl +/// ObjCImplementationDecl +/// LinkageSpecDecl +/// BlockDecl +/// +class DeclContext { + /// DeclKind - This indicates which class this is. + Decl::Kind 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; + + /// \brief Whether this declaration context also has some external + /// storage that contains additional declarations that are visible + /// in this context. + mutable bool ExternalVisibleStorage : 1; + + /// \brief Pointer to the data structure used to lookup declarations + /// within this context, which is a DenseMap<DeclarationName, + /// StoredDeclsList>. + mutable void* LookupPtr; + + /// FirstDecl - The first declaration stored within this declaration + /// context. + mutable Decl *FirstDecl; + + /// LastDecl - The last declaration stored within this declaration + /// context. FIXME: We could probably cache this value somewhere + /// outside of the DeclContext, to reduce the size of DeclContext by + /// another pointer. + mutable Decl *LastDecl; + +protected: + DeclContext(Decl::Kind K) + : DeclKind(K), ExternalLexicalStorage(false), + ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0), + LastDecl(0) { } + + void DestroyDecls(ASTContext &C); + +public: + ~DeclContext(); + + Decl::Kind getDeclKind() const { + return DeclKind; + } + const char *getDeclKindName() const; + + /// getParent - Returns the containing DeclContext. + DeclContext *getParent() { + return cast<Decl>(this)->getDeclContext(); + } + const DeclContext *getParent() const { + return const_cast<DeclContext*>(this)->getParent(); + } + + /// getLexicalParent - Returns the containing lexical DeclContext. May be + /// different from getParent, e.g.: + /// + /// namespace A { + /// struct S; + /// } + /// struct A::S {}; // getParent() == namespace 'A' + /// // getLexicalParent() == translation unit + /// + DeclContext *getLexicalParent() { + return cast<Decl>(this)->getLexicalDeclContext(); + } + const DeclContext *getLexicalParent() const { + return const_cast<DeclContext*>(this)->getLexicalParent(); + } + + bool isFunctionOrMethod() const { + switch (DeclKind) { + case Decl::Block: + case Decl::ObjCMethod: + return true; + default: + return DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast; + } + } + + bool isFileContext() const { + return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; + } + + bool isTranslationUnit() const { + return DeclKind == Decl::TranslationUnit; + } + + bool isRecord() const { + return DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast; + } + + bool isNamespace() const { + return DeclKind == Decl::Namespace; + } + + /// \brief Determines whether this context is dependent on a + /// template parameter. + bool isDependentContext() const; + + /// isTransparentContext - Determines whether this context is a + /// "transparent" context, meaning that the members declared in this + /// context are semantically declared in the nearest enclosing + /// non-transparent (opaque) context but are lexically declared in + /// this context. For example, consider the enumerators of an + /// enumeration type: + /// @code + /// enum E { + /// Val1 + /// }; + /// @endcode + /// Here, E is a transparent context, so its enumerator (Val1) will + /// appear (semantically) that it is in the same context of E. + /// Examples of transparent contexts include: enumerations (except for + /// C++0x scoped enums), C++ linkage specifications, and C++0x + /// inline namespaces. + bool isTransparentContext() const; + + bool Encloses(DeclContext *DC) const { + for (; DC; DC = DC->getParent()) + if (DC == this) + return true; + return false; + } + + /// getPrimaryContext - There may be many different + /// declarations of the same entity (including forward declarations + /// of classes, multiple definitions of namespaces, etc.), each with + /// a different set of declarations. This routine returns the + /// "primary" DeclContext structure, which will contain the + /// information needed to perform name lookup into this context. + DeclContext *getPrimaryContext(); + + /// getLookupContext - Retrieve the innermost non-transparent + /// context of this context, which corresponds to the innermost + /// location from which name lookup can find the entities in this + /// context. + DeclContext *getLookupContext(); + const DeclContext *getLookupContext() const { + return const_cast<DeclContext *>(this)->getLookupContext(); + } + + /// \brief Retrieve the nearest enclosing namespace context. + DeclContext *getEnclosingNamespaceContext(); + const DeclContext *getEnclosingNamespaceContext() const { + return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext(); + } + + /// getNextContext - If this is a DeclContext that may have other + /// DeclContexts that are semantically connected but syntactically + /// different, such as C++ namespaces, this routine retrieves the + /// next DeclContext in the link. Iteration through the chain of + /// DeclContexts should begin at the primary DeclContext and + /// continue until this function returns NULL. For example, given: + /// @code + /// namespace N { + /// int x; + /// } + /// namespace N { + /// int y; + /// } + /// @endcode + /// The first occurrence of namespace N will be the primary + /// DeclContext. Its getNextContext will return the second + /// occurrence of namespace N. + DeclContext *getNextContext(); + + /// decl_iterator - Iterates through the declarations stored + /// within this context. + class decl_iterator { + /// Current - The current declaration. + Decl *Current; + + public: + typedef Decl* value_type; + typedef Decl* reference; + typedef Decl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + decl_iterator() : Current(0) { } + explicit decl_iterator(Decl *C) : Current(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + decl_iterator& operator++() { + Current = Current->getNextDeclInContext(); + return *this; + } + + decl_iterator operator++(int) { + decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(decl_iterator x, decl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(decl_iterator x, decl_iterator y) { + return x.Current != y.Current; + } + }; + + /// decls_begin/decls_end - Iterate over the declarations stored in + /// this context. + decl_iterator decls_begin(ASTContext &Context) const; + decl_iterator decls_end(ASTContext &Context) const; + bool decls_empty(ASTContext &Context) const; + + /// specific_decl_iterator - Iterates over a subrange of + /// declarations stored in a DeclContext, providing only those that + /// are of type SpecificDecl (or a class derived from it). This + /// iterator is used, for example, to provide iteration over just + /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). + template<typename SpecificDecl> + class specific_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && !isa<SpecificDecl>(*Current)) + ++Current; + } + + public: + typedef SpecificDecl* value_type; + typedef SpecificDecl* reference; + typedef SpecificDecl* pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + specific_decl_iterator() : Current() { } + + /// specific_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + reference operator*() const { return cast<SpecificDecl>(*Current); } + pointer operator->() const { return cast<SpecificDecl>(*Current); } + + specific_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + specific_decl_iterator operator++(int) { + specific_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool + operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool + operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// \brief Iterates over a filtered subrange of declarations stored + /// in a DeclContext. + /// + /// This iterator visits only those declarations that are of type + /// SpecificDecl (or a class derived from it) and that meet some + /// additional run-time criteria. This iterator is used, for + /// example, to provide access to the instance methods within an + /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and + /// Acceptable = ObjCMethodDecl::isInstanceMethod). + template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const> + class filtered_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && + (!isa<SpecificDecl>(*Current) || + (Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)()))) + ++Current; + } + + public: + typedef SpecificDecl* value_type; + typedef SpecificDecl* reference; + typedef SpecificDecl* pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + filtered_decl_iterator() : Current() { } + + /// specific_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + reference operator*() const { return cast<SpecificDecl>(*Current); } + pointer operator->() const { return cast<SpecificDecl>(*Current); } + + filtered_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + filtered_decl_iterator operator++(int) { + filtered_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool + operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool + operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// @brief Add the declaration D into this context. + /// + /// This routine should be invoked when the declaration D has first + /// been declared, to place D into the context where it was + /// (lexically) defined. Every declaration must be added to one + /// (and only one!) context, where it can be visited via + /// [decls_begin(), decls_end()). Once a declaration has been added + /// to its lexical context, the corresponding DeclContext owns the + /// declaration. + /// + /// If D is also a NamedDecl, it will be made visible within its + /// semantic context via makeDeclVisibleInContext. + void addDecl(ASTContext &Context, Decl *D); + + /// lookup_iterator - An iterator that provides access to the results + /// of looking up a name within this context. + typedef NamedDecl **lookup_iterator; + + /// lookup_const_iterator - An iterator that provides non-mutable + /// access to the results of lookup up a name within this context. + typedef NamedDecl * const * lookup_const_iterator; + + typedef std::pair<lookup_iterator, lookup_iterator> lookup_result; + typedef std::pair<lookup_const_iterator, lookup_const_iterator> + lookup_const_result; + + /// lookup - Find the declarations (if any) with the given Name in + /// this context. Returns a range of iterators that contains all of + /// the declarations with this name, with object, function, member, + /// and enumerator names preceding any tag name. Note that this + /// routine will not look into parent contexts. + lookup_result lookup(ASTContext &Context, DeclarationName Name); + lookup_const_result lookup(ASTContext &Context, DeclarationName Name) const; + + /// @brief Makes a declaration visible within this context. + /// + /// This routine makes the declaration D visible to name lookup + /// within this context and, if this is a transparent context, + /// within its parent contexts up to the first enclosing + /// non-transparent context. Making a declaration visible within a + /// context does not transfer ownership of a declaration, and a + /// declaration can be visible in many contexts that aren't its + /// lexical context. + /// + /// If D is a redeclaration of an existing declaration that is + /// visible from this context, as determined by + /// NamedDecl::declarationReplaces, the previous declaration will be + /// replaced with D. + void makeDeclVisibleInContext(ASTContext &Context, NamedDecl *D); + + /// udir_iterator - Iterates through the using-directives stored + /// within this context. + typedef UsingDirectiveDecl * const * udir_iterator; + + typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range; + + udir_iterator_range getUsingDirectives(ASTContext &Context) const; + + udir_iterator using_directives_begin(ASTContext &Context) const { + return getUsingDirectives(Context).first; + } + + udir_iterator using_directives_end(ASTContext &Context) const { + return getUsingDirectives(Context).second; + } + + // Low-level accessors + + /// \brief Retrieve the internal representation of the lookup structure. + void* getLookupPtr() const { return LookupPtr; } + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are lexically in this context. + bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations lexically in this context. + void setHasExternalLexicalStorage(bool ES = true) { + ExternalLexicalStorage = ES; + } + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are visible in this context. + bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations visible in this context. + void setHasExternalVisibleStorage(bool ES = true) { + ExternalVisibleStorage = ES; + } + + static bool classof(const Decl *D); + static bool classof(const DeclContext *D) { return true; } +#define DECL_CONTEXT(Name) \ + static bool classof(const Name##Decl *D) { return true; } +#include "clang/AST/DeclNodes.def" + +private: + void LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const; + void LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const; + + void buildLookup(ASTContext &Context, DeclContext *DCtx); + void makeDeclVisibleInContextImpl(ASTContext &Context, NamedDecl *D); +}; + +inline bool Decl::isTemplateParameter() const { + return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm; +} + +inline bool Decl::isDefinedOutsideFunctionOrMethod() const { + if (getDeclContext()) + return !getDeclContext()->getLookupContext()->isFunctionOrMethod(); + return true; +} + +} // end clang. + +namespace llvm { + +/// Implement a isa_impl_wrap specialization to check whether a DeclContext is +/// a specific Decl. +template<class ToTy> +struct isa_impl_wrap<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> { + static bool doit(const ::clang::DeclContext &Val) { + return ToTy::classof(::clang::Decl::castFromDeclContext(&Val)); + } +}; +template<class ToTy> +struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext> + : public isa_impl_wrap<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> {}; + +/// Implement cast_convert_val for Decl -> DeclContext conversions. +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { + static ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { + static ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { + static const ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { + static const ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +/// Implement cast_convert_val for DeclContext -> Decl conversions. +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> { + static ToTy &doit(const ::clang::DeclContext &Val) { + return *reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(&Val)); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> + : public cast_convert_val<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> {}; + +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext*, const ::clang::DeclContext*> { + static ToTy *doit(const ::clang::DeclContext *Val) { + return reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(Val)); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> + : public cast_convert_val<ToTy, + const ::clang::DeclContext*,const ::clang::DeclContext*> {}; + +} // end namespace llvm + +#endif diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h new file mode 100644 index 000000000000..4a74a2c2cbc4 --- /dev/null +++ b/include/clang/AST/DeclCXX.h @@ -0,0 +1,1073 @@ +//===-- DeclCXX.h - Classes for representing C++ declarations -*- 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 C++ Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLCXX_H +#define LLVM_CLANG_AST_DECLCXX_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class ClassTemplateDecl; +class CXXRecordDecl; +class CXXConstructorDecl; +class CXXDestructorDecl; +class CXXConversionDecl; +class CXXMethodDecl; +class ClassTemplateSpecializationDecl; + +/// OverloadedFunctionDecl - An instance of this class represents a +/// set of overloaded functions. All of the functions have the same +/// name and occur within the same scope. +/// +/// An OverloadedFunctionDecl has no ownership over the FunctionDecl +/// nodes it contains. Rather, the FunctionDecls are owned by the +/// enclosing scope (which also owns the OverloadedFunctionDecl +/// node). OverloadedFunctionDecl is used primarily to store a set of +/// overloaded functions for name lookup. +class OverloadedFunctionDecl : public NamedDecl { +protected: + OverloadedFunctionDecl(DeclContext *DC, DeclarationName N) + : NamedDecl(OverloadedFunction, DC, SourceLocation(), N) { } + + /// Functions - the set of overloaded functions contained in this + /// overload set. + llvm::SmallVector<FunctionDecl *, 4> Functions; + + // FIXME: This should go away when we stop using + // OverloadedFunctionDecl to store conversions in CXXRecordDecl. + friend class CXXRecordDecl; + +public: + typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator; + typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator + function_const_iterator; + + static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC, + DeclarationName N); + + /// addOverload - Add an overloaded function FD to this set of + /// overloaded functions. + void addOverload(FunctionDecl *FD) { + assert((FD->getDeclName() == getDeclName() || + isa<CXXConversionDecl>(FD) || isa<CXXConstructorDecl>(FD)) && + "Overloaded functions must have the same name"); + Functions.push_back(FD); + + // An overloaded function declaration always has the location of + // the most-recently-added function declaration. + if (FD->getLocation().isValid()) + this->setLocation(FD->getLocation()); + } + + function_iterator function_begin() { return Functions.begin(); } + function_iterator function_end() { return Functions.end(); } + function_const_iterator function_begin() const { return Functions.begin(); } + function_const_iterator function_end() const { return Functions.end(); } + + /// getNumFunctions - the number of overloaded functions stored in + /// this set. + unsigned getNumFunctions() const { return Functions.size(); } + + /// getFunction - retrieve the ith function in the overload set. + const FunctionDecl *getFunction(unsigned i) const { + assert(i < getNumFunctions() && "Illegal function #"); + return Functions[i]; + } + FunctionDecl *getFunction(unsigned i) { + assert(i < getNumFunctions() && "Illegal function #"); + return Functions[i]; + } + + // getDeclContext - Get the context of these overloaded functions. + DeclContext *getDeclContext() { + assert(getNumFunctions() > 0 && "Context of an empty overload set"); + return getFunction(0)->getDeclContext(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == OverloadedFunction; + } + static bool classof(const OverloadedFunctionDecl *D) { return true; } +}; + +/// CXXBaseSpecifier - A base class of a C++ class. +/// +/// Each CXXBaseSpecifier represents a single, direct base class (or +/// struct) of a C++ class (or struct). It specifies the type of that +/// base class, whether it is a virtual or non-virtual base, and what +/// level of access (public, protected, private) is used for the +/// derivation. For example: +/// +/// @code +/// class A { }; +/// class B { }; +/// class C : public virtual A, protected B { }; +/// @endcode +/// +/// In this code, C will have two CXXBaseSpecifiers, one for "public +/// virtual A" and the other for "protected B". +class CXXBaseSpecifier { + /// Range - The source code range that covers the full base + /// specifier, including the "virtual" (if present) and access + /// specifier (if present). + SourceRange Range; + + /// Virtual - Whether this is a virtual base class or not. + bool Virtual : 1; + + /// BaseOfClass - Whether this is the base of a class (true) or of a + /// struct (false). This determines the mapping from the access + /// specifier as written in the source code to the access specifier + /// used for semantic analysis. + bool BaseOfClass : 1; + + /// Access - Access specifier as written in the source code (which + /// may be AS_none). The actual type of data stored here is an + /// AccessSpecifier, but we use "unsigned" here to work around a + /// VC++ bug. + unsigned Access : 2; + + /// BaseType - The type of the base class. This will be a class or + /// struct (or a typedef of such). + QualType BaseType; + +public: + CXXBaseSpecifier() { } + + CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, QualType T) + : Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseType(T) { } + + /// getSourceRange - Retrieves the source range that contains the + /// entire base specifier. + SourceRange getSourceRange() const { return Range; } + + /// isVirtual - Determines whether the base class is a virtual base + /// class (or not). + bool isVirtual() const { return Virtual; } + + /// 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 + /// retrieve the access specifier as written in the source code, use + /// getAccessSpecifierAsWritten(). + AccessSpecifier getAccessSpecifier() const { + if ((AccessSpecifier)Access == AS_none) + return BaseOfClass? AS_private : AS_public; + else + return (AccessSpecifier)Access; + } + + /// getAccessSpecifierAsWritten - Retrieves the access specifier as + /// written in the source code (which may mean that no access + /// specifier was explicitly written). Use getAccessSpecifier() to + /// retrieve the access specifier for use in semantic analysis. + AccessSpecifier getAccessSpecifierAsWritten() const { + return (AccessSpecifier)Access; + } + + /// getType - Retrieves the type of the base class. This type will + /// always be an unqualified class type. + QualType getType() const { return BaseType; } +}; + +/// CXXRecordDecl - Represents a C++ struct/union/class. +/// FIXME: This class will disappear once we've properly taught RecordDecl +/// to deal with C++-specific things. +class CXXRecordDecl : public RecordDecl { + /// UserDeclaredConstructor - True when this class has a + /// user-declared constructor. + bool UserDeclaredConstructor : 1; + + /// UserDeclaredCopyConstructor - True when this class has a + /// user-declared copy constructor. + bool UserDeclaredCopyConstructor : 1; + + /// UserDeclaredCopyAssignment - True when this class has a + /// user-declared copy assignment operator. + bool UserDeclaredCopyAssignment : 1; + + /// UserDeclaredDestructor - True when this class has a + /// user-declared destructor. + bool UserDeclaredDestructor : 1; + + /// Aggregate - True when this class is an aggregate. + bool Aggregate : 1; + + /// PlainOldData - True when this class is a POD-type. + bool PlainOldData : 1; + + /// Polymorphic - True when this class is polymorphic, i.e. has at least one + /// virtual member or derives from a polymorphic class. + bool Polymorphic : 1; + + /// Abstract - True when this class is abstract, i.e. has at least one + /// pure virtual function, (that can come from a base class). + bool Abstract : 1; + + /// HasTrivialConstructor - True when this class has a trivial constructor + bool HasTrivialConstructor : 1; + + /// HasTrivialDestructor - True when this class has a trivial destructor + bool HasTrivialDestructor : 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; + + /// Conversions - Overload set containing the conversion functions + /// of this C++ class (but not its inherited conversion + /// functions). Each of the entries in this overload set is a + /// CXXConversionDecl. + OverloadedFunctionDecl Conversions; + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For record + /// declarations that describe a class template, this will be a + /// pointer to a ClassTemplateDecl. For member + /// classes of class template specializations, this will be the + /// RecordDecl from which the member class was instantiated. + llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*> + TemplateOrInstantiation; + +protected: + CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + + ~CXXRecordDecl(); + +public: + /// base_class_iterator - Iterator that traverses the base classes + /// of a clas. + typedef CXXBaseSpecifier* base_class_iterator; + + /// base_class_const_iterator - Iterator that traverses the base + /// classes of a clas. + typedef const CXXBaseSpecifier* base_class_const_iterator; + + static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl* PrevDecl=0, + bool DelayTypeCreation = false); + + /// setBases - Sets the base classes of this struct or class. + void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); + + /// getNumBases - Retrieves the number of base classes of this + /// class. + unsigned getNumBases() const { return NumBases; } + + base_class_iterator bases_begin() { return Bases; } + base_class_const_iterator bases_begin() const { return Bases; } + base_class_iterator bases_end() { return Bases + NumBases; } + base_class_const_iterator bases_end() const { return Bases + NumBases; } + + /// hasConstCopyConstructor - Determines whether this class has a + /// copy constructor that accepts a const-qualified argument. + bool hasConstCopyConstructor(ASTContext &Context) const; + + /// hasConstCopyAssignment - Determines whether this class has a + /// copy assignment operator that accepts a const-qualified argument. + bool hasConstCopyAssignment(ASTContext &Context) 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. + bool hasUserDeclaredConstructor() const { return UserDeclaredConstructor; } + + /// hasUserDeclaredCopyConstructor - Whether this class has a + /// user-declared copy constructor. When false, a copy constructor + /// will be implicitly declared. + bool hasUserDeclaredCopyConstructor() const { + return UserDeclaredCopyConstructor; + } + + /// 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. + bool hasUserDeclaredCopyAssignment() const { + return UserDeclaredCopyAssignment; + } + + /// hasUserDeclaredDestructor - Whether this class has a + /// user-declared destructor. When false, a destructor will be + /// implicitly declared. + bool hasUserDeclaredDestructor() const { return 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) { + UserDeclaredDestructor = UCD; + } + + /// getConversions - Retrieve the overload set containing all of the + /// conversion functions in this class. + OverloadedFunctionDecl *getConversionFunctions() { + return &Conversions; + } + const OverloadedFunctionDecl *getConversionFunctions() const { + return &Conversions; + } + + /// addConversionFunction - Add a new conversion function to the + /// list of conversion functions. + void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl); + + /// 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 Aggregate; } + + /// setAggregate - Set whether this class is an aggregate (C++ + /// [dcl.init.aggr]). + void setAggregate(bool Agg) { Aggregate = Agg; } + + /// 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 PlainOldData; } + + /// setPOD - Set whether this class is a POD-type (C++ [class]p4). + void setPOD(bool POD) { PlainOldData = POD; } + + /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), + /// which means that the class contains or inherits a virtual function. + bool isPolymorphic() const { return Polymorphic; } + + /// setPolymorphic - Set whether this class is polymorphic (C++ + /// [class.virtual]). + void setPolymorphic(bool Poly) { 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 Abstract; } + + /// setAbstract - Set whether this class is abstract (C++ [class.abstract]) + void setAbstract(bool Abs) { Abstract = Abs; } + + // hasTrivialConstructor - Whether this class has a trivial constructor + // (C++ [class.ctor]p5) + bool hasTrivialConstructor() const { return HasTrivialConstructor; } + + // setHasTrivialConstructor - Set whether this class has a trivial constructor + // (C++ [class.ctor]p5) + void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; } + + // hasTrivialDestructor - Whether this class has a trivial destructor + // (C++ [class.dtor]p3) + bool hasTrivialDestructor() const { return HasTrivialDestructor; } + + // setHasTrivialDestructor - Set whether this class has a trivial destructor + // (C++ [class.dtor]p3) + void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; } + + /// \brief If this record is an instantiation of a member class, + /// retrieves the member class from which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// classes of class templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// struct A { }; + /// }; + /// \endcode + /// + /// The declaration for X<int>::A is a (non-templated) CXXRecordDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromMemberClass() will return + /// the CXXRecordDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberClass(). + CXXRecordDecl *getInstantiatedFromMemberClass() const { + return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>(); + } + + /// \brief Specify that this record is an instantiation of the + /// member class RD. + void setInstantiationOfMemberClass(CXXRecordDecl *RD) { + TemplateOrInstantiation = RD; + } + + /// \brief Retrieves the class template that is described by this + /// class declaration. + /// + /// Every class template is represented as a ClassTemplateDecl and a + /// CXXRecordDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the + /// CXXRecordDecl that from a ClassTemplateDecl, while + /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from + /// a CXXRecordDecl. + ClassTemplateDecl *getDescribedClassTemplate() const { + return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>(); + } + + void setDescribedClassTemplate(ClassTemplateDecl *Template) { + TemplateOrInstantiation = Template; + } + + /// getDestructor - Returns the destructor decl for this class. + const CXXDestructorDecl *getDestructor(ASTContext &Context); + + /// viewInheritance - Renders and displays an inheritance diagram + /// for this C++ class and all of its base classes (transitively) using + /// GraphViz. + void viewInheritance(ASTContext& Context) const; + + static bool classof(const Decl *D) { + return D->getKind() == CXXRecord || + D->getKind() == ClassTemplateSpecialization || + D->getKind() == ClassTemplatePartialSpecialization; + } + static bool classof(const CXXRecordDecl *D) { return true; } + static bool classof(const ClassTemplateSpecializationDecl *D) { + return true; + } +}; + +/// CXXMethodDecl - Represents a static or instance method of a +/// struct/union/class. +class CXXMethodDecl : public FunctionDecl { +protected: + CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, + DeclarationName N, QualType T, + bool isStatic, bool isInline) + : FunctionDecl(DK, RD, L, N, T, (isStatic ? Static : None), + isInline) {} + +public: + static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isStatic = false, + bool isInline = false); + + bool isStatic() const { return getStorageClass() == Static; } + bool isInstance() const { return !isStatic(); } + + bool isOutOfLineDefinition() const { + return getLexicalDeclContext() != getDeclContext(); + } + + bool isVirtual() const { + return isVirtualAsWritten() || + (begin_overridden_methods() != end_overridden_methods()); + } + + /// + void addOverriddenMethod(const CXXMethodDecl *MD); + + typedef const CXXMethodDecl ** method_iterator; + + method_iterator begin_overridden_methods() const; + method_iterator end_overridden_methods() const; + + /// getParent - Returns the parent of this method declaration, which + /// is the class in which this method is defined. + const CXXRecordDecl *getParent() const { + return cast<CXXRecordDecl>(FunctionDecl::getParent()); + } + + /// getParent - Returns the parent of this method declaration, which + /// is the class in which this method is defined. + CXXRecordDecl *getParent() { + return const_cast<CXXRecordDecl *>( + cast<CXXRecordDecl>(FunctionDecl::getParent())); + } + + /// getThisType - Returns the type of 'this' pointer. + /// Should only be called for instance methods. + QualType getThisType(ASTContext &C) const; + + unsigned getTypeQualifiers() const { + return getType()->getAsFunctionProtoType()->getTypeQuals(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion; + } + static bool classof(const CXXMethodDecl *D) { return true; } +}; + +/// CXXBaseOrMemberInitializer - 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 +/// initializers: +/// +/// @code +/// class A { }; +/// class B : public A { +/// float f; +/// public: +/// B(A& a) : A(a), f(3.14159) { } +/// }; +class CXXBaseOrMemberInitializer { + /// BaseOrMember - This points to the entity being initialized, + /// which is either a base class (a Type) or a non-static data + /// member. When the low bit is 1, it's a base + /// class; when the low bit is 0, it's a member. + uintptr_t BaseOrMember; + + /// Args - The arguments used to initialize the base or member. + Expr **Args; + unsigned NumArgs; + +public: + /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. + explicit + CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs); + + /// CXXBaseOrMemberInitializer - Creates a new member initializer. + explicit + CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs); + + /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer. + ~CXXBaseOrMemberInitializer(); + + /// arg_iterator - Iterates through the member initialization + /// arguments. + typedef Expr **arg_iterator; + + /// arg_const_iterator - Iterates through the member initialization + /// arguments. + typedef Expr * const * arg_const_iterator; + + /// isBaseInitializer - Returns true when this initializer is + /// initializing a base class. + bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; } + + /// isMemberInitializer - Returns true when this initializer is + /// initializing a non-static data member. + bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; } + + /// getBaseClass - If this is a base class initializer, returns the + /// type used to specify the initializer. The resulting type will be + /// a class type or a typedef of a class type. If this is not a base + /// class initializer, returns NULL. + Type *getBaseClass() { + if (isBaseInitializer()) + return reinterpret_cast<Type*>(BaseOrMember & ~0x01); + else + return 0; + } + + /// getBaseClass - If this is a base class initializer, returns the + /// type used to specify the initializer. The resulting type will be + /// a class type or a typedef of a class type. If this is not a base + /// class initializer, returns NULL. + const Type *getBaseClass() const { + if (isBaseInitializer()) + return reinterpret_cast<const Type*>(BaseOrMember & ~0x01); + else + return 0; + } + + /// getMember - If this is a member initializer, returns the + /// declaration of the non-static data member being + /// initialized. Otherwise, returns NULL. + FieldDecl *getMember() { + if (isMemberInitializer()) + return reinterpret_cast<FieldDecl *>(BaseOrMember); + else + return 0; + } + + /// begin() - Retrieve an iterator to the first initializer argument. + arg_iterator begin() { return Args; } + /// begin() - Retrieve an iterator to the first initializer argument. + arg_const_iterator begin() const { return Args; } + + /// end() - Retrieve an iterator past the last initializer argument. + arg_iterator end() { return Args + NumArgs; } + /// end() - Retrieve an iterator past the last initializer argument. + arg_const_iterator end() const { return Args + NumArgs; } + + /// getNumArgs - Determine the number of arguments used to + /// initialize the member or base. + unsigned getNumArgs() const { return NumArgs; } +}; + +/// CXXConstructorDecl - Represents a C++ constructor within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// explicit X(int); // represented by a CXXConstructorDecl. +/// }; +/// @endcode +class CXXConstructorDecl : public CXXMethodDecl { + /// Explicit - Whether this constructor is explicit. + bool Explicit : 1; + + /// ImplicitlyDefined - Whether this constructor was implicitly + /// defined by the compiler. When false, the constructor was defined + /// by the user. In C++03, this flag will have the same value as + /// Implicit. In C++0x, however, a constructor that is + /// explicitly defaulted (i.e., defined with " = default") will have + /// @c !Implicit && ImplicitlyDefined. + bool ImplicitlyDefined : 1; + + /// FIXME: Add support for base and member initializers. + + CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L, + DeclarationName N, QualType T, + bool isExplicit, bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline), + Explicit(isExplicit), ImplicitlyDefined(false) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isExplicit, + bool isInline, bool isImplicitlyDeclared); + + /// isExplicit - Whether this constructor was marked "explicit" or not. + bool isExplicit() const { return Explicit; } + + /// isImplicitlyDefined - Whether this constructor was implicitly + /// defined. If false, then this constructor was defined by the + /// user. This operation can only be invoked if the constructor has + /// already been defined. + bool isImplicitlyDefined(ASTContext &C) const { + assert(isThisDeclarationADefinition() && + "Can only get the implicit-definition flag once the constructor has been defined"); + return ImplicitlyDefined; + } + + /// setImplicitlyDefined - Set whether this constructor was + /// implicitly defined or not. + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && + "Can only set the implicit-definition flag once the constructor has been defined"); + ImplicitlyDefined = ID; + } + + /// isDefaultConstructor - Whether this constructor is a default + /// constructor (C++ [class.ctor]p5), which can be used to + /// default-initialize a class of this type. + bool isDefaultConstructor() const; + + /// isCopyConstructor - Whether this constructor is a copy + /// constructor (C++ [class.copy]p2, which can be used to copy the + /// class. @p TypeQuals will be set to the qualifiers on the + /// argument type. For example, @p TypeQuals would be set to @c + /// QualType::Const for the following copy constructor: + /// + /// @code + /// class X { + /// public: + /// X(const X&); + /// }; + /// @endcode + bool isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const; + + /// isCopyConstructor - Whether this constructor is a copy + /// constructor (C++ [class.copy]p2, which can be used to copy the + /// class. + bool isCopyConstructor(ASTContext &Context) const { + unsigned TypeQuals = 0; + return isCopyConstructor(Context, TypeQuals); + } + + /// isConvertingConstructor - Whether this constructor is a + /// converting constructor (C++ [class.conv.ctor]), which can be + /// used for user-defined conversions. + bool isConvertingConstructor() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == CXXConstructor; + } + static bool classof(const CXXConstructorDecl *D) { return true; } +}; + +/// CXXDestructorDecl - Represents a C++ destructor within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// ~X(); // represented by a CXXDestructorDecl. +/// }; +/// @endcode +class CXXDestructorDecl : public CXXMethodDecl { + /// ImplicitlyDefined - Whether this destructor was implicitly + /// defined by the compiler. When false, the destructor was defined + /// by the user. In C++03, this flag will have the same value as + /// Implicit. In C++0x, however, a destructor that is + /// explicitly defaulted (i.e., defined with " = default") will have + /// @c !Implicit && ImplicitlyDefined. + bool ImplicitlyDefined : 1; + + CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, + DeclarationName N, QualType T, + bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline), + ImplicitlyDefined(false) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isInline, + bool isImplicitlyDeclared); + + /// isImplicitlyDefined - Whether this destructor was implicitly + /// defined. If false, then this destructor was defined by the + /// user. This operation can only be invoked if the destructor has + /// already been defined. + bool isImplicitlyDefined() const { + assert(isThisDeclarationADefinition() && + "Can only get the implicit-definition flag once the destructor has been defined"); + return ImplicitlyDefined; + } + + /// setImplicitlyDefined - Set whether this destructor was + /// implicitly defined or not. + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && + "Can only set the implicit-definition flag once the destructor has been defined"); + ImplicitlyDefined = ID; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == CXXDestructor; + } + static bool classof(const CXXDestructorDecl *D) { return true; } +}; + +/// CXXConversionDecl - Represents a C++ conversion function within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// operator bool(); +/// }; +/// @endcode +class CXXConversionDecl : public CXXMethodDecl { + /// Explicit - Whether this conversion function is marked + /// "explicit", meaning that it can only be applied when the user + /// explicitly wrote a cast. This is a C++0x feature. + bool Explicit : 1; + + CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L, + DeclarationName N, QualType T, + bool isInline, bool isExplicit) + : CXXMethodDecl(CXXConversion, RD, L, N, T, false, isInline), + Explicit(isExplicit) { } + +public: + static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isInline, + bool isExplicit); + + /// isExplicit - Whether this is an explicit conversion operator + /// (C++0x only). Explicit conversion operators are only considered + /// when the user has explicitly written a cast. + bool isExplicit() const { return Explicit; } + + /// getConversionType - Returns the type that this conversion + /// function is converting to. + QualType getConversionType() const { + return getType()->getAsFunctionType()->getResultType(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == CXXConversion; + } + static bool classof(const CXXConversionDecl *D) { return true; } +}; + +/// LinkageSpecDecl - This represents a linkage specification. For example: +/// extern "C" void foo(); +/// +class LinkageSpecDecl : public Decl, public DeclContext { +public: + /// LanguageIDs - Used to represent the language in a linkage + /// specification. The values are part of the serialization abi for + /// ASTs and cannot be changed without altering that abi. To help + /// ensure a stable abi for this, we choose the DW_LANG_ encodings + /// from the dwarf standard. + enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002, + lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 }; +private: + /// Language - The language for this linkage specification. + LanguageIDs Language; + + /// HadBraces - Whether this linkage specification had curly braces or not. + bool HadBraces : 1; + + LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang, + bool Braces) + : Decl(LinkageSpec, DC, L), + DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { } + +public: + static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, LanguageIDs Lang, + bool Braces); + + LanguageIDs getLanguage() const { return Language; } + + /// hasBraces - Determines whether this linkage specification had + /// braces in its syntactic form. + bool hasBraces() const { return HadBraces; } + + static bool classof(const Decl *D) { + return D->getKind() == LinkageSpec; + } + static bool classof(const LinkageSpecDecl *D) { return true; } + static DeclContext *castToDeclContext(const LinkageSpecDecl *D) { + return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D)); + } + static LinkageSpecDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<LinkageSpecDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// UsingDirectiveDecl - Represents C++ using-directive. For example: +/// +/// using namespace std; +/// +// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide +// artificial name, for all using-directives in order to store +// them in DeclContext effectively. +class UsingDirectiveDecl : public NamedDecl { + + /// SourceLocation - Location of 'namespace' token. + SourceLocation NamespaceLoc; + + /// \brief The source range that covers the nested-name-specifier + /// preceding the namespace name. + SourceRange QualifierRange; + + /// \brief The nested-name-specifier that precedes the namespace + /// name, if any. + NestedNameSpecifier *Qualifier; + + /// IdentLoc - Location of nominated namespace-name identifier. + // FIXME: We don't store location of scope specifier. + SourceLocation IdentLoc; + + /// NominatedNamespace - Namespace nominated by using-directive. + NamespaceDecl *NominatedNamespace; + + /// Enclosing context containing both using-directive and nomintated + /// namespace. + DeclContext *CommonAncestor; + + /// getUsingDirectiveName - Returns special DeclarationName used by + /// using-directives. This is only used by DeclContext for storing + /// UsingDirectiveDecls in its lookup structure. + static DeclarationName getName() { + return DeclarationName::getUsingDirectiveName(); + } + + UsingDirectiveDecl(DeclContext *DC, SourceLocation L, + SourceLocation NamespcLoc, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamespaceDecl *Nominated, + DeclContext *CommonAncestor) + : NamedDecl(Decl::UsingDirective, DC, L, getName()), + NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange), + Qualifier(Qualifier), IdentLoc(IdentLoc), + NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0), + CommonAncestor(CommonAncestor) { + } + +public: + /// \brief Retrieve the source range of the nested-name-specifier + /// that qualifiers the namespace name. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// getNominatedNamespace - Returns namespace nominated by using-directive. + NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; } + + const NamespaceDecl *getNominatedNamespace() const { + return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace(); + } + + /// getCommonAncestor - returns common ancestor context of using-directive, + /// and nominated by it namespace. + DeclContext *getCommonAncestor() { return CommonAncestor; } + const DeclContext *getCommonAncestor() const { return CommonAncestor; } + + /// getNamespaceKeyLocation - Returns location of namespace keyword. + SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; } + + /// getIdentLocation - Returns location of identifier. + SourceLocation getIdentLocation() const { return IdentLoc; } + + static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamespaceDecl *Nominated, + DeclContext *CommonAncestor); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::UsingDirective; + } + static bool classof(const UsingDirectiveDecl *D) { return true; } + + // Friend for getUsingDirectiveName. + friend class DeclContext; +}; + +/// NamespaceAliasDecl - Represents a C++ namespace alias. For example: +/// +/// @code +/// namespace Foo = Bar; +/// @endcode +class NamespaceAliasDecl : public NamedDecl { + SourceLocation AliasLoc; + + /// \brief The source range that covers the nested-name-specifier + /// preceding the namespace name. + SourceRange QualifierRange; + + /// \brief The nested-name-specifier that precedes the namespace + /// name, if any. + NestedNameSpecifier *Qualifier; + + /// IdentLoc - Location of namespace identifier. + SourceLocation IdentLoc; + + /// Namespace - The Decl that this alias points to. Can either be a + /// NamespaceDecl or a NamespaceAliasDecl. + NamedDecl *Namespace; + + NamespaceAliasDecl(DeclContext *DC, SourceLocation L, + SourceLocation AliasLoc, IdentifierInfo *Alias, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, NamedDecl *Namespace) + : NamedDecl(Decl::NamespaceAlias, DC, L, Alias), AliasLoc(AliasLoc), + QualifierRange(QualifierRange), Qualifier(Qualifier), + IdentLoc(IdentLoc), Namespace(Namespace) { } + +public: + /// \brief Retrieve the source range of the nested-name-specifier + /// that qualifiers the namespace name. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + NamespaceDecl *getNamespace() { + if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace)) + return AD->getNamespace(); + + return cast<NamespaceDecl>(Namespace); + } + + const NamespaceDecl *getNamespace() const { + return const_cast<NamespaceAliasDecl*>(this)->getNamespace(); + } + + /// \brief Retrieve the namespace that this alias refers to, which + /// may either be a NamespaceDecl or a NamespaceAliasDecl. + NamedDecl *getAliasedNamespace() const { return Namespace; } + + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamedDecl *Namespace); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::NamespaceAlias; + } + static bool classof(const NamespaceAliasDecl *D) { return true; } +}; + +/// StaticAssertDecl - Represents a C++0x static_assert declaration. +class StaticAssertDecl : public Decl { + Expr *AssertExpr; + StringLiteral *Message; + + StaticAssertDecl(DeclContext *DC, SourceLocation L, + Expr *assertexpr, StringLiteral *message) + : Decl(StaticAssert, DC, L), AssertExpr(assertexpr), Message(message) { } + +public: + static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, Expr *AssertExpr, + StringLiteral *Message); + + Expr *getAssertExpr() { return AssertExpr; } + const Expr *getAssertExpr() const { return AssertExpr; } + + StringLiteral *getMessage() { return Message; } + const StringLiteral *getMessage() const { return Message; } + + virtual ~StaticAssertDecl(); + virtual void Destroy(ASTContext& C); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::StaticAssert; + } + static bool classof(StaticAssertDecl *D) { return true; } +}; + +/// Insertion operator for diagnostics. This allows sending AccessSpecifier's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + AccessSpecifier AS); + +} // end namespace clang + +#endif diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h new file mode 100644 index 000000000000..6c1231c0a73d --- /dev/null +++ b/include/clang/AST/DeclContextInternals.h @@ -0,0 +1,220 @@ +//===-- DeclContextInternals.h - DeclContext Representation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures used in the implementation +// of DeclContext. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H +#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> + +namespace clang { + +/// StoredDeclsList - This is an array of decls optimized a common case of only +/// containing one entry. +struct StoredDeclsList { + /// The kind of data encoded in this list. + enum DataKind { + /// \brief The data is a NamedDecl*. + DK_Decl = 0, + /// \brief The data is a declaration ID (an unsigned value), + /// shifted left by 2 bits. + DK_DeclID = 1, + /// \brief The data is a pointer to a vector (of type VectorTy) + /// that contains declarations. + DK_Decl_Vector = 2, + /// \brief The data is a pointer to a vector (of type VectorTy) + /// that contains declaration ID. + DK_ID_Vector = 3 + }; + + /// VectorTy - When in vector form, this is what the Data pointer points to. + typedef llvm::SmallVector<uintptr_t, 4> VectorTy; + + /// \brief The stored data, which will be either a declaration ID, a + /// pointer to a NamedDecl, or a pointer to a vector. + uintptr_t Data; + +public: + StoredDeclsList() : Data(0) {} + + StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) { + if (VectorTy *RHSVec = RHS.getAsVector()) { + VectorTy *New = new VectorTy(*RHSVec); + Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03); + } + } + + ~StoredDeclsList() { + // If this is a vector-form, free the vector. + if (VectorTy *Vector = getAsVector()) + delete Vector; + } + + StoredDeclsList &operator=(const StoredDeclsList &RHS) { + if (VectorTy *Vector = getAsVector()) + delete Vector; + Data = RHS.Data; + if (VectorTy *RHSVec = RHS.getAsVector()) { + VectorTy *New = new VectorTy(*RHSVec); + Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03); + } + return *this; + } + + bool isNull() const { return (Data & ~0x03) == 0; } + + NamedDecl *getAsDecl() const { + if ((Data & 0x03) != DK_Decl) + return 0; + + return reinterpret_cast<NamedDecl *>(Data & ~0x03); + } + + VectorTy *getAsVector() const { + if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector) + return 0; + + return reinterpret_cast<VectorTy *>(Data & ~0x03); + } + + void setOnlyValue(NamedDecl *ND) { + assert(!getAsVector() && "Not inline"); + Data = reinterpret_cast<uintptr_t>(ND); + } + + void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) { + if (Vec.size() > 1) { + VectorTy *Vector = getAsVector(); + if (!Vector) { + Vector = new VectorTy; + Data = reinterpret_cast<uintptr_t>(Vector) | DK_ID_Vector; + } + + Vector->resize(Vec.size()); + std::copy(Vec.begin(), Vec.end(), Vector->begin()); + return; + } + + if (VectorTy *Vector = getAsVector()) + delete Vector; + + if (Vec.empty()) + Data = 0; + else + Data = (Vec[0] << 2) | DK_DeclID; + } + + /// \brief Force the stored declarations list to contain actual + /// declarations. + /// + /// This routine will resolve any declaration IDs for declarations + /// that may not yet have been loaded from external storage. + void materializeDecls(ASTContext &Context); + + bool hasDeclarationIDs() const { + DataKind DK = (DataKind)(Data & 0x03); + return DK == DK_DeclID || DK == DK_ID_Vector; + } + + /// getLookupResult - Return an array of all the decls that this list + /// represents. + DeclContext::lookup_result getLookupResult(ASTContext &Context) { + if (isNull()) + return DeclContext::lookup_result(0, 0); + + if (hasDeclarationIDs()) + materializeDecls(Context); + + // If we have a single NamedDecl, return it. + if (getAsDecl()) { + assert(!isNull() && "Empty list isn't allowed"); + + // Data is a raw pointer to a NamedDecl*, return it. + void *Ptr = &Data; + return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1); + } + + assert(getAsVector() && "Must have a vector at this point"); + VectorTy &Vector = *getAsVector(); + + // Otherwise, we have a range result. + return DeclContext::lookup_result((NamedDecl **)&Vector[0], + (NamedDecl **)&Vector[0]+Vector.size()); + } + + /// HandleRedeclaration - If this is a redeclaration of an existing decl, + /// replace the old one with D and return true. Otherwise return false. + bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) { + if (hasDeclarationIDs()) + materializeDecls(Context); + + // Most decls only have one entry in their list, special case it. + if (NamedDecl *OldD = getAsDecl()) { + if (!D->declarationReplaces(OldD)) + return false; + setOnlyValue(D); + return true; + } + + // Determine if this declaration is actually a redeclaration. + VectorTy &Vec = *getAsVector(); + for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); + OD != ODEnd; ++OD) { + NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD); + if (D->declarationReplaces(OldD)) { + *OD = reinterpret_cast<uintptr_t>(D); + return true; + } + } + + return false; + } + + /// AddSubsequentDecl - This is called on the second and later decl when it is + /// not a redeclaration to merge it into the appropriate place in our list. + /// + void AddSubsequentDecl(NamedDecl *D) { + assert(!hasDeclarationIDs() && "Must materialize before adding decls"); + + // If this is the second decl added to the list, convert this to vector + // form. + if (NamedDecl *OldD = getAsDecl()) { + VectorTy *VT = new VectorTy(); + VT->push_back(reinterpret_cast<uintptr_t>(OldD)); + Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector; + } + + VectorTy &Vec = *getAsVector(); + if (isa<UsingDirectiveDecl>(D) || + D->getIdentifierNamespace() == Decl::IDNS_Tag) + Vec.push_back(reinterpret_cast<uintptr_t>(D)); + else if (reinterpret_cast<NamedDecl *>(Vec.back()) + ->getIdentifierNamespace() == Decl::IDNS_Tag) { + uintptr_t TagD = Vec.back(); + Vec.back() = reinterpret_cast<uintptr_t>(D); + Vec.push_back(TagD); + } else + Vec.push_back(reinterpret_cast<uintptr_t>(D)); + } +}; + +typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap; + + +} // end namespace clang + +#endif diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h new file mode 100644 index 000000000000..15a8adef8e57 --- /dev/null +++ b/include/clang/AST/DeclGroup.h @@ -0,0 +1,152 @@ +//===--- DeclGroup.h - Classes for representing groups of Decls -*- 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 DeclGroup, DeclGroupRef, and OwningDeclGroup classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLGROUP_H +#define LLVM_CLANG_AST_DECLGROUP_H + +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class ASTContext; +class Decl; +class DeclGroup; +class DeclGroupIterator; + +class DeclGroup { + // FIXME: Include a TypeSpecifier object. + unsigned NumDecls; + +private: + DeclGroup() : NumDecls(0) {} + DeclGroup(unsigned numdecls, Decl** decls); + +public: + static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls); + void Destroy(ASTContext& C); + + unsigned size() const { return NumDecls; } + + Decl*& operator[](unsigned i) { + assert (i < NumDecls && "Out-of-bounds access."); + return *((Decl**) (this+1)); + } + + Decl* const& operator[](unsigned i) const { + assert (i < NumDecls && "Out-of-bounds access."); + return *((Decl* const*) (this+1)); + } +}; + +class DeclGroupRef { + // Note this is not a PointerIntPair because we need the address of the + // non-group case to be valid as a Decl** for iteration. + enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; + Decl* D; + + Kind getKind() const { + return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask); + } + +public: + DeclGroupRef() : D(0) {} + + explicit DeclGroupRef(Decl* d) : D(d) {} + explicit DeclGroupRef(DeclGroup* dg) + : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {} + + static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { + if (NumDecls == 0) + return DeclGroupRef(); + if (NumDecls == 1) + return DeclGroupRef(Decls[0]); + return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls)); + } + + typedef Decl** iterator; + typedef Decl* const * const_iterator; + + bool isNull() const { return D == 0; } + bool isSingleDecl() const { return getKind() == SingleDeclKind; } + bool isDeclGroup() const { return getKind() == DeclGroupKind; } + + Decl *getSingleDecl() { + assert(isSingleDecl() && "Isn't a declgroup"); + return D; + } + const Decl *getSingleDecl() const { + return const_cast<DeclGroupRef*>(this)->getSingleDecl(); + } + + DeclGroup &getDeclGroup() { + assert(isDeclGroup() && "Isn't a declgroup"); + return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask)); + } + const DeclGroup &getDeclGroup() const { + return const_cast<DeclGroupRef*>(this)->getDeclGroup(); + } + + iterator begin() { + if (isSingleDecl()) + return D ? &D : 0; + return &getDeclGroup()[0]; + } + + iterator end() { + if (isSingleDecl()) + return D ? &D+1 : 0; + DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + const_iterator begin() const { + if (isSingleDecl()) + return D ? &D : 0; + return &getDeclGroup()[0]; + } + + const_iterator end() const { + if (isSingleDecl()) + return D ? &D+1 : 0; + const DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + void *getAsOpaquePtr() const { return D; } + static DeclGroupRef getFromOpaquePtr(void *Ptr) { + DeclGroupRef X; + X.D = static_cast<Decl*>(Ptr); + return X; + } +}; + +} // end clang namespace + +namespace llvm { + // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits. + template <typename T> + class PointerLikeTypeTraits; + template <> + class PointerLikeTypeTraits<clang::DeclGroupRef> { + public: + static inline void *getAsVoidPointer(clang::DeclGroupRef P) { + return P.getAsOpaquePtr(); + } + static inline clang::DeclGroupRef getFromVoidPointer(void *P) { + return clang::DeclGroupRef::getFromOpaquePtr(P); + } + enum { NumLowBitsAvailable = 0 }; + }; +} +#endif diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def new file mode 100644 index 000000000000..d1b921a4cb65 --- /dev/null +++ b/include/clang/AST/DeclNodes.def @@ -0,0 +1,161 @@ +//===-- DeclNodes.def - Metadata about Decl AST nodes -----------*- 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 declaration nodes within the AST. The +// description of the declaration nodes uses six macros: +// +// DECL(Derived, Base) describes a normal declaration type Derived +// and specifies its base class. Note that Derived should not have +// the Decl suffix on it, while Base should. +// +// LAST_DECL(Derived, Base) is like DECL, but is used for the last +// declaration in the list. +// +// ABSTRACT_DECL(Derived, Base) describes an abstract class that is +// used to specify a classification of declarations. For example, +// TagDecl is an abstract class used to describe the various kinds of +// "tag" declarations (unions, structs, classes, enums). +// +// DECL_CONTEXT(Decl) specifies that Decl is a kind of declaration +// that is also a DeclContext. +// +// LAST_DECL_CONTEXT(Decl) is like DECL_CONTEXT, but is used for the +// last declaration context. +// +// DECL_RANGE(CommonBase, Start, End) specifies a range of +// declaration values that have a common (potentially indirect) base +// class. +// +// LAST_DECL_RANGE(CommonBase, Start, End) is like DECL_RANGE, but is +// used for the last declaration range. +// +// Note that, due to the use of ranges, the order of the these +// declarations is significant. A declaration should be listed under +// its base class. +// ===----------------------------------------------------------------------===// + +#ifndef DECL +# define DECL(Derived, Base) +#endif + +#ifndef LAST_DECL +# define LAST_DECL(Derived, Base) DECL(Derived, Base) +#endif + +#ifndef ABSTRACT_DECL +# define ABSTRACT_DECL(Derived, Base) +#endif + +#ifndef DECL_CONTEXT +# define DECL_CONTEXT(Decl) +#endif + +#ifndef DECL_CONTEXT_BASE +# define DECL_CONTEXT_BASE(Decl) DECL_CONTEXT(Decl) +#endif + +#ifndef LAST_DECL_CONTEXT +# define LAST_DECL_CONTEXT(Decl) DECL_CONTEXT(Decl) +#endif + +#ifndef DECL_RANGE +# define DECL_RANGE(CommonBase, Start, End) +#endif + +#ifndef LAST_DECL_RANGE +# define LAST_DECL_RANGE(CommonBase, Start, End) \ + DECL_RANGE(CommonBase, Start, End) +#endif + +DECL(TranslationUnit, Decl) +ABSTRACT_DECL(Named, Decl) + DECL(OverloadedFunction, NamedDecl) + DECL(Namespace, NamedDecl) + DECL(UsingDirective, NamedDecl) + DECL(NamespaceAlias, NamedDecl) + ABSTRACT_DECL(Type, NamedDecl) + DECL(Typedef, TypeDecl) + ABSTRACT_DECL(Tag, TypeDecl) + DECL(Enum, TagDecl) + DECL(Record, TagDecl) + DECL(CXXRecord, RecordDecl) + DECL(ClassTemplateSpecialization, CXXRecordDecl) + DECL(ClassTemplatePartialSpecialization, + ClassTemplateSpecializationDecl) + DECL(TemplateTypeParm, TypeDecl) + ABSTRACT_DECL(Value, NamedDecl) + DECL(EnumConstant, ValueDecl) + DECL(Function, ValueDecl) + DECL(CXXMethod, FunctionDecl) + DECL(CXXConstructor, CXXMethodDecl) + DECL(CXXDestructor, CXXMethodDecl) + DECL(CXXConversion, CXXMethodDecl) + DECL(Field, ValueDecl) + DECL(ObjCIvar, FieldDecl) + DECL(ObjCAtDefsField, FieldDecl) + DECL(Var, ValueDecl) + DECL(ImplicitParam, VarDecl) + DECL(ParmVar, VarDecl) + DECL(OriginalParmVar, ParmVarDecl) + DECL(NonTypeTemplateParm, VarDecl) + DECL(Template, NamedDecl) + DECL(FunctionTemplate, TemplateDecl) + DECL(ClassTemplate, TemplateDecl) + DECL(TemplateTemplateParm, TemplateDecl) + DECL(ObjCMethod, NamedDecl) + DECL(ObjCContainer, NamedDecl) + DECL(ObjCCategory, ObjCContainerDecl) + DECL(ObjCProtocol, ObjCContainerDecl) + DECL(ObjCInterface, ObjCContainerDecl) + DECL(ObjCProperty, NamedDecl) + DECL(ObjCCompatibleAlias, NamedDecl) + ABSTRACT_DECL(ObjCImpl, NamedDecl) + DECL(ObjCCategoryImpl, ObjCImplDecl) + DECL(ObjCImplementation, ObjCImplDecl) +DECL(LinkageSpec, Decl) +DECL(ObjCPropertyImpl, Decl) +DECL(ObjCForwardProtocol, Decl) +DECL(ObjCClass, Decl) +DECL(FileScopeAsm, Decl) +DECL(StaticAssert, Decl) +LAST_DECL(Block, Decl) + +// Declaration contexts. DECL_CONTEXT_BASE indicates that it has subclasses. +DECL_CONTEXT(TranslationUnit) +DECL_CONTEXT(Namespace) +DECL_CONTEXT(LinkageSpec) +DECL_CONTEXT(ObjCMethod) +DECL_CONTEXT(ObjCCategoryImpl) +DECL_CONTEXT(ObjCImplementation) +DECL_CONTEXT_BASE(Tag) +DECL_CONTEXT_BASE(Function) +DECL_CONTEXT_BASE(ObjCContainer) +LAST_DECL_CONTEXT(Block) + +// Declaration ranges +DECL_RANGE(Named, OverloadedFunction, ObjCImplementation) +DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface) +DECL_RANGE(Field, Field, ObjCAtDefsField) +DECL_RANGE(Type, Typedef, TemplateTypeParm) +DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization) +DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization) +DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm) +DECL_RANGE(Function, Function, CXXConversion) +DECL_RANGE(Template, Template, TemplateTemplateParm) +DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation) +LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm) + +#undef LAST_DECL_RANGE +#undef DECL_RANGE +#undef LAST_DECL_CONTEXT +#undef DECL_CONTEXT_BASE +#undef DECL_CONTEXT +#undef ABSTRACT_DECL +#undef LAST_DECL +#undef DECL diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h new file mode 100644 index 000000000000..6e89a7ae7bc9 --- /dev/null +++ b/include/clang/AST/DeclObjC.h @@ -0,0 +1,1224 @@ +//===--- DeclObjC.h - Classes for representing declarations -----*- 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 DeclObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLOBJC_H +#define LLVM_CLANG_AST_DECLOBJC_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +class Expr; +class Stmt; +class FunctionDecl; +class AttributeList; +class RecordDecl; +class ObjCIvarDecl; +class ObjCMethodDecl; +class ObjCProtocolDecl; +class ObjCCategoryDecl; +class ObjCPropertyDecl; +class ObjCPropertyImplDecl; + +class ObjCListBase { + void operator=(const ObjCListBase &); // DO NOT IMPLEMENT + ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT +protected: + /// List is an array of pointers to objects that are not owned by this object. + void **List; + unsigned NumElts; + +public: + ObjCListBase() : List(0), NumElts(0) {} + ~ObjCListBase() { + assert(List == 0 && "Destroy should have been called before dtor"); + } + + void Destroy(ASTContext &Ctx); + + unsigned size() const { return NumElts; } + bool empty() const { return NumElts == 0; } + +protected: + void set(void *const* InList, unsigned Elts, ASTContext &Ctx); +}; + + +/// ObjCList - This is a simple template class used to hold various lists of +/// decls etc, which is heavily used by the ObjC front-end. This only use case +/// this supports is setting the list all at once and then reading elements out +/// of it. +template <typename T> +class ObjCList : public ObjCListBase { +public: + void set(T* const* InList, unsigned Elts, ASTContext &Ctx) { + ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx); + } + + typedef T* const * iterator; + iterator begin() const { return (iterator)List; } + iterator end() const { return (iterator)List+NumElts; } + + T* operator[](unsigned Idx) const { + assert(Idx < NumElts && "Invalid access"); + return (T*)List[Idx]; + } +}; + + + +/// ObjCMethodDecl - Represents an instance or class method declaration. +/// ObjC methods can be declared within 4 contexts: class interfaces, +/// categories, protocols, and class implementations. While C++ member +/// functions leverage C syntax, Objective-C method syntax is modeled after +/// Smalltalk (using colons to specify argument types/expressions). +/// Here are some brief examples: +/// +/// Setter/getter instance methods: +/// - (void)setMenu:(NSMenu *)menu; +/// - (NSMenu *)menu; +/// +/// Instance method that takes 2 NSView arguments: +/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView; +/// +/// Getter class method: +/// + (NSMenu *)defaultMenu; +/// +/// A selector represents a unique name for a method. The selector names for +/// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu. +/// +class ObjCMethodDecl : public NamedDecl, public DeclContext { +public: + enum ImplementationControl { None, Required, Optional }; +private: + /// Bitfields must be first fields in this class so they pack with those + /// declared in class Decl. + /// instance (true) or class (false) method. + bool IsInstance : 1; + bool IsVariadic : 1; + + // Synthesized declaration method for a property setter/getter + bool IsSynthesized : 1; + + // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum + /// @required/@optional + unsigned DeclImplementation : 2; + + // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum + /// in, inout, etc. + unsigned objcDeclQualifier : 6; + + // Type of this method. + QualType MethodDeclType; + /// ParamInfo - List of pointers to VarDecls for the formal parameters of this + /// Method. + ObjCList<ParmVarDecl> ParamInfo; + + /// List of attributes for this method declaration. + SourceLocation EndLoc; // the location of the ';' or '{'. + + // The following are only used for method definitions, null otherwise. + // FIXME: space savings opportunity, consider a sub-class. + Stmt *Body; + + /// SelfDecl - Decl for the implicit self parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *SelfDecl; + /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *CmdDecl; + + ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, + Selector SelInfo, QualType T, + DeclContext *contextDecl, + bool isInstance = true, + bool isVariadic = false, + bool isSynthesized = false, + ImplementationControl impControl = None) + : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), + DeclContext(ObjCMethod), + IsInstance(isInstance), IsVariadic(isVariadic), + IsSynthesized(isSynthesized), + DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None), + MethodDeclType(T), + EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {} + + virtual ~ObjCMethodDecl() {} + +public: + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + static ObjCMethodDecl *Create(ASTContext &C, + SourceLocation beginLoc, + SourceLocation endLoc, Selector SelInfo, + QualType T, DeclContext *contextDecl, + bool isInstance = true, + bool isVariadic = false, + bool isSynthesized = false, + ImplementationControl impControl = None); + + ObjCDeclQualifier getObjCDeclQualifier() const { + return ObjCDeclQualifier(objcDeclQualifier); + } + void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const { return getLocation(); } + SourceLocation getLocEnd() const { return EndLoc; } + void setEndLoc(SourceLocation Loc) { EndLoc = Loc; } + SourceRange getSourceRange() const { + return SourceRange(getLocation(), EndLoc); + } + + ObjCInterfaceDecl *getClassInterface(); + const ObjCInterfaceDecl *getClassInterface() const { + return const_cast<ObjCMethodDecl*>(this)->getClassInterface(); + } + + Selector getSelector() const { return getDeclName().getObjCSelector(); } + unsigned getSynthesizedMethodSize() const; + QualType getResultType() const { return MethodDeclType; } + void setResultType(QualType T) { MethodDeclType = T; } + + // Iterator access to formal parameters. + unsigned param_size() const { return ParamInfo.size(); } + typedef ObjCList<ParmVarDecl>::iterator param_iterator; + param_iterator param_begin() const { return ParamInfo.begin(); } + param_iterator param_end() const { return ParamInfo.end(); } + + void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num) { + ParamInfo.set(List, Num, C); + } + + // Iterator access to parameter types. + typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun; + typedef llvm::mapped_iterator<param_iterator, deref_fun> arg_type_iterator; + + arg_type_iterator arg_type_begin() const { + return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType)); + } + arg_type_iterator arg_type_end() const { + return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType)); + } + + /// createImplicitParams - Used to lazily create the self and cmd + /// implict parameters. This must be called prior to using getSelfDecl() + /// or getCmdDecl(). The call is ignored if the implicit paramters + /// have already been created. + void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID); + + ImplicitParamDecl * getSelfDecl() const { return SelfDecl; } + void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; } + ImplicitParamDecl * getCmdDecl() const { return CmdDecl; } + void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; } + + bool isInstanceMethod() const { return IsInstance; } + void setInstanceMethod(bool isInst) { IsInstance = isInst; } + bool isVariadic() const { return IsVariadic; } + void setVariadic(bool isVar) { IsVariadic = isVar; } + + bool isClassMethod() const { return !IsInstance; } + + bool isSynthesized() const { return IsSynthesized; } + void setSynthesized(bool isSynth) { IsSynthesized = isSynth; } + + // Related to protocols declared in @protocol + void setDeclImplementation(ImplementationControl ic) { + DeclImplementation = ic; + } + ImplementationControl getImplementationControl() const { + return ImplementationControl(DeclImplementation); + } + + virtual Stmt *getBody(ASTContext &C) const { + return (Stmt*) Body; + } + CompoundStmt *getBody() { return (CompoundStmt*)Body; } + void setBody(Stmt *B) { Body = B; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; } + static bool classof(const ObjCMethodDecl *D) { return true; } + static DeclContext *castToDeclContext(const ObjCMethodDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D)); + } + static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ObjCMethodList - a linked list of methods with different signatures. +struct ObjCMethodList { + ObjCMethodDecl *Method; + ObjCMethodList *Next; + + ObjCMethodList() { + Method = 0; + Next = 0; + } + ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { + Method = M; + Next = C; + } +}; + +/// ObjCContainerDecl - Represents a container for method declarations. +/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, and +/// ObjCProtocolDecl. +/// FIXME: Use for ObjC implementation decls. +/// +class ObjCContainerDecl : public NamedDecl, public DeclContext { + SourceLocation AtEndLoc; // marks the end of the method container. +public: + + ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : NamedDecl(DK, DC, L, Id), DeclContext(DK) {} + + virtual ~ObjCContainerDecl() {} + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator; + prop_iterator prop_begin(ASTContext &Context) const { + return prop_iterator(decls_begin(Context)); + } + prop_iterator prop_end(ASTContext &Context) const { + return prop_iterator(decls_end(Context)); + } + + // Iterator access to instance/class methods. + typedef specific_decl_iterator<ObjCMethodDecl> method_iterator; + method_iterator meth_begin(ASTContext &Context) const { + return method_iterator(decls_begin(Context)); + } + method_iterator meth_end(ASTContext &Context) const { + return method_iterator(decls_end(Context)); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod> + instmeth_iterator; + instmeth_iterator instmeth_begin(ASTContext &Context) const { + return instmeth_iterator(decls_begin(Context)); + } + instmeth_iterator instmeth_end(ASTContext &Context) const { + return instmeth_iterator(decls_end(Context)); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod> + classmeth_iterator; + classmeth_iterator classmeth_begin(ASTContext &Context) const { + return classmeth_iterator(decls_begin(Context)); + } + classmeth_iterator classmeth_end(ASTContext &Context) const { + return classmeth_iterator(decls_end(Context)); + } + + // Get the local instance/class method declared in this interface. + ObjCMethodDecl *getInstanceMethod(ASTContext &Context, Selector Sel) const; + ObjCMethodDecl *getClassMethod(ASTContext &Context, Selector Sel) const; + + ObjCMethodDecl * + getMethod(ASTContext &Context, Selector Sel, bool isInstance) const { + return isInstance ? getInstanceMethod(Context, Sel) + : getClassMethod(Context, Sel); + } + + ObjCPropertyDecl *FindPropertyDeclaration(ASTContext &Context, + IdentifierInfo *PropertyId) const; + + // Marks the end of the container. + SourceLocation getAtEndLoc() const { return AtEndLoc; } + void setAtEndLoc(SourceLocation L) { AtEndLoc = L; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= ObjCContainerFirst && + D->getKind() <= ObjCContainerLast; + } + static bool classof(const ObjCContainerDecl *D) { return true; } + + static DeclContext *castToDeclContext(const ObjCContainerDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D)); + } + static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ObjCInterfaceDecl - Represents an ObjC class declaration. For example: +/// +/// // MostPrimitive declares no super class (not particularly useful). +/// @interface MostPrimitive +/// // no instance variables or methods. +/// @end +/// +/// // NSResponder inherits from NSObject & implements NSCoding (a protocol). +/// @interface NSResponder : NSObject <NSCoding> +/// { // instance variables are represented by ObjCIvarDecl. +/// id nextResponder; // nextResponder instance variable. +/// } +/// - (NSResponder *)nextResponder; // return a pointer to NSResponder. +/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer +/// @end // to an NSEvent. +/// +/// Unlike C/C++, forward class declarations are accomplished with @class. +/// Unlike C/C++, @class allows for a list of classes to be forward declared. +/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes +/// typically inherit from NSObject (an exception is NSProxy). +/// +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; + friend class ASTContext; + + /// Class's super class. + ObjCInterfaceDecl *SuperClass; + + /// Protocols referenced in interface header declaration + ObjCList<ObjCProtocolDecl> ReferencedProtocols; + + /// Instance variables in the interface. + ObjCList<ObjCIvarDecl> IVars; + + /// List of categories defined for this class. + /// FIXME: Why is this a linked list?? + ObjCCategoryDecl *CategoryList; + + bool ForwardDecl:1; // declared with @class. + bool InternalInterface:1; // true - no @interface for @implementation + + SourceLocation ClassLoc; // location of the class identifier. + SourceLocation SuperClassLoc; // location of the super class identifier. + SourceLocation EndLoc; // marks the '>', '}', or identifier. + + ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + SourceLocation CLoc, bool FD, bool isInternal); + + virtual ~ObjCInterfaceDecl() {} + +public: + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation atLoc, + IdentifierInfo *Id, + SourceLocation ClassLoc = SourceLocation(), + bool ForwardDecl = false, + bool isInternal = false); + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + return ReferencedProtocols; + } + + ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + + typedef ObjCList<ObjCIvarDecl>::iterator ivar_iterator; + ivar_iterator ivar_begin() const { return IVars.begin(); } + ivar_iterator ivar_end() const { return IVars.end(); } + unsigned ivar_size() const { return IVars.size(); } + bool ivar_empty() const { return IVars.empty(); } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num, + ASTContext &C) { + ReferencedProtocols.set(List, Num, C); + } + + void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) { + IVars.set(List, Num, C); + } + + bool isForwardDecl() const { return ForwardDecl; } + void setForwardDecl(bool val) { ForwardDecl = val; } + + ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } + + ObjCCategoryDecl* getCategoryList() const { return CategoryList; } + void setCategoryList(ObjCCategoryDecl *category) { + CategoryList = category; + } + + /// isSuperClassOf - Return true if this class is the specified class or is a + /// super class of the specified interface class. + bool isSuperClassOf(const ObjCInterfaceDecl *I) const { + // If RHS is derived from LHS it is OK; else it is not OK. + while (I != NULL) { + if (this == I) + return true; + I = I->getSuperClass(); + } + return false; + } + + ObjCIvarDecl *lookupInstanceVariable(ASTContext &Context, + IdentifierInfo *IVarName, + ObjCInterfaceDecl *&ClassDeclared); + ObjCIvarDecl *lookupInstanceVariable(ASTContext &Context, + IdentifierInfo *IVarName) { + ObjCInterfaceDecl *ClassDeclared; + return lookupInstanceVariable(Context, IVarName, ClassDeclared); + } + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupInstanceMethod(ASTContext &Context, Selector Sel); + ObjCMethodDecl *lookupClassMethod(ASTContext &Context, Selector Sel); + ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const { return getLocation(); } // '@'interface + SourceLocation getLocEnd() const { return EndLoc; } + void setLocEnd(SourceLocation LE) { EndLoc = LE; }; + + void setClassLoc(SourceLocation Loc) { ClassLoc = Loc; } + SourceLocation getClassLoc() const { return ClassLoc; } + void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; } + SourceLocation getSuperClassLoc() const { return SuperClassLoc; } + + /// isImplicitInterfaceDecl - check that this is an implicitly declared + /// ObjCInterfaceDecl node. This is for legacy objective-c @implementation + /// declaration without an @interface declaration. + bool isImplicitInterfaceDecl() const { return InternalInterface; } + void setImplicitInterfaceDecl(bool val) { InternalInterface = val; } + + // Low-level accessor + Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(Type *TD) const { TypeForDecl = TD; } + + static bool classof(const Decl *D) { return D->getKind() == ObjCInterface; } + static bool classof(const ObjCInterfaceDecl *D) { return true; } +}; + +/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC +/// instance variables are identical to C. The only exception is Objective-C +/// supports C++ style access control. For example: +/// +/// @interface IvarExample : NSObject +/// { +/// id defaultToProtected; +/// @public: +/// id canBePublic; // same as C++. +/// @protected: +/// id canBeProtected; // same as C++. +/// @package: +/// id canBePackage; // framework visibility (not available in C++). +/// } +/// +class ObjCIvarDecl : public FieldDecl { +public: + enum AccessControl { + None, Private, Protected, Public, Package + }; + +private: + ObjCIvarDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + QualType T, AccessControl ac, Expr *BW) + : FieldDecl(ObjCIvar, DC, L, Id, T, BW, /*Mutable=*/false), + DeclAccess(ac) {} + +public: + static ObjCIvarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + AccessControl ac, Expr *BW = NULL); + + void setAccessControl(AccessControl ac) { DeclAccess = ac; } + + AccessControl getAccessControl() const { return AccessControl(DeclAccess); } + + AccessControl getCanonicalAccessControl() const { + return DeclAccess == None ? Protected : AccessControl(DeclAccess); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == ObjCIvar; } + static bool classof(const ObjCIvarDecl *D) { return true; } +private: + // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum + unsigned DeclAccess : 3; +}; + + +/// ObjCAtDefsFieldDecl - Represents a field declaration created by an +/// @defs(...). +class ObjCAtDefsFieldDecl : public FieldDecl { +private: + ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *BW) + : FieldDecl(ObjCAtDefsField, DC, L, Id, T, BW, /*Mutable=*/false) {} + +public: + static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *BW); + + virtual void Destroy(ASTContext& C); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == ObjCAtDefsField; } + static bool classof(const ObjCAtDefsFieldDecl *D) { return true; } +}; + +/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols +/// declare a pure abstract type (i.e no instance variables are permitted). +/// Protocols orginally drew inspiration from C++ pure virtual functions (a C++ +/// feature with nice semantics and lousy syntax:-). Here is an example: +/// +/// @protocol NSDraggingInfo <refproto1, refproto2> +/// - (NSWindow *)draggingDestinationWindow; +/// - (NSImage *)draggedImage; +/// @end +/// +/// This says that NSDraggingInfo requires two methods and requires everything +/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as +/// well. +/// +/// @interface ImplementsNSDraggingInfo : NSObject <NSDraggingInfo> +/// @end +/// +/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and +/// protocols are in distinct namespaces. For example, Cocoa defines both +/// an NSObject protocol and class (which isn't allowed in Java). As a result, +/// protocols are referenced using angle brackets as follows: +/// +/// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo; +/// +class ObjCProtocolDecl : public ObjCContainerDecl { + /// Referenced protocols + ObjCList<ObjCProtocolDecl> ReferencedProtocols; + + bool isForwardProtoDecl; // declared with @protocol. + + SourceLocation EndLoc; // marks the '>' or identifier. + + ObjCProtocolDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) + : ObjCContainerDecl(ObjCProtocol, DC, L, Id), + isForwardProtoDecl(true) { + } + + virtual ~ObjCProtocolDecl() {} + +public: + static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + return ReferencedProtocols; + } + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + ASTContext &C) { + ReferencedProtocols.set(List, Num, C); + } + + ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupInstanceMethod(ASTContext &Context, Selector Sel); + ObjCMethodDecl *lookupClassMethod(ASTContext &Context, Selector Sel); + + bool isForwardDecl() const { return isForwardProtoDecl; } + void setForwardDecl(bool val) { isForwardProtoDecl = val; } + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const { return getLocation(); } // '@'protocol + SourceLocation getLocEnd() const { return EndLoc; } + void setLocEnd(SourceLocation LE) { EndLoc = LE; }; + + static bool classof(const Decl *D) { return D->getKind() == ObjCProtocol; } + static bool classof(const ObjCProtocolDecl *D) { return true; } +}; + +/// ObjCClassDecl - Specifies a list of forward class declarations. For example: +/// +/// @class NSCursor, NSImage, NSPasteboard, NSWindow; +/// +class ObjCClassDecl : public Decl { + ObjCList<ObjCInterfaceDecl> ForwardDecls; + + ObjCClassDecl(DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *const *Elts, unsigned nElts, ASTContext &C); + virtual ~ObjCClassDecl() {} +public: + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *const *Elts = 0, + unsigned nElts = 0); + + typedef ObjCList<ObjCInterfaceDecl>::iterator iterator; + iterator begin() const { return ForwardDecls.begin(); } + iterator end() const { return ForwardDecls.end(); } + unsigned size() const { return ForwardDecls.size(); } + + /// setClassList - Set the list of forward classes. + void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, unsigned Num) { + ForwardDecls.set(List, Num, C); + } + + static bool classof(const Decl *D) { return D->getKind() == ObjCClass; } + static bool classof(const ObjCClassDecl *D) { return true; } +}; + +/// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations. +/// For example: +/// +/// @protocol NSTextInput, NSChangeSpelling, NSDraggingInfo; +/// +class ObjCForwardProtocolDecl : public Decl { + ObjCList<ObjCProtocolDecl> ReferencedProtocols; + + ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, + ObjCProtocolDecl *const *Elts, unsigned nElts, + ASTContext &C); + virtual ~ObjCForwardProtocolDecl() {} + +public: + static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCProtocolDecl *const *Elts = 0, + unsigned Num = 0); + + /// Destroy - Call destructors and release memory. + virtual void Destroy(ASTContext& C); + + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + + /// setProtocolList - Set the list of forward protocols. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + ASTContext &C) { + ReferencedProtocols.set(List, Num, C); + } + static bool classof(const Decl *D) { + return D->getKind() == ObjCForwardProtocol; + } + static bool classof(const ObjCForwardProtocolDecl *D) { return true; } +}; + +/// ObjCCategoryDecl - Represents a category declaration. A category allows +/// you to add methods to an existing class (without subclassing or modifying +/// the original class interface or implementation:-). Categories don't allow +/// you to add instance data. The following example adds "myMethod" to all +/// NSView's within a process: +/// +/// @interface NSView (MyViewMethods) +/// - myMethod; +/// @end +/// +/// Cateogries also allow you to split the implementation of a class across +/// several files (a feature more naturally supported in C++). +/// +/// Categories were originally inspired by dynamic languages such as Common +/// Lisp and Smalltalk. More traditional class-based languages (C++, Java) +/// don't support this level of dynamism, which is both powerful and dangerous. +/// +class ObjCCategoryDecl : public ObjCContainerDecl { + /// Interface belonging to this category + ObjCInterfaceDecl *ClassInterface; + + /// referenced protocols in this category. + ObjCList<ObjCProtocolDecl> ReferencedProtocols; + + /// Next category belonging to this class. + /// FIXME: this should not be a singly-linked list. Move storage elsewhere. + ObjCCategoryDecl *NextClassCategory; + + SourceLocation EndLoc; // marks the '>' or identifier. + + ObjCCategoryDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) + : ObjCContainerDecl(ObjCCategory, DC, L, Id), + ClassInterface(0), NextClassCategory(0){ + } +public: + + static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + ASTContext &C) { + ReferencedProtocols.set(List, Num, C); + } + + const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + return ReferencedProtocols; + } + + typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + + ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } + void setNextClassCategory(ObjCCategoryDecl *Cat) { + NextClassCategory = Cat; + } + void insertNextClassCategory() { + NextClassCategory = ClassInterface->getCategoryList(); + ClassInterface->setCategoryList(this); + } + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const { return getLocation(); } // '@'interface + SourceLocation getLocEnd() const { return EndLoc; } + void setLocEnd(SourceLocation LE) { EndLoc = LE; }; + + static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; } + static bool classof(const ObjCCategoryDecl *D) { return true; } +}; + +class ObjCImplDecl : public NamedDecl, public DeclContext { + /// Class interface for this category implementation + ObjCInterfaceDecl *ClassInterface; + + SourceLocation EndLoc; + +protected: + ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *classInterface) + : NamedDecl(DK, DC, L, + classInterface? classInterface->getDeclName() + : DeclarationName()), + DeclContext(DK), ClassInterface(classInterface) {} + +public: + virtual ~ObjCImplDecl() {} + + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + void setClassInterface(ObjCInterfaceDecl *IFace) { ClassInterface = IFace; } + + void addInstanceMethod(ASTContext &Context, ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(Context, method); + } + void addClassMethod(ASTContext &Context, ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(Context, method); + } + + // Get the local instance/class method declared in this interface. + ObjCMethodDecl *getInstanceMethod(ASTContext &Context, Selector Sel) const; + ObjCMethodDecl *getClassMethod(ASTContext &Context, Selector Sel) const; + ObjCMethodDecl *getMethod(ASTContext &Context, Selector Sel, + bool isInstance) const { + return isInstance ? getInstanceMethod(Context, Sel) + : getClassMethod(Context, Sel); + } + + void addPropertyImplementation(ASTContext &Context, + ObjCPropertyImplDecl *property); + + ObjCPropertyImplDecl *FindPropertyImplDecl(ASTContext &Context, + IdentifierInfo *propertyId) const; + ObjCPropertyImplDecl *FindPropertyImplIvarDecl(ASTContext &Context, + IdentifierInfo *ivarId) const; + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator; + propimpl_iterator propimpl_begin(ASTContext &Context) const { + return propimpl_iterator(decls_begin(Context)); + } + propimpl_iterator propimpl_end(ASTContext &Context) const { + return propimpl_iterator(decls_end(Context)); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod> + instmeth_iterator; + instmeth_iterator instmeth_begin(ASTContext &Context) const { + return instmeth_iterator(decls_begin(Context)); + } + instmeth_iterator instmeth_end(ASTContext &Context) const { + return instmeth_iterator(decls_end(Context)); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod> + classmeth_iterator; + classmeth_iterator classmeth_begin(ASTContext &Context) const { + return classmeth_iterator(decls_begin(Context)); + } + classmeth_iterator classmeth_end(ASTContext &Context) const { + return classmeth_iterator(decls_end(Context)); + } + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const { return getLocation(); } + SourceLocation getLocEnd() const { return EndLoc; } + void setLocEnd(SourceLocation LE) { EndLoc = LE; }; +}; + +/// ObjCCategoryImplDecl - An object of this class encapsulates a category +/// @implementation declaration. If a category class has declaration of a +/// property, its implementation must be specified in the category's +/// @implementation declaration. Example: +/// @interface I @end +/// @interface I(CATEGORY) +/// @property int p1, d1; +/// @end +/// @implementation I(CATEGORY) +/// @dynamic p1,d1; +/// @end +/// +/// ObjCCategoryImplDecl +class ObjCCategoryImplDecl : public ObjCImplDecl { + // Category name + IdentifierInfo *Id; + + ObjCCategoryImplDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface) + : ObjCImplDecl(ObjCCategoryImpl, DC, L, classInterface), Id(Id) {} +public: + static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface); + + /// getIdentifier - Get the identifier that names the class + /// interface associated with this implementation. + IdentifierInfo *getIdentifier() const { + return Id; + } + void setIdentifier(IdentifierInfo *II) { Id = II; } + + /// getNameAsCString - Get the name of identifier for the class + /// interface associated with this implementation as a C string + /// (const char*). + const char *getNameAsCString() const { + return Id ? Id->getName() : ""; + } + + /// @brief Get the name of the class associated with this interface. + std::string getNameAsString() const { + return Id ? Id->getName() : ""; + } + + static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;} + static bool classof(const ObjCCategoryImplDecl *D) { return true; } + static DeclContext *castToDeclContext(const ObjCCategoryImplDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCCategoryImplDecl*>(D)); + } + static ObjCCategoryImplDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCCategoryImplDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ObjCImplementationDecl - Represents a class definition - this is where +/// method definitions are specified. For example: +/// +/// @code +/// @implementation MyClass +/// - (void)myMethod { /* do something */ } +/// @end +/// @endcode +/// +/// Typically, instance variables are specified in the class interface, +/// *not* in the implementation. Nevertheless (for legacy reasons), we +/// allow instance variables to be specified in the implementation. When +/// specified, they need to be *identical* to the interface. +/// +class ObjCImplementationDecl : public ObjCImplDecl { + /// Implementation Class's super class. + ObjCInterfaceDecl *SuperClass; + + ObjCImplementationDecl(DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl) + : ObjCImplDecl(ObjCImplementation, DC, L, classInterface), + SuperClass(superDecl){} +public: + static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl); + + /// getIdentifier - Get the identifier that names the class + /// interface associated with this implementation. + IdentifierInfo *getIdentifier() const { + return getClassInterface()->getIdentifier(); + } + + /// getNameAsCString - Get the name of identifier for the class + /// interface associated with this implementation as a C string + /// (const char*). + const char *getNameAsCString() const { + assert(getIdentifier() && "Name is not a simple identifier"); + return getIdentifier()->getName(); + } + + /// @brief Get the name of the class associated with this interface. + std::string getNameAsString() const { + return getClassInterface()->getNameAsString(); + } + + const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } + ObjCInterfaceDecl *getSuperClass() { return SuperClass; } + + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + ivar_iterator ivar_begin(ASTContext &Context) const { + return ivar_iterator(decls_begin(Context)); + } + ivar_iterator ivar_end(ASTContext &Context) const { + return ivar_iterator(decls_end(Context)); + } + unsigned ivar_size(ASTContext &Context) const { + return std::distance(ivar_begin(Context), ivar_end(Context)); + } + bool ivar_empty(ASTContext &Context) const { + return ivar_begin(Context) == ivar_end(Context); + } + + static bool classof(const Decl *D) { + return D->getKind() == ObjCImplementation; + } + static bool classof(const ObjCImplementationDecl *D) { return true; } + static DeclContext *castToDeclContext(const ObjCImplementationDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCImplementationDecl*>(D)); + } + static ObjCImplementationDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCImplementationDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is +/// declared as @compatibility_alias alias class. +class ObjCCompatibleAliasDecl : public NamedDecl { + /// Class that this is an alias of. + ObjCInterfaceDecl *AliasedClass; + + ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass) + : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} +public: + static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass); + + const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } + ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } + void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; } + + static bool classof(const Decl *D) { + return D->getKind() == ObjCCompatibleAlias; + } + static bool classof(const ObjCCompatibleAliasDecl *D) { return true; } + +}; + +/// ObjCPropertyDecl - Represents one property declaration in an interface. +/// For example: +/// @property (assign, readwrite) int MyProperty; +/// +class ObjCPropertyDecl : public NamedDecl { +public: + enum PropertyAttributeKind { + OBJC_PR_noattr = 0x00, + OBJC_PR_readonly = 0x01, + OBJC_PR_getter = 0x02, + OBJC_PR_assign = 0x04, + OBJC_PR_readwrite = 0x08, + OBJC_PR_retain = 0x10, + OBJC_PR_copy = 0x20, + OBJC_PR_nonatomic = 0x40, + OBJC_PR_setter = 0x80 + }; + + enum SetterKind { Assign, Retain, Copy }; + enum PropertyControl { None, Required, Optional }; +private: + QualType DeclType; + unsigned PropertyAttributes : 8; + + // @required/@optional + unsigned PropertyImplementation : 2; + + Selector GetterName; // getter name of NULL if no getter + Selector SetterName; // setter name of NULL if no setter + + ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method + ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method + ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property + + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + QualType T) + : NamedDecl(ObjCProperty, DC, L, Id), DeclType(T), + PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None), + GetterName(Selector()), + SetterName(Selector()), + GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {} +public: + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, QualType T, + PropertyControl propControl = None); + QualType getType() const { return DeclType; } + void setType(QualType T) { DeclType = T; } + + PropertyAttributeKind getPropertyAttributes() const { + return PropertyAttributeKind(PropertyAttributes); + } + void setPropertyAttributes(PropertyAttributeKind PRVal) { + PropertyAttributes |= PRVal; + } + + void makeitReadWriteAttribute(void) { + PropertyAttributes &= ~OBJC_PR_readonly; + PropertyAttributes |= OBJC_PR_readwrite; + } + + // Helper methods for accessing attributes. + + /// isReadOnly - Return true iff the property has a setter. + bool isReadOnly() const { + return (PropertyAttributes & OBJC_PR_readonly); + } + + /// getSetterKind - Return the method used for doing assignment in + /// the property setter. This is only valid if the property has been + /// defined to have a setter. + SetterKind getSetterKind() const { + if (PropertyAttributes & OBJC_PR_retain) + return Retain; + if (PropertyAttributes & OBJC_PR_copy) + return Copy; + return Assign; + } + + Selector getGetterName() const { return GetterName; } + void setGetterName(Selector Sel) { GetterName = Sel; } + + Selector getSetterName() const { return SetterName; } + void setSetterName(Selector Sel) { SetterName = Sel; } + + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; } + + // Related to @optional/@required declared in @protocol + void setPropertyImplementation(PropertyControl pc) { + PropertyImplementation = pc; + } + PropertyControl getPropertyImplementation() const { + return PropertyControl(PropertyImplementation); + } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { + PropertyIvarDecl = Ivar; + } + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + + static bool classof(const Decl *D) { + return D->getKind() == ObjCProperty; + } + static bool classof(const ObjCPropertyDecl *D) { return true; } +}; + +/// ObjCPropertyImplDecl - Represents implementation declaration of a property +/// in a class or category implementation block. For example: +/// @synthesize prop1 = ivar1; +/// +class ObjCPropertyImplDecl : public Decl { +public: + enum Kind { + Synthesize, + Dynamic + }; +private: + SourceLocation AtLoc; // location of @synthesize or @dynamic + /// Property declaration being implemented + ObjCPropertyDecl *PropertyDecl; + + /// Null for @dynamic. Required for @synthesize. + ObjCIvarDecl *PropertyIvarDecl; + + ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl) + : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), + PropertyDecl(property), PropertyIvarDecl(ivarDecl) { + assert (PK == Dynamic || PropertyIvarDecl); + } + +public: + static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl); + + SourceLocation getLocStart() const { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + ObjCPropertyDecl *getPropertyDecl() const { + return PropertyDecl; + } + void setPropertyDecl(ObjCPropertyDecl *Prop) { PropertyDecl = Prop; } + + Kind getPropertyImplementation() const { + return PropertyIvarDecl ? Synthesize : Dynamic; + } + + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } + + static bool classof(const Decl *D) { + return D->getKind() == ObjCPropertyImpl; + } + static bool classof(const ObjCPropertyImplDecl *D) { return true; } +}; + +} // end namespace clang +#endif diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h new file mode 100644 index 000000000000..226af3411d55 --- /dev/null +++ b/include/clang/AST/DeclTemplate.h @@ -0,0 +1,859 @@ +//===-- DeclTemplate.h - Classes for representing C++ templates -*- 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 C++ template declaration subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H +#define LLVM_CLANG_AST_DECLTEMPLATE_H + +#include "clang/AST/DeclCXX.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +class TemplateParameterList; +class TemplateDecl; +class FunctionTemplateDecl; +class ClassTemplateDecl; +class ClassTemplatePartialSpecializationDecl; +class TemplateTypeParmDecl; +class NonTypeTemplateParmDecl; +class TemplateTemplateParmDecl; + +/// TemplateParameterList - Stores a list of template parameters for a +/// TemplateDecl and its derived classes. +class TemplateParameterList { + /// The location of the 'template' keyword. + SourceLocation TemplateLoc; + + /// The locations of the '<' and '>' angle brackets. + SourceLocation LAngleLoc, RAngleLoc; + + /// The number of template parameters in this template + /// parameter list. + unsigned NumParams; + + TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, + Decl **Params, unsigned NumParams, + SourceLocation RAngleLoc); + +public: + static TemplateParameterList *Create(ASTContext &C, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + Decl **Params, + unsigned NumParams, + SourceLocation RAngleLoc); + + /// iterator - Iterates through the template parameters in this list. + typedef Decl** iterator; + + /// const_iterator - Iterates through the template parameters in this list. + typedef Decl* const* const_iterator; + + iterator begin() { return reinterpret_cast<Decl **>(this + 1); } + const_iterator begin() const { + return reinterpret_cast<Decl * const *>(this + 1); + } + iterator end() { return begin() + NumParams; } + const_iterator end() const { return begin() + NumParams; } + + unsigned size() const { return NumParams; } + + const Decl* getParam(unsigned Idx) const { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + + /// \btief 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. + unsigned getMinRequiredArguments() const; + + SourceLocation getTemplateLoc() const { return TemplateLoc; } + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + SourceRange getSourceRange() const { + return SourceRange(TemplateLoc, RAngleLoc); + } +}; + +//===----------------------------------------------------------------------===// +// Kinds of Templates +//===----------------------------------------------------------------------===// + +/// TemplateDecl - The base class of all kinds of template declarations (e.g., +/// class, function, etc.). The TemplateDecl class stores the list of template +/// parameters and a reference to the templated scoped declaration: the +/// underlying AST node. +class TemplateDecl : public NamedDecl { +protected: + // This is probably never used. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0) + { } + + // Construct a template decl with the given name and parameters. + // Used when there is not templated element (tt-params, alias?). + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params) + { } + + // Construct a template decl with name, parameters, and templated element. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), + TemplateParams(Params) { } +public: + ~TemplateDecl(); + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the underlying, templated declaration. + NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast; + } + static bool classof(const TemplateDecl *D) { return true; } + static bool classof(const FunctionTemplateDecl *D) { return true; } + static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classof(const TemplateTemplateParmDecl *D) { return true; } + +protected: + NamedDecl *TemplatedDecl; + TemplateParameterList* TemplateParams; +}; + +/// Declaration of a template function. +class FunctionTemplateDecl : public TemplateDecl { +protected: + FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { } +public: + /// Get the underling function declaration of the template. + FunctionDecl *getTemplatedDecl() const { + return static_cast<FunctionDecl*>(TemplatedDecl); + } + + /// Create a template function node. + static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) + { return D->getKind() == FunctionTemplate; } + static bool classof(const FunctionTemplateDecl *D) + { return true; } +}; + +//===----------------------------------------------------------------------===// +// Kinds of Template Parameters +//===----------------------------------------------------------------------===// + +/// The TemplateParmPosition class defines the position of a template parameter +/// within a template parameter list. Because template parameter can be listed +/// sequentially for out-of-line template members, each template parameter is +/// given a Depth - the nesting of template parameter scopes - and a Position - +/// the occurrence within the parameter list. +/// This class is inheritedly privately by different kinds of template +/// parameters and is not part of the Decl hierarchy. Just a facility. +class TemplateParmPosition +{ +protected: + // FIXME: This should probably never be called, but it's here as + TemplateParmPosition() + : Depth(0), Position(0) + { /* assert(0 && "Cannot create positionless template parameter"); */ } + + TemplateParmPosition(unsigned D, unsigned P) + : Depth(D), Position(P) + { } + + // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for + // position? Maybe? + unsigned Depth; + unsigned Position; + +public: + /// Get the nesting depth of the template parameter. + unsigned getDepth() const { return Depth; } + + /// Get the position of the template parameter within its parameter list. + unsigned getPosition() const { return Position; } +}; + +/// TemplateTypeParmDecl - Declaration of a template type parameter, +/// e.g., "T" in +/// @code +/// template<typename T> class vector; +/// @endcode +class TemplateTypeParmDecl : public TypeDecl { + /// \brief Whether this template type parameter was declaration with + /// the 'typename' keyword. If false, it was declared with the + /// 'class' keyword. + bool Typename : 1; + + /// \brief Whether this template type parameter inherited its + /// default argument. + bool InheritedDefault : 1; + + /// \brief The location of the default argument, if any. + SourceLocation DefaultArgumentLoc; + + /// \brief The default template argument, if any. + QualType DefaultArgument; + + TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + bool Typename, QualType Type) + : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename), + InheritedDefault(false), DefaultArgument() { + TypeForDecl = Type.getTypePtr(); + } + +public: + static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, bool Typename); + + /// \brief Whether this template type parameter was declared with + /// the 'typename' keyword. If not, it was declared with the 'class' + /// keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return !DefaultArgument.isNull(); } + + /// \brief Retrieve the default argument, if any. + QualType getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; } + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { return InheritedDefault; } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc, + bool Inherited) { + DefaultArgument = DefArg; + DefaultArgumentLoc = DefArgLoc; + InheritedDefault = Inherited; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == TemplateTypeParm; + } + static bool classof(const TemplateTypeParmDecl *D) { return true; } +}; + +/// NonTypeTemplateParmDecl - Declares a non-type template parameter, +/// e.g., "Size" in +/// @code +/// template<int Size> class array { }; +/// @endcode +class NonTypeTemplateParmDecl + : public VarDecl, protected TemplateParmPosition { + /// \brief The default template argument, if any. + Expr *DefaultArgument; + + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, QualType T, + SourceLocation TSSL = SourceLocation()) + : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL), + TemplateParmPosition(D, P), DefaultArgument(0) + { } + +public: + static NonTypeTemplateParmDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, QualType T, + SourceLocation TypeSpecStartLoc = SourceLocation()); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::getPosition; + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Set the default argument for this template parameter. + void setDefaultArgument(Expr *DefArg) { + DefaultArgument = DefArg; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == NonTypeTemplateParm; + } + static bool classof(const NonTypeTemplateParmDecl *D) { return true; } +}; + +/// TemplateTemplateParmDecl - Declares a template template parameter, +/// e.g., "T" in +/// @code +/// template <template <typename> class T> class container { }; +/// @endcode +/// A template template parameter is a TemplateDecl because it defines the +/// name of a template and the template parameters allowable for substitution. +class TemplateTemplateParmDecl + : public TemplateDecl, protected TemplateParmPosition { + + /// \brief The default template argument, if any. + Expr *DefaultArgument; + + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, + unsigned D, unsigned P, + IdentifierInfo *Id, TemplateParameterList *Params) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), DefaultArgument(0) + { } + +public: + static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, + TemplateParameterList *Params); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::getPosition; + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Set the default argument for this template parameter. + void setDefaultArgument(Expr *DefArg) { + DefaultArgument = DefArg; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == TemplateTemplateParm; + } + static bool classof(const TemplateTemplateParmDecl *D) { return true; } +}; + +/// \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; + }; + + /// \brief Location of the beginning of this template argument. + SourceLocation StartLoc; + +public: + /// \brief The type of template argument we're storing. + enum ArgKind { + /// The template argument is a type. It's value is stored in the + /// TypeOrValue field. + Type = 0, + /// The template argument is a declaration + Declaration = 1, + /// The template argument is an integral value stored in an llvm::APSInt. + Integral = 2, + /// The template argument is a value- or type-dependent expression + /// stored in an Expr*. + Expression = 3 + } Kind; + + /// \brief Construct an empty, invalid template argument. + TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { } + + /// \brief Construct a template type argument. + TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) { + TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + StartLoc = Loc; + } + + /// \brief Construct a template argument that refers to a + /// declaration, which is either an external declaration or a + /// template declaration. + TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) { + // FIXME: Need to be sure we have the "canonical" declaration! + TypeOrValue = reinterpret_cast<uintptr_t>(D); + StartLoc = Loc; + } + + /// \brief Construct an integral constant template argument. + TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value, + QualType Type) + : Kind(Integral) { + new (Integer.Value) llvm::APSInt(Value); + Integer.Type = Type.getAsOpaquePtr(); + StartLoc = Loc; + } + + /// \brief Construct a template argument that is an expression. + /// + /// This form of template argument only occurs in template argument + /// lists used for dependent types and for expression; it will not + /// occur in a non-dependent, canonical template argument list. + TemplateArgument(Expr *E); + + /// \brief Copy constructor for a template argument. + TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { + if (Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } + else + TypeOrValue = Other.TypeOrValue; + StartLoc = Other.StartLoc; + } + + TemplateArgument& operator=(const TemplateArgument& Other) { + // FIXME: Does not provide the strong guarantee for exception + // safety. + using llvm::APSInt; + + 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(); + + Kind = Other.Kind; + + if (Other.Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else + TypeOrValue = Other.TypeOrValue; + } + StartLoc = Other.StartLoc; + + return *this; + } + + ~TemplateArgument() { + using llvm::APSInt; + + if (Kind == Integral) + getAsIntegral()->~APSInt(); + } + + /// \brief Return the kind of stored template argument. + ArgKind getKind() const { return Kind; } + + /// \brief Retrieve the template argument as a type. + QualType getAsType() const { + if (Kind != Type) + return QualType(); + + return QualType::getFromOpaquePtr( + reinterpret_cast<void*>(TypeOrValue)); + } + + /// \brief Retrieve the template argument as a declaration. + Decl *getAsDecl() const { + if (Kind != Declaration) + return 0; + return reinterpret_cast<Decl *>(TypeOrValue); + } + + /// \brief Retrieve the template argument as an integral value. + llvm::APSInt *getAsIntegral() { + if (Kind != Integral) + return 0; + return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]); + } + + const llvm::APSInt *getAsIntegral() const { + return const_cast<TemplateArgument*>(this)->getAsIntegral(); + } + + /// \brief Retrieve the type of the integral value. + QualType getIntegralType() const { + if (Kind != Integral) + return QualType(); + + return QualType::getFromOpaquePtr(Integer.Type); + } + + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + if (Kind != Expression) + return 0; + + return reinterpret_cast<Expr *>(TypeOrValue); + } + + /// \brief Retrieve the location where the template argument starts. + SourceLocation getLocation() const { return StartLoc; } + + /// \brief Used to insert TemplateArguments into FoldingSets. + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Kind); + switch (Kind) { + case Type: + getAsType().Profile(ID); + break; + + case Declaration: + ID.AddPointer(getAsDecl()); // FIXME: Must be canonical! + break; + + case Integral: + getAsIntegral()->Profile(ID); + getIntegralType().Profile(ID); + break; + + case Expression: + // FIXME: We need a canonical representation of expressions. + ID.AddPointer(getAsExpr()); + break; + } + } +}; + +/// \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 not own the pointer. + llvm::PointerIntPair<TemplateArgument *, 1> Arguments; + + /// \brief The number of template arguments in this template + /// argument list. + unsigned NumArguments; + + +public: + TemplateArgumentList(ASTContext &Context, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + bool CopyArgs); + + ~TemplateArgumentList(); + + /// \brief Retrieve the template argument at a given index. + const TemplateArgument &get(unsigned Idx) const { + assert(Idx < NumArguments && "Invalid template argument index"); + return getFlatArgumentList()[Idx]; + } + + /// \brief Retrieve the template argument at a given index. + TemplateArgument &get(unsigned Idx) { + assert(Idx < NumArguments && "Invalid template argument index"); + return getFlatArgumentList()[Idx]; + } + + /// \brief Retrieve the template argument at a given index. + TemplateArgument &operator[](unsigned Idx) { return get(Idx); } + const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); } + + /// \brief Retrieve the number of template arguments in this + /// template argument list. + unsigned size() const { return NumArguments; } + + /// \brief Retrieve the number of template arguments in the + /// flattened template argument list. + unsigned flat_size() const { return NumArguments; } + + /// \brief Retrieve the flattened template argument list. + TemplateArgument *getFlatArgumentList() { + return Arguments.getPointer(); + } + const TemplateArgument *getFlatArgumentList() const { + return Arguments.getPointer(); + } +}; + +// \brief Describes the kind of template specialization that a +// particular template specialization declaration represents. +enum TemplateSpecializationKind { + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + TSK_Undeclared = 0, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + TSK_ExplicitSpecialization, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + TSK_ImplicitInstantiation, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation request (C++ [temp.explicit]). + TSK_ExplicitInstantiation +}; + +/// \brief Represents a class template specialization, which refers to +/// a class template with a given set of template arguments. +/// +/// Class template specializations represent both explicit +/// specialization of class templates, as in the example below, and +/// implicit instantiations of class templates. +/// +/// \code +/// template<typename T> class array; +/// +/// template<> +/// class array<bool> { }; // class template specialization array<bool> +/// \endcode +class ClassTemplateSpecializationDecl + : public CXXRecordDecl, public llvm::FoldingSetNode { + /// \brief The template that this specialization specializes + ClassTemplateDecl *SpecializedTemplate; + + /// \brief The template arguments used to describe this specialization. + TemplateArgumentList TemplateArgs; + + /// \brief The kind of specialization this declaration refers to. + /// Really a value of type TemplateSpecializationKind. + unsigned SpecializationKind : 2; + +protected: + ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, + DeclContext *DC, SourceLocation L, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + +public: + static ClassTemplateSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + ClassTemplateSpecializationDecl *PrevDecl); + + /// \brief Retrieve the template that this specialization specializes. + ClassTemplateDecl *getSpecializedTemplate() const { + return SpecializedTemplate; + } + + const TemplateArgumentList &getTemplateArgs() const { + return TemplateArgs; + } + + /// \brief Determine the kind of specialization that this + /// declaration represents. + TemplateSpecializationKind getSpecializationKind() const { + return static_cast<TemplateSpecializationKind>(SpecializationKind); + } + + void setSpecializationKind(TemplateSpecializationKind TSK) { + SpecializationKind = TSK; + } + + /// \brief Sets the type of this specialization as it was written by + /// the user. This will be a class template specialization type. + void setTypeAsWritten(QualType T) { + TypeForDecl = T.getTypePtr(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size()); + } + + static void + Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) + TemplateArgs[Arg].Profile(ID); + } + + static bool classof(const Decl *D) { + return D->getKind() == ClassTemplateSpecialization || + D->getKind() == ClassTemplatePartialSpecialization; + } + + static bool classof(const ClassTemplateSpecializationDecl *) { + return true; + } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } +}; + +class ClassTemplatePartialSpecializationDecl + : public ClassTemplateSpecializationDecl +{ + /// \brief The list of template parameters + TemplateParameterList* TemplateParams; + + ClassTemplatePartialSpecializationDecl(ASTContext &Context, + DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) + : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, + DC, L, SpecializedTemplate, TemplateArgs, + NumTemplateArgs), + TemplateParams(Params) { } + +public: + static ClassTemplatePartialSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + ClassTemplatePartialSpecializationDecl *PrevDecl); + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + // FIXME: Add Profile support! + + static bool classof(const Decl *D) { + return D->getKind() == ClassTemplatePartialSpecialization; + } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } +}; + +/// Declaration of a class template. +class ClassTemplateDecl : public TemplateDecl { +protected: + /// \brief Data that is common to all of the declarations of a given + /// class template. + struct Common { + /// \brief The class template specializations for this class + /// template, including explicit specializations and instantiations. + llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; + + /// \brief The class template partial specializations for this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> + PartialSpecializations; + + /// \brief The injected-class-name type for this class template. + QualType InjectedClassNameType; + }; + + /// \brief Previous declaration of this class template. + ClassTemplateDecl *PreviousDeclaration; + + /// \brief Pointer to the data that is common to all of the + /// declarations of this class template. + /// + /// The first declaration of a class template (e.g., the declaration + /// with no "previous declaration") owns this pointer. + Common *CommonPtr; + + ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl, + ClassTemplateDecl *PrevDecl, Common *CommonPtr) + : TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl), + PreviousDeclaration(PrevDecl), CommonPtr(CommonPtr) { } + + ~ClassTemplateDecl(); + +public: + /// Get the underlying class declarations of the template. + CXXRecordDecl *getTemplatedDecl() const { + return static_cast<CXXRecordDecl *>(TemplatedDecl); + } + + /// \brief Retrieve the previous declaration of this template. + ClassTemplateDecl *getPreviousDeclaration() const { + return PreviousDeclaration; + } + + /// Create a class template node. + static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + ClassTemplateDecl *PrevDecl); + + /// \brief Retrieve the set of specializations of this class template. + llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() { + return CommonPtr->Specializations; + } + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & + getPartialSpecializations() { + return CommonPtr->PartialSpecializations; + } + + /// \brief Retrieve the type of the injected-class-name for this + /// class template. + /// + /// The injected-class-name for a class template \c X is \c + /// X<template-args>, where \c template-args is formed from the + /// template arguments that correspond to the template parameters of + /// \c X. For example: + /// + /// \code + /// template<typename T, int N> + /// struct array { + /// typedef array this_type; // "array" is equivalent to "array<T, N>" + /// }; + /// \endcode + QualType getInjectedClassNameType(ASTContext &Context); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) + { return D->getKind() == ClassTemplate; } + static bool classof(const ClassTemplateDecl *D) + { return true; } + + virtual void Destroy(ASTContext& C); +}; + +} /* end of namespace clang */ + +#endif diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h new file mode 100644 index 000000000000..9423c319c3e3 --- /dev/null +++ b/include/clang/AST/DeclVisitor.h @@ -0,0 +1,54 @@ +//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLVISITOR_H +#define LLVM_CLANG_AST_DECLVISITOR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +namespace clang { + +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)-> Visit##NAME(static_cast<CLASS*>(D)) + +/// \brief A simple visitor class that helps create declaration visitors. +template<typename ImplClass, typename RetTy=void> +class DeclVisitor { +public: + RetTy Visit(Decl *D) { + switch (D->getKind()) { + default: assert(false && "Decl that isn't part of DeclNodes.def!"); +#define DECL(Derived, Base) \ + case Decl::Derived: DISPATCH(Derived##Decl, Derived##Decl); +#define ABSTRACT_DECL(Derived, Base) +#include "clang/AST/DeclNodes.def" + } + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. +#define DECL(Derived, Base) \ + RetTy Visit##Derived##Decl(Derived##Decl *D) { DISPATCH(Base, Base); } +#define ABSTRACT_DECL(Derived, Base) DECL(Derived, Base) +#include "clang/AST/DeclNodes.def" + + RetTy VisitDecl(Decl *D) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_DECLVISITOR_H diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h new file mode 100644 index 000000000000..db140999b045 --- /dev/null +++ b/include/clang/AST/DeclarationName.h @@ -0,0 +1,357 @@ +//===-- DeclarationName.h - Representation of declaration names -*- 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 DeclarationName and DeclarationNameTable classes. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H +#define LLVM_CLANG_AST_DECLARATIONNAME_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/AST/Type.h" + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class CXXSpecialName; + class CXXOperatorIdName; + class DeclarationNameExtra; + class IdentifierInfo; + class MultiKeywordSelector; + class UsingDirectiveDecl; + +/// DeclarationName - The name of a declaration. In the common case, +/// this just stores an IdentifierInfo pointer to a normal +/// name. However, it also provides encodings for Objective-C +/// selectors (optimizing zero- and one-argument selectors, which make +/// up 78% percent of all selectors in Cocoa.h) and special C++ names +/// for constructors, destructors, and conversion functions. +class DeclarationName { +public: + /// NameKind - The kind of name this object contains. + enum NameKind { + Identifier, + ObjCZeroArgSelector, + ObjCOneArgSelector, + ObjCMultiArgSelector, + CXXConstructorName, + CXXDestructorName, + CXXConversionFunctionName, + CXXOperatorName, + CXXUsingDirective + }; + +private: + /// StoredNameKind - The kind of name that is actually stored in the + /// upper bits of the Ptr field. This is only used internally. + enum StoredNameKind { + StoredIdentifier = 0, + StoredObjCZeroArgSelector, + StoredObjCOneArgSelector, + StoredDeclarationNameExtra, + PtrMask = 0x03 + }; + + /// Ptr - The lowest two bits are used to express what kind of name + /// we're actually storing, using the values of NameKind. Depending + /// on the kind of name this is, the upper bits of Ptr may have one + /// of several different meanings: + /// + /// StoredIdentifier - The name is a normal identifier, and Ptr is + /// a normal IdentifierInfo pointer. + /// + /// StoredObjCZeroArgSelector - The name is an Objective-C + /// selector with zero arguments, and Ptr is an IdentifierInfo + /// pointer pointing to the selector name. + /// + /// StoredObjCOneArgSelector - The name is an Objective-C selector + /// with one argument, and Ptr is an IdentifierInfo pointer + /// pointing to the selector name. + /// + /// StoredDeclarationNameExtra - Ptr is actually a pointer to a + /// DeclarationNameExtra structure, whose first value will tell us + /// whether this is an Objective-C selector, C++ operator-id name, + /// or special C++ name. + uintptr_t Ptr; + + /// getStoredNameKind - Return the kind of object that is stored in + /// Ptr. + StoredNameKind getStoredNameKind() const { + return static_cast<StoredNameKind>(Ptr & PtrMask); + } + + /// getExtra - Get the "extra" information associated with this + /// multi-argument selector or C++ special name. + DeclarationNameExtra *getExtra() const { + assert(getStoredNameKind() == StoredDeclarationNameExtra && + "Declaration name does not store an Extra structure"); + return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask); + } + + /// getAsCXXSpecialName - If the stored pointer is actually a + /// CXXSpecialName, returns a pointer to it. Otherwise, returns + /// a NULL pointer. + CXXSpecialName *getAsCXXSpecialName() const { + if (getNameKind() >= CXXConstructorName && + getNameKind() <= CXXConversionFunctionName) + return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask); + return 0; + } + + /// getAsCXXOperatorIdName + CXXOperatorIdName *getAsCXXOperatorIdName() const { + if (getNameKind() == CXXOperatorName) + return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask); + return 0; + } + + // Construct a declaration name from the name of a C++ constructor, + // destructor, or conversion function. + DeclarationName(CXXSpecialName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName"); + Ptr |= StoredDeclarationNameExtra; + } + + // Construct a declaration name from the name of a C++ overloaded + // operator. + DeclarationName(CXXOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + + /// Construct a declaration name from a raw pointer. + DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } + + friend class DeclarationNameTable; + friend class NamedDecl; + + /// getFETokenInfoAsVoid - Retrieves the front end-specified pointer + /// for this name as a void pointer. + void *getFETokenInfoAsVoid() const; + +public: + /// DeclarationName - Used to create an empty selector. + DeclarationName() : Ptr(0) { } + + // Construct a declaration name from an IdentifierInfo *. + DeclarationName(const IdentifierInfo *II) + : Ptr(reinterpret_cast<uintptr_t>(II)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + } + + // Construct a declaration name from an Objective-C selector. + DeclarationName(Selector Sel); + + /// getUsingDirectiveName - Return name for all using-directives. + static DeclarationName getUsingDirectiveName(); + + // operator bool() - Evaluates true when this declaration name is + // non-empty. + operator bool() const { + return ((Ptr & PtrMask) != 0) || + (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); + } + + /// Predicate functions for querying what type of name this is. + bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } + bool isObjCZeroArgSelector() const { + return getStoredNameKind() == StoredObjCZeroArgSelector; + } + bool isObjCOneArgSelector() const { + return getStoredNameKind() == StoredObjCOneArgSelector; + } + + /// getNameKind - Determine what kind of name this is. + NameKind getNameKind() const; + + + /// getName - Retrieve the human-readable string for this name. + std::string getAsString() const; + + /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in + /// this declaration name, or NULL if this declaration name isn't a + /// simple identifier. + IdentifierInfo *getAsIdentifierInfo() const { + if (isIdentifier()) + return reinterpret_cast<IdentifierInfo *>(Ptr); + return 0; + } + + /// getAsOpaqueInteger - Get the representation of this declaration + /// name as an opaque integer. + uintptr_t getAsOpaqueInteger() const { return Ptr; } + + /// getAsOpaquePtr - Get the representation of this declaration name as + /// an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); } + + static DeclarationName getFromOpaqueInteger(uintptr_t P) { + DeclarationName N; + N.Ptr = P; + return N; + } + + /// getCXXNameType - If this name is one of the C++ names (of a + /// constructor, destructor, or conversion function), return the + /// type associated with that name. + QualType getCXXNameType() const; + + /// getCXXOverloadedOperator - If this name is the name of an + /// overloadable operator in C++ (e.g., @c operator+), retrieve the + /// kind of overloaded operator. + OverloadedOperatorKind getCXXOverloadedOperator() const; + + /// getObjCSelector - Get the Objective-C selector stored in this + /// declaration name. + Selector getObjCSelector() const; + + /// getFETokenInfo/setFETokenInfo - The language front-end is + /// allowed to associate arbitrary metadata with some kinds of + /// declaration names, including normal identifiers and C++ + /// constructors, destructors, and conversion functions. + template<typename T> + T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); } + + void setFETokenInfo(void *T); + + /// operator== - Determine whether the specified names are identical.. + friend bool operator==(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr == RHS.Ptr; + } + + /// operator!= - Determine whether the specified names are different. + friend bool operator!=(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr != RHS.Ptr; + } + + static DeclarationName getEmptyMarker() { + return DeclarationName(uintptr_t(-1)); + } + + static DeclarationName getTombstoneMarker() { + return DeclarationName(uintptr_t(-2)); + } +}; + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +bool operator<(DeclarationName LHS, DeclarationName RHS); + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>(DeclarationName LHS, DeclarationName RHS) { + return RHS < LHS; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator<=(DeclarationName LHS, DeclarationName RHS) { + return !(RHS < LHS); +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { + return !(LHS < RHS); +} + +/// DeclarationNameTable - Used to store and retrieve DeclarationName +/// instances for the various kinds of declaration names, e.g., normal +/// identifiers, C++ constructor names, etc. This class contains +/// uniqued versions of each of the C++ special names, which can be +/// retrieved using its member functions (e.g., +/// getCXXConstructorName). +class DeclarationNameTable { + void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * + CXXOperatorIdName *CXXOperatorNames; // Operator names + + DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE + DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE + +public: + DeclarationNameTable(); + ~DeclarationNameTable(); + + /// getIdentifier - Create a declaration name that is a simple + /// identifier. + DeclarationName getIdentifier(IdentifierInfo *ID) { + return DeclarationName(ID); + } + + /// getCXXConstructorName - Returns the name of a C++ constructor + /// for the given Type. + DeclarationName getCXXConstructorName(QualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty); + } + + /// getCXXDestructorName - Returns the name of a C++ destructor + /// for the given Type. + DeclarationName getCXXDestructorName(QualType Ty) { + return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty); + } + + /// getCXXConversionFunctionName - Returns the name of a C++ + /// conversion function for the given Type. + DeclarationName getCXXConversionFunctionName(QualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty); + } + + /// getCXXSpecialName - Returns a declaration name for special kind + /// of C++ name, e.g., for a constructor, destructor, or conversion + /// function. + DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, + QualType Ty); + + /// getCXXOperatorName - Get the name of the overloadable C++ + /// operator corresponding to Op. + DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); +}; + +/// Insertion operator for diagnostics. This allows sending DeclarationName's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + DeclarationName N) { + DB.AddTaggedVal(N.getAsOpaqueInteger(), + Diagnostic::ak_declarationname); + return DB; +} + + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that DeclarationNames can be used as keys +/// in DenseMap and DenseSets. +template<> +struct DenseMapInfo<clang::DeclarationName> { + static inline clang::DeclarationName getEmptyKey() { + return clang::DeclarationName::getEmptyMarker(); + } + + static inline clang::DeclarationName getTombstoneKey() { + return clang::DeclarationName::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::DeclarationName); + + static inline bool + isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) { + return LHS == RHS; + } + + static inline bool isPod() { return true; } +}; + +} // end namespace llvm + +#endif diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h new file mode 100644 index 000000000000..98de5f9d382e --- /dev/null +++ b/include/clang/AST/Expr.h @@ -0,0 +1,2500 @@ +//===--- Expr.h - Classes for representing 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 the Expr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPR_H +#define LLVM_CLANG_AST_EXPR_H + +#include "clang/AST/APValue.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallVector.h" +#include <vector> + +namespace clang { + class ASTContext; + class APValue; + class Decl; + class IdentifierInfo; + class ParmVarDecl; + class NamedDecl; + class ValueDecl; + class BlockDecl; + class CXXOperatorCallExpr; + class CXXMemberCallExpr; + +/// Expr - This represents one expression. Note that Expr's are subclasses of +/// Stmt. This allows an expression to be transparently used any place a Stmt +/// is required. +/// +class Expr : public Stmt { + QualType TR; + +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; + + // FIXME: Eventually, this constructor should go away and we should + // require every subclass to provide type/value-dependence + // information. + Expr(StmtClass SC, QualType T) + : Stmt(SC), TypeDependent(false), ValueDependent(false) { + setType(T); + } + + Expr(StmtClass SC, QualType T, bool TD, bool VD) + : Stmt(SC), TypeDependent(TD), ValueDependent(VD) { + setType(T); + } + + /// \brief Construct an empty expression. + explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } + +public: + QualType getType() const { return TR; } + void setType(QualType t) { + // In C++, the type of an expression is always adjusted so that it + // will not have reference type an expression will never have + // reference type (C++ [expr]p6). Use + // QualType::getNonReferenceType() to retrieve the non-reference + // type. Additionally, inspect Expr::isLvalue to determine whether + // an expression that is adjusted in this manner should be + // considered an lvalue. + assert((TR.isNull() || !TR->isReferenceType()) && + "Expressions can't have reference type"); + + TR = t; + } + + /// isValueDependent - Determines whether this expression is + /// value-dependent (C++ [temp.dep.constexpr]). For example, the + /// array bound of "Chars" in the following example is + /// value-dependent. + /// @code + /// template<int Size, char (&Chars)[Size]> struct meta_string; + /// @endcode + bool isValueDependent() const { return ValueDependent; } + + /// \brief Set whether this expression is value-dependent or not. + void setValueDependent(bool VD) { ValueDependent = VD; } + + /// isTypeDependent - Determines whether this expression is + /// type-dependent (C++ [temp.dep.expr]), which means that its type + /// could change from one template instantiation to the next. For + /// example, the expressions "x" and "x + y" are type-dependent in + /// the following code, but "y" is not type-dependent: + /// @code + /// template<typename T> + /// void add(T x, int y) { + /// x + y; + /// } + /// @endcode + bool isTypeDependent() const { return TypeDependent; } + + /// \brief Set whether this expression is type-dependent or not. + void setTypeDependent(bool TD) { TypeDependent = TD; } + + /// 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; + + /// getExprLoc - Return the preferred location for the arrow when diagnosing + /// a problem with a generic expression. + virtual SourceLocation getExprLoc() const { return getLocStart(); } + + /// isUnusedResultAWarning - Return true if this immediate expression should + /// be warned about if the result is unused. If so, fill in Loc and Ranges + /// with location to warn on and the source range[s] to report with the + /// warning. + bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, + SourceRange &R2) const; + + /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or + /// incomplete type other than void. Nonarray expressions that can be lvalues: + /// - name, where name must be a variable + /// - 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++] + /// + enum isLvalueResult { + LV_Valid, + LV_NotObjectType, + LV_IncompleteVoidType, + LV_DuplicateVectorComponents, + LV_InvalidExpression, + LV_MemberFunction + }; + isLvalueResult isLvalue(ASTContext &Ctx) const; + + // Same as above, but excluding checks for non-object and void types in C + isLvalueResult isLvalueInternal(ASTContext &Ctx) const; + + /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, + /// does not have an incomplete type, does not have a const-qualified type, + /// and if it is a structure or union, does not have any member (including, + /// recursively, any member or element of all contained aggregates or unions) + /// with a const-qualified type. + /// + /// \param Loc [in] [out] - A source location which *may* be filled + /// in with the location of the expression making this a + /// non-modifiable lvalue, if specified. + enum isModifiableLvalueResult { + MLV_Valid, + MLV_NotObjectType, + MLV_IncompleteVoidType, + MLV_DuplicateVectorComponents, + MLV_InvalidExpression, + MLV_LValueCast, // Specialized form of MLV_InvalidExpression. + MLV_IncompleteType, + MLV_ConstQualified, + MLV_ArrayType, + MLV_NotBlockQualified, + MLV_ReadonlyProperty, + MLV_NoSetterProperty, + MLV_MemberFunction + }; + isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, + SourceLocation *Loc = 0) const; + + /// \brief If this expression refers to a bit-field, retrieve the + /// declaration of that bit-field. + FieldDecl *getBitField(); + + const FieldDecl *getBitField() const { + return const_cast<Expr*>(this)->getBitField(); + } + + /// isIntegerConstantExpr - Return true if this expression is a valid integer + /// constant expression, and, if so, return its value in Result. If not a + /// valid i-c-e, return false and fill in Loc (if specified) with the location + /// of the invalid expression. + bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc = 0, + bool isEvaluated = true) const; + bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const { + llvm::APSInt X; + return isIntegerConstantExpr(X, Ctx, Loc); + } + /// isConstantInitializer - Returns true if this expression is a constant + /// initializer, which can be emitted at compile-time. + bool isConstantInitializer(ASTContext &Ctx) const; + + /// EvalResult is a struct with detailed info about an evaluated expression. + struct EvalResult { + /// Val - This is the value the expression can be folded to. + APValue Val; + + /// HasSideEffects - Whether the evaluated expression has side effects. + /// For example, (f() && 0) can be folded, but it still has side effects. + bool HasSideEffects; + + /// Diag - If the expression is unfoldable, then Diag contains a note + /// diagnostic indicating why it's not foldable. DiagLoc indicates a caret + /// position for the error, and DiagExpr is the expression that caused + /// the error. + /// If the expression is foldable, but not an integer constant expression, + /// Diag contains a note diagnostic that describes why it isn't an integer + /// constant expression. If the expression *is* an integer constant + /// expression, then Diag will be zero. + unsigned Diag; + const Expr *DiagExpr; + SourceLocation DiagLoc; + + EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {} + }; + + /// Evaluate - Return true if this is a constant which we can fold using + /// 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; + + /// isEvaluatable - Call Evaluate to see if this expression can be constant + /// folded, but discard the result. + bool isEvaluatable(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; + + /// EvaluateAsLValue - Evaluate an expression to see if it's a valid LValue. + bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const; + + /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an + /// integer constant expression with the value zero, or if this is one that is + /// cast to void*. + bool isNullPointerConstant(ASTContext &Ctx) const; + + /// hasGlobalStorage - Return true if this expression has static storage + /// duration. This means that the address of this expression is a link-time + /// constant. + bool hasGlobalStorage() const; + + /// isOBJCGCCandidate - Return true if this expression may be used in a read/ + /// write barrier. + bool isOBJCGCCandidate(ASTContext &Ctx) const; + + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return + /// its subexpression. If that subexpression is also a ParenExpr, + /// then this method recursively returns its subexpression, and so forth. + /// Otherwise, the method returns the current Expr. + Expr* IgnoreParens(); + + /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr + /// or CastExprs, returning their operand. + Expr *IgnoreParenCasts(); + + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the + /// value (including ptr->int casts of the same size). Strip off any + /// ParenExpr or CastExprs, returning their operand. + Expr *IgnoreParenNoopCasts(ASTContext &Ctx); + + const Expr* IgnoreParens() const { + return const_cast<Expr*>(this)->IgnoreParens(); + } + const Expr *IgnoreParenCasts() const { + return const_cast<Expr*>(this)->IgnoreParenCasts(); + } + const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const { + return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx); + } + + static bool hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs); + static bool hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs); + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstExprConstant && + T->getStmtClass() <= lastExprConstant; + } + static bool classof(const Expr *) { return true; } +}; + + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +/// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function, +/// enum, etc. +class DeclRefExpr : public Expr { + NamedDecl *D; + SourceLocation Loc; + +protected: + // FIXME: Eventually, this constructor will go away and all subclasses + // will have to provide the type- and value-dependent flags. + DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : + Expr(SC, t), D(d), Loc(l) {} + + DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD, + bool VD) : + Expr(SC, t, TD, VD), D(d), Loc(l) {} + +public: + // FIXME: Eventually, this constructor will go away and all clients + // will have to provide the type- and value-dependent flags. + DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : + Expr(DeclRefExprClass, t), D(d), Loc(l) {} + + DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : + Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {} + + /// \brief Construct an empty declaration reference expression. + explicit DeclRefExpr(EmptyShell Empty) + : Expr(DeclRefExprClass, Empty) { } + + NamedDecl *getDecl() { return D; } + const NamedDecl *getDecl() const { return D; } + void setDecl(NamedDecl *NewD) { D = NewD; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclRefExprClass || + T->getStmtClass() == CXXConditionDeclExprClass || + T->getStmtClass() == QualifiedDeclRefExprClass; + } + static bool classof(const DeclRefExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__. +class PredefinedExpr : public Expr { +public: + enum IdentType { + Func, + Function, + PrettyFunction + }; + +private: + SourceLocation Loc; + IdentType Type; +public: + PredefinedExpr(SourceLocation l, QualType type, IdentType IT) + : Expr(PredefinedExprClass, type), Loc(l), Type(IT) {} + + /// \brief Construct an empty predefined expression. + explicit PredefinedExpr(EmptyShell Empty) + : Expr(PredefinedExprClass, Empty) { } + + PredefinedExpr* Clone(ASTContext &C) const; + + IdentType getIdentType() const { return Type; } + void setIdentType(IdentType IT) { Type = IT; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + // FIXME: The logic for computing the value of a predefined expr should go + // into a method here that takes the inner-most code decl (a block, function + // or objc method) that the expr lives in. This would allow sema and codegen + // to be consistent for things like sizeof(__func__) etc. + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; + } + static bool classof(const PredefinedExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class IntegerLiteral : public Expr { + llvm::APInt Value; + SourceLocation Loc; +public: + // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, + // or UnsignedLongLongTy + IntegerLiteral(const llvm::APInt &V, QualType type, SourceLocation l) + : Expr(IntegerLiteralClass, type), Value(V), Loc(l) { + assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); + } + + /// \brief Construct an empty integer literal. + explicit IntegerLiteral(EmptyShell Empty) + : Expr(IntegerLiteralClass, Empty) { } + + IntegerLiteral* Clone(ASTContext &C) const; + + const llvm::APInt &getValue() const { return Value; } + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + /// \brief Retrieve the location of the literal. + SourceLocation getLocation() const { return Loc; } + + void setValue(const llvm::APInt &Val) { Value = Val; } + void setLocation(SourceLocation Location) { Loc = Location; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IntegerLiteralClass; + } + static bool classof(const IntegerLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class CharacterLiteral : public Expr { + unsigned Value; + SourceLocation Loc; + bool IsWide; +public: + // type should be IntTy + CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l) + : Expr(CharacterLiteralClass, type), Value(value), Loc(l), IsWide(iswide) { + } + + /// \brief Construct an empty character literal. + CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } + + CharacterLiteral* Clone(ASTContext &C) const; + + SourceLocation getLoc() const { return Loc; } + bool isWide() const { return IsWide; } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + unsigned getValue() const { return Value; } + + void setLocation(SourceLocation Location) { Loc = Location; } + void setWide(bool W) { IsWide = W; } + void setValue(unsigned Val) { Value = Val; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CharacterLiteralClass; + } + static bool classof(const CharacterLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class FloatingLiteral : public Expr { + llvm::APFloat Value; + bool IsExact : 1; + SourceLocation Loc; +public: + FloatingLiteral(const llvm::APFloat &V, bool* isexact, + QualType Type, SourceLocation L) + : Expr(FloatingLiteralClass, Type), Value(V), IsExact(*isexact), Loc(L) {} + + /// \brief Construct an empty floating-point literal. + explicit FloatingLiteral(EmptyShell Empty) + : Expr(FloatingLiteralClass, Empty), Value(0.0) { } + + FloatingLiteral* Clone(ASTContext &C) const; + + const llvm::APFloat &getValue() const { return Value; } + void setValue(const llvm::APFloat &Val) { Value = Val; } + + bool isExact() const { return IsExact; } + void setExact(bool E) { IsExact = E; } + + /// getValueAsApproximateDouble - This returns the value as an inaccurate + /// double. Note that this may cause loss of precision, but is useful for + /// debugging dumps, etc. + double getValueAsApproximateDouble() const; + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + // FIXME: The logic for computing the value of a predefined expr should go + // into a method here that takes the inner-most code decl (a block, function + // or objc method) that the expr lives in. This would allow sema and codegen + // to be consistent for things like sizeof(__func__) etc. + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FloatingLiteralClass; + } + static bool classof(const FloatingLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ImaginaryLiteral - We support imaginary integer and floating point literals, +/// like "1.0i". We represent these as a wrapper around FloatingLiteral and +/// IntegerLiteral classes. Instances of this class always have a Complex type +/// whose element type matches the subexpression. +/// +class ImaginaryLiteral : public Expr { + Stmt *Val; +public: + ImaginaryLiteral(Expr *val, QualType Ty) + : Expr(ImaginaryLiteralClass, Ty), Val(val) {} + + /// \brief Build an empty imaginary literal. + explicit ImaginaryLiteral(EmptyShell Empty) + : Expr(ImaginaryLiteralClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + ImaginaryLiteral* Clone(ASTContext &C) const; + + virtual SourceRange getSourceRange() const { return Val->getSourceRange(); } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImaginaryLiteralClass; + } + static bool classof(const ImaginaryLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// StringLiteral - This represents a string literal expression, e.g. "foo" +/// or L"bar" (wide strings). The actual string is returned by getStrData() +/// is NOT null-terminated, and the length of the string is determined by +/// calling getByteLength(). The C type for a string is always a +/// ConstantArrayType. In C++, the char type is const qualified, in C it is +/// not. +/// +/// Note that strings in C can be formed by concatenation of multiple string +/// literal pptokens in translation phase #6. This keeps track of the locations +/// of each of these pieces. +/// +/// Strings in C can also be truncated and extended by assigning into arrays, +/// e.g. with constructs like: +/// char X[2] = "foobar"; +/// In this case, getByteLength() will return 6, but the string literal will +/// have type "char[2]". +class StringLiteral : public Expr { + const char *StrData; + unsigned ByteLength; + bool IsWide; + unsigned NumConcatenated; + SourceLocation TokLocs[1]; + + StringLiteral(QualType Ty) : Expr(StringLiteralClass, Ty) {} +public: + /// This is the "fully general" constructor that allows representation of + /// strings formed from multiple concatenated tokens. + static StringLiteral *Create(ASTContext &C, const char *StrData, + unsigned ByteLength, bool Wide, QualType Ty, + const SourceLocation *Loc, unsigned NumStrs); + + /// Simple constructor for string literals made from one token. + static StringLiteral *Create(ASTContext &C, const char *StrData, + unsigned ByteLength, + bool Wide, QualType Ty, SourceLocation Loc) { + return Create(C, StrData, ByteLength, Wide, Ty, &Loc, 1); + } + + /// \brief Construct an empty string literal. + static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs); + + StringLiteral* Clone(ASTContext &C) const; + void Destroy(ASTContext &C); + + const char *getStrData() const { return StrData; } + unsigned getByteLength() const { return ByteLength; } + + /// \brief Sets the string data to the given string data. + void setStrData(ASTContext &C, const char *Str, unsigned Len); + + bool isWide() const { return IsWide; } + void setWide(bool W) { IsWide = W; } + + bool containsNonAsciiOrNull() const { + for (unsigned i = 0; i < getByteLength(); ++i) + if (!isascii(getStrData()[i]) || !getStrData()[i]) + return true; + return false; + } + /// getNumConcatenated - Get the number of string literal tokens that were + /// concatenated in translation phase #6 to form this string literal. + unsigned getNumConcatenated() const { return NumConcatenated; } + + SourceLocation getStrTokenLoc(unsigned TokNum) const { + assert(TokNum < NumConcatenated && "Invalid tok number"); + return TokLocs[TokNum]; + } + void setStrTokenLoc(unsigned TokNum, SourceLocation L) { + assert(TokNum < NumConcatenated && "Invalid tok number"); + TokLocs[TokNum] = L; + } + + typedef const SourceLocation *tokloc_iterator; + tokloc_iterator tokloc_begin() const { return TokLocs; } + tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == StringLiteralClass; + } + static bool classof(const StringLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This +/// AST node is only formed if full location information is requested. +class ParenExpr : public Expr { + SourceLocation L, R; + Stmt *Val; +public: + ParenExpr(SourceLocation l, SourceLocation r, Expr *val) + : Expr(ParenExprClass, val->getType(), + val->isTypeDependent(), val->isValueDependent()), + L(l), R(r), Val(val) {} + + /// \brief Construct an empty parenthesized expression. + explicit ParenExpr(EmptyShell Empty) + : Expr(ParenExprClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + virtual SourceRange getSourceRange() const { return SourceRange(L, R); } + + /// \brief Get the location of the left parentheses '('. + SourceLocation getLParen() const { return L; } + void setLParen(SourceLocation Loc) { L = Loc; } + + /// \brief Get the location of the right parentheses ')'. + SourceLocation getRParen() const { return R; } + void setRParen(SourceLocation Loc) { R = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenExprClass; + } + static bool classof(const ParenExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// UnaryOperator - This represents the unary-expression's (except sizeof and +/// alignof), the postinc/postdec operators from postfix-expression, and various +/// extensions. +/// +/// Notes on various nodes: +/// +/// Real/Imag - These return the real/imag part of a complex operand. If +/// applied to a non-complex value, the former returns its operand and the +/// later returns zero in the type of the operand. +/// +/// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose +/// subexpression is a compound literal with the various MemberExpr and +/// ArraySubscriptExpr's applied to it. +/// +class UnaryOperator : public Expr { +public: + // Note that additions to this should also update the StmtVisitor class. + enum Opcode { + PostInc, PostDec, // [C99 6.5.2.4] Postfix increment and decrement operators + PreInc, PreDec, // [C99 6.5.3.1] Prefix increment and decrement operators. + AddrOf, Deref, // [C99 6.5.3.2] Address and indirection operators. + Plus, Minus, // [C99 6.5.3.3] Unary arithmetic operators. + Not, LNot, // [C99 6.5.3.3] Unary arithmetic operators. + Real, Imag, // "__real expr"/"__imag expr" Extension. + Extension, // __extension__ marker. + OffsetOf // __builtin_offsetof + }; +private: + Stmt *Val; + Opcode Opc; + SourceLocation Loc; +public: + + UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l) + : Expr(UnaryOperatorClass, type, + input->isTypeDependent() && opc != OffsetOf, + input->isValueDependent()), + Val(input), Opc(opc), Loc(l) {} + + /// \brief Build an empty unary operator. + explicit UnaryOperator(EmptyShell Empty) + : Expr(UnaryOperatorClass, Empty), Opc(AddrOf) { } + + Opcode getOpcode() const { return Opc; } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getSubExpr() const { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return Loc; } + void setOperatorLoc(SourceLocation L) { Loc = L; } + + /// isPostfix - Return true if this is a postfix operation, like x++. + static bool isPostfix(Opcode Op) { + return Op == PostInc || Op == PostDec; + } + + /// isPostfix - Return true if this is a prefix operation, like --x. + static bool isPrefix(Opcode Op) { + return Op == PreInc || Op == PreDec; + } + + bool isPrefix() const { return isPrefix(Opc); } + bool isPostfix() const { return isPostfix(Opc); } + bool isIncrementOp() const {return Opc==PreInc || Opc==PostInc; } + bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; } + bool isOffsetOfOp() const { return Opc == OffsetOf; } + static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "sizeof" or "[pre]++" + static const char *getOpcodeStr(Opcode Op); + + /// \brief Retrieve the unary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given unary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + virtual SourceRange getSourceRange() const { + if (isPostfix()) + return SourceRange(Val->getLocStart(), Loc); + else + return SourceRange(Loc, Val->getLocEnd()); + } + virtual SourceLocation getExprLoc() const { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryOperatorClass; + } + static bool classof(const UnaryOperator *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of +/// types and expressions. +class SizeOfAlignOfExpr : public Expr { + bool isSizeof : 1; // true if sizeof, false if alignof. + bool isType : 1; // true if operand is a type, false if an expression + union { + void *Ty; + Stmt *Ex; + } Argument; + SourceLocation OpLoc, RParenLoc; +public: + SizeOfAlignOfExpr(bool issizeof, QualType T, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(SizeOfAlignOfExprClass, resultType, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + T->isDependentType()), + isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) { + Argument.Ty = T.getAsOpaquePtr(); + } + + SizeOfAlignOfExpr(bool issizeof, Expr *E, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(SizeOfAlignOfExprClass, resultType, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + E->isTypeDependent()), + isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) { + Argument.Ex = E; + } + + /// \brief Construct an empty sizeof/alignof expression. + explicit SizeOfAlignOfExpr(EmptyShell Empty) + : Expr(SizeOfAlignOfExprClass, Empty) { } + + virtual void Destroy(ASTContext& C); + + bool isSizeOf() const { return isSizeof; } + void setSizeof(bool S) { isSizeof = S; } + + bool isArgumentType() const { return isType; } + QualType getArgumentType() const { + assert(isArgumentType() && "calling getArgumentType() when arg is expr"); + return QualType::getFromOpaquePtr(Argument.Ty); + } + Expr *getArgumentExpr() { + assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); + return static_cast<Expr*>(Argument.Ex); + } + const Expr *getArgumentExpr() const { + return const_cast<SizeOfAlignOfExpr*>(this)->getArgumentExpr(); + } + + void setArgument(Expr *E) { Argument.Ex = E; isType = false; } + void setArgument(QualType T) { + Argument.Ty = T.getAsOpaquePtr(); + isType = true; + } + + /// Gets the argument type, or the type of the argument expression, whichever + /// is appropriate. + QualType getTypeOfArgument() const { + return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType(); + } + + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(OpLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SizeOfAlignOfExprClass; + } + static bool classof(const SizeOfAlignOfExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. +class ArraySubscriptExpr : public Expr { + enum { LHS, RHS, END_EXPR=2 }; + Stmt* SubExprs[END_EXPR]; + SourceLocation RBracketLoc; +public: + ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, + SourceLocation rbracketloc) + : Expr(ArraySubscriptExprClass, t, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent()), + RBracketLoc(rbracketloc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Create an empty array subscript expression. + explicit ArraySubscriptExpr(EmptyShell Shell) + : Expr(ArraySubscriptExprClass, Shell) { } + + /// An array access can be written A[4] or 4[A] (both are equivalent). + /// - getBase() and getIdx() always present the normalized view: A[4]. + /// In this case getBase() returns "A" and getIdx() returns "4". + /// - getLHS() and getRHS() present the syntactic view. e.g. for + /// 4[A] getLHS() returns "4". + /// Note: Because vector element access is also written A[4] we must + /// predicate the format conversion in getBase and getIdx only on the + /// the type of the RHS, as it is possible for the LHS to be a vector of + /// integer type + Expr *getLHS() { return cast<Expr>(SubExprs[LHS]); } + const Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + + Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); } + const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + Expr *getBase() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + const Expr *getBase() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + Expr *getIdx() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + const Expr *getIdx() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(getLHS()->getLocStart(), RBracketLoc); + } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + virtual SourceLocation getExprLoc() const { return getBase()->getExprLoc(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArraySubscriptExprClass; + } + static bool classof(const ArraySubscriptExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). +/// CallExpr itself represents a normal function call, e.g., "f(x, 2)", +/// while its subclasses may represent alternative syntax that (semantically) +/// results in a function call. For example, CXXOperatorCallExpr is +/// a subclass for overloaded operator calls that use operator syntax, e.g., +/// "str1 + str2" to resolve to a function call. +class CallExpr : public Expr { + enum { FN=0, ARGS_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); + +public: + CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t, + SourceLocation rparenloc); + + /// \brief Build an empty call expression. + CallExpr(ASTContext &C, EmptyShell Empty); + + ~CallExpr() {} + + void Destroy(ASTContext& C); + + const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } + Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } + void setCallee(Expr *F) { SubExprs[FN] = F; } + + /// getNumArgs - Return the number of actual arguments to this call. + /// + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+ARGS_START]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+ARGS_START]); + } + + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + SubExprs[Arg+ARGS_START] = ArgExpr; + } + + /// setNumArgs - This changes the number of arguments present in this call. + /// Any orphaned expressions are deleted by this, and any new operands are set + /// to null. + void setNumArgs(ASTContext& C, unsigned NumArgs); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return SubExprs+ARGS_START; } + arg_iterator arg_end() { return SubExprs+ARGS_START+getNumArgs(); } + const_arg_iterator arg_begin() const { return SubExprs+ARGS_START; } + const_arg_iterator arg_end() const { return SubExprs+ARGS_START+getNumArgs();} + + /// getNumCommas - Return the number of commas that must have been present in + /// this function call. + unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; } + + /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If + /// not, return 0. + unsigned isBuiltinCall(ASTContext &Context) const; + + /// getCallReturnType - Get the return type of the call expr. This is not + /// always the type of the expr itself, if the return type is a reference + /// type. + QualType getCallReturnType() const; + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(getCallee()->getLocStart(), RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CallExprClass || + T->getStmtClass() == CXXOperatorCallExprClass || + T->getStmtClass() == CXXMemberCallExprClass; + } + static bool classof(const CallExpr *) { return true; } + static bool classof(const CXXOperatorCallExpr *) { return true; } + static bool classof(const CXXMemberCallExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. +/// +class MemberExpr : public Expr { + /// Base - the expression for the base pointer or structure references. In + /// X.F, this is "X". + Stmt *Base; + + /// MemberDecl - This is the decl being referenced by the field/member name. + /// In X.F, this is the decl referenced by F. + NamedDecl *MemberDecl; + + /// MemberLoc - This is the location of the member name. + SourceLocation MemberLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow; +public: + MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, + QualType ty) + : Expr(MemberExprClass, ty, + base->isTypeDependent(), base->isValueDependent()), + Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {} + + /// \brief Build an empty member reference expression. + explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Retrieve the member declaration to which this expression refers. + /// + /// The returned declaration will either be a FieldDecl or (in C++) + /// a CXXMethodDecl. + NamedDecl *getMemberDecl() const { return MemberDecl; } + void setMemberDecl(NamedDecl *D) { MemberDecl = D; } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + virtual SourceRange getSourceRange() const { + // If we have an implicit base (like a C++ implicit this), + // make sure not to return its location + SourceLocation BaseLoc = getBase()->getLocStart(); + if (BaseLoc.isInvalid()) + return SourceRange(MemberLoc, MemberLoc); + return SourceRange(BaseLoc, MemberLoc); + } + + virtual SourceLocation getExprLoc() const { return MemberLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MemberExprClass; + } + static bool classof(const MemberExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CompoundLiteralExpr - [C99 6.5.2.5] +/// +class CompoundLiteralExpr : public Expr { + /// LParenLoc - If non-null, this is the location of the left paren in a + /// compound literal like "(int){4}". This can be null if this is a + /// synthesized compound expression. + SourceLocation LParenLoc; + Stmt *Init; + bool FileScope; +public: + CompoundLiteralExpr(SourceLocation lparenloc, QualType ty, Expr *init, + bool fileScope) + : Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init), + FileScope(fileScope) {} + + /// \brief Construct an empty compound literal. + explicit CompoundLiteralExpr(EmptyShell Empty) + : Expr(CompoundLiteralExprClass, Empty) { } + + const Expr *getInitializer() const { return cast<Expr>(Init); } + Expr *getInitializer() { return cast<Expr>(Init); } + void setInitializer(Expr *E) { Init = E; } + + bool isFileScope() const { return FileScope; } + void setFileScope(bool FS) { FileScope = FS; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + virtual SourceRange getSourceRange() const { + // FIXME: Init should never be null. + if (!Init) + return SourceRange(); + if (LParenLoc.isInvalid()) + return Init->getSourceRange(); + return SourceRange(LParenLoc, Init->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundLiteralExprClass; + } + static bool classof(const CompoundLiteralExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CastExpr - Base class for type casts, including both implicit +/// casts (ImplicitCastExpr) and explicit casts that have some +/// representation in the source code (ExplicitCastExpr's derived +/// classes). +class CastExpr : public Expr { + Stmt *Op; +protected: + CastExpr(StmtClass SC, QualType ty, Expr *op) : + Expr(SC, ty, + // Cast expressions are type-dependent if the type is + // dependent (C++ [temp.dep.expr]p3). + ty->isDependentType(), + // Cast expressions are value-dependent if the type is + // dependent or if the subexpression is value-dependent. + ty->isDependentType() || (op && op->isValueDependent())), + Op(op) {} + + /// \brief Construct an empty cast. + CastExpr(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty) { } + +public: + Expr *getSubExpr() { return cast<Expr>(Op); } + const Expr *getSubExpr() const { return cast<Expr>(Op); } + void setSubExpr(Expr *E) { Op = E; } + + static bool classof(const Stmt *T) { + StmtClass SC = T->getStmtClass(); + if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) + return true; + + if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass) + return true; + + return false; + } + static bool classof(const CastExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ImplicitCastExpr - Allows us to explicitly represent implicit type +/// conversions, which have no direct representation in the original +/// source code. For example: converting T[]->T*, void f()->void +/// (*f)(), float->double, short->int, etc. +/// +/// In C, implicit casts always produce rvalues. However, in C++, an +/// implicit cast whose result is being bound to a reference will be +/// an lvalue. For example: +/// +/// @code +/// class Base { }; +/// class Derived : public Base { }; +/// void f(Derived d) { +/// Base& b = d; // initializer is an ImplicitCastExpr to an lvalue of type Base +/// } +/// @endcode +class ImplicitCastExpr : public CastExpr { + /// LvalueCast - Whether this cast produces an lvalue. + bool LvalueCast; + +public: + ImplicitCastExpr(QualType ty, Expr *op, bool Lvalue) : + CastExpr(ImplicitCastExprClass, ty, op), LvalueCast(Lvalue) { } + + /// \brief Construct an empty implicit cast. + explicit ImplicitCastExpr(EmptyShell Shell) + : CastExpr(ImplicitCastExprClass, Shell) { } + + + virtual SourceRange getSourceRange() const { + return getSubExpr()->getSourceRange(); + } + + /// isLvalueCast - Whether this cast produces an lvalue. + bool isLvalueCast() const { return LvalueCast; } + + /// setLvalueCast - Set whether this cast produces an lvalue. + void setLvalueCast(bool Lvalue) { LvalueCast = Lvalue; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitCastExprClass; + } + static bool classof(const ImplicitCastExpr *) { return true; } +}; + +/// ExplicitCastExpr - An explicit cast written in the source +/// code. +/// +/// This class is effectively an abstract class, because it provides +/// the basic representation of an explicitly-written cast without +/// specifying which kind of cast (C cast, functional cast, static +/// cast, etc.) was written; specific derived classes represent the +/// particular style of cast and its location information. +/// +/// Unlike implicit casts, explicit cast nodes have two different +/// types: the type that was written into the source code, and the +/// actual type of the expression as determined by semantic +/// analysis. These types may differ slightly. For example, in C++ one +/// can cast to a reference type, which indicates that the resulting +/// expression will be an lvalue. The reference type, however, will +/// not be used as the type of the expression. +class ExplicitCastExpr : public CastExpr { + /// TypeAsWritten - The type that this expression is casting to, as + /// written in the source code. + QualType TypeAsWritten; + +protected: + ExplicitCastExpr(StmtClass SC, QualType exprTy, Expr *op, QualType writtenTy) + : CastExpr(SC, exprTy, op), TypeAsWritten(writtenTy) {} + + /// \brief Construct an empty explicit cast. + ExplicitCastExpr(StmtClass SC, EmptyShell Shell) + : CastExpr(SC, Shell) { } + +public: + /// getTypeAsWritten - Returns the type that this expression is + /// casting to, as written in the source code. + QualType getTypeAsWritten() const { return TypeAsWritten; } + void setTypeAsWritten(QualType T) { TypeAsWritten = T; } + + static bool classof(const Stmt *T) { + StmtClass SC = T->getStmtClass(); + if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass) + return true; + if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) + return true; + + return false; + } + static bool classof(const ExplicitCastExpr *) { return true; } +}; + +/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style +/// cast in C++ (C++ [expr.cast]), which uses the syntax +/// (Type)expr. For example: @c (int)f. +class CStyleCastExpr : public ExplicitCastExpr { + SourceLocation LPLoc; // the location of the left paren + SourceLocation RPLoc; // the location of the right paren +public: + CStyleCastExpr(QualType exprTy, Expr *op, QualType writtenTy, + SourceLocation l, SourceLocation r) : + ExplicitCastExpr(CStyleCastExprClass, exprTy, op, writtenTy), + LPLoc(l), RPLoc(r) {} + + /// \brief Construct an empty C-style explicit cast. + explicit CStyleCastExpr(EmptyShell Shell) + : ExplicitCastExpr(CStyleCastExprClass, Shell) { } + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CStyleCastExprClass; + } + static bool classof(const CStyleCastExpr *) { return true; } +}; + +/// \brief A builtin binary operation expression such as "x + y" or "x <= y". +/// +/// This expression node kind describes a builtin binary operation, +/// such as "x + y" for integer values "x" and "y". The operands will +/// already have been converted to appropriate types (e.g., by +/// performing promotions or conversions). +/// +/// In C++, where operators may be overloaded, a different kind of +/// expression node (CXXOperatorCallExpr) is used to express the +/// invocation of an overloaded operator with operator syntax. Within +/// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is +/// used to store an expression "x + y" depends on the subexpressions +/// for x and y. If neither x or y is type-dependent, and the "+" +/// operator resolves to a built-in operation, BinaryOperator will be +/// used to express the computation (x and y may still be +/// value-dependent). If either x or y is type-dependent, or if the +/// "+" resolves to an overloaded operator, CXXOperatorCallExpr will +/// be used to express the computation. +class BinaryOperator : public Expr { +public: + enum Opcode { + // Operators listed in order of precedence. + // Note that additions to this should also update the StmtVisitor class. + PtrMemD, PtrMemI, // [C++ 5.5] Pointer-to-member operators. + Mul, Div, Rem, // [C99 6.5.5] Multiplicative operators. + Add, Sub, // [C99 6.5.6] Additive operators. + Shl, Shr, // [C99 6.5.7] Bitwise shift operators. + LT, GT, LE, GE, // [C99 6.5.8] Relational operators. + EQ, NE, // [C99 6.5.9] Equality operators. + And, // [C99 6.5.10] Bitwise AND operator. + Xor, // [C99 6.5.11] Bitwise XOR operator. + Or, // [C99 6.5.12] Bitwise OR operator. + LAnd, // [C99 6.5.13] Logical AND operator. + LOr, // [C99 6.5.14] Logical OR operator. + Assign, MulAssign,// [C99 6.5.16] Assignment operators. + DivAssign, RemAssign, + AddAssign, SubAssign, + ShlAssign, ShrAssign, + AndAssign, XorAssign, + OrAssign, + Comma // [C99 6.5.17] Comma operator. + }; +private: + enum { LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + Opcode Opc; + SourceLocation OpLoc; +public: + + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + SourceLocation opLoc) + : Expr(BinaryOperatorClass, ResTy, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent()), + Opc(opc), OpLoc(opLoc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + assert(!isCompoundAssignmentOp() && + "Use ArithAssignBinaryOperator for compound assignments"); + } + + /// \brief Construct an empty binary operator. + explicit BinaryOperator(EmptyShell Empty) + : Expr(BinaryOperatorClass, Empty), Opc(Comma) { } + + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + Opcode getOpcode() const { return Opc; } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + virtual SourceRange getSourceRange() const { + return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd()); + } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "<<=". + static const char *getOpcodeStr(Opcode Op); + + /// \brief Retrieve the binary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given binary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + /// predicates to categorize the respective opcodes. + bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; } + bool isAdditiveOp() const { return Opc == Add || Opc == Sub; } + bool isShiftOp() const { return Opc == Shl || Opc == Shr; } + bool isBitwiseOp() const { return Opc >= And && Opc <= Or; } + + static bool isRelationalOp(Opcode Opc) { return Opc >= LT && Opc <= GE; } + bool isRelationalOp() const { return isRelationalOp(Opc); } + + static bool isEqualityOp(Opcode Opc) { return Opc == EQ || Opc == NE; } + bool isEqualityOp() const { return isEqualityOp(Opc); } + + static bool isLogicalOp(Opcode Opc) { return Opc == LAnd || Opc == LOr; } + bool isLogicalOp() const { return isLogicalOp(Opc); } + + bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; } + bool isCompoundAssignmentOp() const { return Opc > Assign && Opc <= OrAssign;} + bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; } + + static bool classof(const Stmt *S) { + return S->getStmtClass() == BinaryOperatorClass || + S->getStmtClass() == CompoundAssignOperatorClass; + } + static bool classof(const BinaryOperator *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + +protected: + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + SourceLocation oploc, bool dead) + : Expr(CompoundAssignOperatorClass, ResTy), Opc(opc), OpLoc(oploc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + BinaryOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), Opc(MulAssign) { } +}; + +/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep +/// track of the type the operation is performed in. Due to the semantics of +/// these operators, the operands are promoted, the aritmetic performed, an +/// implicit conversion back to the result type done, then the assignment takes +/// place. This captures the intermediate type which the computation is done +/// in. +class CompoundAssignOperator : public BinaryOperator { + QualType ComputationLHSType; + QualType ComputationResultType; +public: + CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, + QualType ResType, QualType CompLHSType, + QualType CompResultType, + SourceLocation OpLoc) + : BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true), + ComputationLHSType(CompLHSType), + ComputationResultType(CompResultType) { + assert(isCompoundAssignmentOp() && + "Only should be used for compound assignments"); + } + + /// \brief Build an empty compound assignment operator expression. + explicit CompoundAssignOperator(EmptyShell Empty) + : BinaryOperator(CompoundAssignOperatorClass, Empty) { } + + // The two computation types are the type the LHS is converted + // to for the computation and the type of the result; the two are + // distinct in a few cases (specifically, int+=ptr and ptr-=ptr). + QualType getComputationLHSType() const { return ComputationLHSType; } + void setComputationLHSType(QualType T) { ComputationLHSType = T; } + + QualType getComputationResultType() const { return ComputationResultType; } + void setComputationResultType(QualType T) { ComputationResultType = T; } + + static bool classof(const CompoundAssignOperator *) { return true; } + static bool classof(const Stmt *S) { + return S->getStmtClass() == CompoundAssignOperatorClass; + } +}; + +/// ConditionalOperator - The ?: operator. Note that LHS may be null when the +/// GNU "missing LHS" extension is in use. +/// +class ConditionalOperator : public Expr { + enum { COND, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. +public: + ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t) + : Expr(ConditionalOperatorClass, t, + // FIXME: the type of the conditional operator doesn't + // depend on the type of the conditional, but the standard + // seems to imply that it could. File a bug! + ((lhs && lhs->isTypeDependent()) || (rhs && rhs->isTypeDependent())), + (cond->isValueDependent() || + (lhs && lhs->isValueDependent()) || + (rhs && rhs->isValueDependent()))) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty conditional operator. + explicit ConditionalOperator(EmptyShell Empty) + : Expr(ConditionalOperatorClass, Empty) { } + + // getCond - Return the expression representing the condition for + // 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. In most cases this value + // will be the same as getLHS() except a GCC extension allows the left + // subexpression to be omitted, and instead of the condition be returned. + // e.g: x ?: y is shorthand for x ? x : y, except that the expression "x" + // is only evaluated once. + Expr *getTrueExpr() const { + return cast<Expr>(SubExprs[LHS] ? SubExprs[LHS] : SubExprs[COND]); + } + + // getTrueExpr - Return the subexpression representing the value of the ?: + // expression if the condition evaluates to false. This is the same as getRHS. + Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); } + + Expr *getLHS() const { return cast_or_null<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + virtual SourceRange getSourceRange() const { + return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass; + } + static bool classof(const ConditionalOperator *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// AddrLabelExpr - The GNU address of label extension, representing &&label. +class AddrLabelExpr : public Expr { + SourceLocation AmpAmpLoc, LabelLoc; + LabelStmt *Label; +public: + AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L, + QualType t) + : Expr(AddrLabelExprClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} + + /// \brief Build an empty address of a label expression. + explicit AddrLabelExpr(EmptyShell Empty) + : Expr(AddrLabelExprClass, Empty) { } + + SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } + void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AmpAmpLoc, LabelLoc); + } + + LabelStmt *getLabel() const { return Label; } + void setLabel(LabelStmt *S) { Label = S; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AddrLabelExprClass; + } + static bool classof(const AddrLabelExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// 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. +class StmtExpr : public Expr { + Stmt *SubStmt; + SourceLocation LParenLoc, RParenLoc; +public: + StmtExpr(CompoundStmt *substmt, QualType T, + SourceLocation lp, SourceLocation rp) : + Expr(StmtExprClass, T), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + + /// \brief Build an empty statement expression. + explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } + + CompoundStmt *getSubStmt() { return cast<CompoundStmt>(SubStmt); } + const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); } + void setSubStmt(CompoundStmt *S) { SubStmt = S; } + + virtual SourceRange getSourceRange() const { + return SourceRange(LParenLoc, RParenLoc); + } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == StmtExprClass; + } + static bool classof(const StmtExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// 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 { + QualType Type1; + QualType Type2; + SourceLocation BuiltinLoc, RParenLoc; +public: + TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc, + QualType t1, QualType t2, SourceLocation RP) : + Expr(TypesCompatibleExprClass, ReturnType), Type1(t1), Type2(t2), + BuiltinLoc(BLoc), RParenLoc(RP) {} + + /// \brief Build an empty __builtin_type_compatible_p expression. + explicit TypesCompatibleExpr(EmptyShell Empty) + : Expr(TypesCompatibleExprClass, Empty) { } + + QualType getArgType1() const { return Type1; } + void setArgType1(QualType T) { Type1 = T; } + QualType getArgType2() const { return Type2; } + void setArgType2(QualType T) { Type2 = T; } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == TypesCompatibleExprClass; + } + 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. +/// This AST node represents a operator that does a constant +/// shuffle, similar to LLVM's shufflevector instruction. It takes +/// two vectors and a variable number of constant indices, +/// and returns the appropriately shuffled vector. +class ShuffleVectorExpr : public Expr { + SourceLocation BuiltinLoc, RParenLoc; + + // SubExprs - the list of values passed to the __builtin_shufflevector + // function. The first two are vectors, and the rest are constant + // indices. The number of values in this list is always + // 2+the number of indices in the vector type. + Stmt **SubExprs; + unsigned NumExprs; + +public: + ShuffleVectorExpr(Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP) : + Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc), + RParenLoc(RP), NumExprs(nexpr) { + + SubExprs = new Stmt*[nexpr]; + for (unsigned i = 0; i < nexpr; i++) + SubExprs[i] = args[i]; + } + + /// \brief Build an empty vector-shuffle expression. + explicit ShuffleVectorExpr(EmptyShell Empty) + : Expr(ShuffleVectorExprClass, Empty), SubExprs(0) { } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ShuffleVectorExprClass; + } + static bool classof(const ShuffleVectorExpr *) { return true; } + + ~ShuffleVectorExpr() { + delete [] SubExprs; + } + + /// getNumSubExprs - Return the size of the SubExprs array. This includes the + /// constant expression, the actual arguments passed in, and the function + /// pointers. + unsigned getNumSubExprs() const { return NumExprs; } + + /// getExpr - Return the Expr at the specified index. + Expr *getExpr(unsigned Index) { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + const Expr *getExpr(unsigned Index) const { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + + void setExprs(Expr ** Exprs, unsigned NumExprs); + + unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) { + assert((N < NumExprs - 2) && "Shuffle idx out of range!"); + return getExpr(N+2)->EvaluateAsInt(Ctx).getZExtValue(); + } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ChooseExpr - GNU builtin-in function __builtin_choose_expr. +/// This AST node is similar to the conditional operator (?:) in C, with +/// the following exceptions: +/// - the test expression must be a integer constant expression. +/// - the expression returned acts like the chosen subexpression in every +/// visible way: the type is the same as that of the chosen subexpression, +/// and all predicates (whether it's an l-value, whether it's an integer +/// constant expression, etc.) return the same result as for the chosen +/// sub-expression. +class ChooseExpr : public Expr { + enum { COND, LHS, RHS, END_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, + SourceLocation RP) + : Expr(ChooseExprClass, t), + BuiltinLoc(BLoc), RParenLoc(RP) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty __builtin_choose_expr. + explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } + + /// isConditionTrue - Return whether the condition is true (i.e. not + /// equal to zero). + bool isConditionTrue(ASTContext &C) const; + + /// getChosenSubExpr - Return the subexpression chosen according to the + /// condition. + Expr *getChosenSubExpr(ASTContext &C) const { + return isConditionTrue(C) ? getLHS() : getRHS(); + } + + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + void setCond(Expr *E) { SubExprs[COND] = E; } + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + SourceLocation 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() == ChooseExprClass; + } + static bool classof(const ChooseExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// GNUNullExpr - Implements the GNU __null extension, which is a name +/// for a null pointer constant that has integral type (e.g., int or +/// long) and is the same size and alignment as a pointer. The __null +/// extension is typically only used by system headers, which define +/// NULL as __null in C++ rather than using 0 (which is an integer +/// that may not match the size of a pointer). +class GNUNullExpr : public Expr { + /// TokenLoc - The location of the __null keyword. + SourceLocation TokenLoc; + +public: + GNUNullExpr(QualType Ty, SourceLocation Loc) + : Expr(GNUNullExprClass, Ty), TokenLoc(Loc) { } + + /// \brief Build an empty GNU __null expression. + explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } + + GNUNullExpr* Clone(ASTContext &C) const; + + /// getTokenLocation - The location of the __null token. + SourceLocation getTokenLocation() const { return TokenLoc; } + void setTokenLocation(SourceLocation L) { TokenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TokenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GNUNullExprClass; + } + static bool classof(const GNUNullExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// VAArgExpr, used for the builtin function __builtin_va_start. +class VAArgExpr : public Expr { + Stmt *Val; + SourceLocation BuiltinLoc, RParenLoc; +public: + VAArgExpr(SourceLocation BLoc, Expr* e, QualType t, SourceLocation RPLoc) + : Expr(VAArgExprClass, t), + Val(e), + BuiltinLoc(BLoc), + RParenLoc(RPLoc) { } + + /// \brief Create an empty __builtin_va_start expression. + explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == VAArgExprClass; + } + static bool classof(const VAArgExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// @brief Describes an C or C++ initializer list. +/// +/// InitListExpr describes an initializer list, which can be used to +/// initialize objects of different types, including +/// struct/class/union types, arrays, and vectors. For example: +/// +/// @code +/// struct foo x = { 1, { 2, 3 } }; +/// @endcode +/// +/// Prior to semantic analysis, an initializer list will represent the +/// initializer list as written by the user, but will have the +/// placeholder type "void". This initializer list is called the +/// syntactic form of the initializer, and may contain C99 designated +/// initializers (represented as DesignatedInitExprs), initializations +/// of subobject members without explicit braces, and so on. Clients +/// interested in the original syntax of the initializer list should +/// use the syntactic form of the initializer list. +/// +/// After semantic analysis, the initializer list will represent the +/// semantic form of the initializer, where the initializations of all +/// subobjects are made explicit with nested InitListExpr nodes and +/// C99 designators have been eliminated by placing the designated +/// initializations into the subobject they initialize. Additionally, +/// any "holes" in the initialization, where no initializer has been +/// specified for a particular subobject, will be replaced with +/// implicitly-generated ImplicitValueInitExpr expressions that +/// value-initialize the subobjects. Note, however, that the +/// initializer lists may still have fewer initializers than there are +/// elements to initialize within the object. +/// +/// Given the semantic form of the initializer list, one can retrieve +/// the original syntactic form of that initializer list (if it +/// exists) using getSyntacticForm(). Since many initializer lists +/// have the same syntactic and semantic forms, getSyntacticForm() may +/// return NULL, indicating that the current initializer list also +/// serves as its syntactic form. +class InitListExpr : public Expr { + std::vector<Stmt *> InitExprs; + SourceLocation LBraceLoc, RBraceLoc; + + /// Contains the initializer list that describes the syntactic form + /// written in the source code. + InitListExpr *SyntacticForm; + + /// If this initializer list initializes a union, specifies which + /// field within the union will be initialized. + FieldDecl *UnionFieldInit; + + /// Whether this initializer list originally had a GNU array-range + /// designator in it. This is a temporary marker used by CodeGen. + bool HadArrayRangeDesignator; + +public: + InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits, + SourceLocation rbraceloc); + + /// \brief Build an empty initializer list. + explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty) { } + + unsigned getNumInits() const { return InitExprs.size(); } + + const Expr* getInit(unsigned Init) const { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + Expr* getInit(unsigned Init) { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + void setInit(unsigned Init, Expr *expr) { + assert(Init < getNumInits() && "Initializer access out of range!"); + InitExprs[Init] = expr; + } + + /// \brief Reserve space for some number of initializers. + void reserveInits(unsigned NumInits); + + /// @brief Specify the number of initializers + /// + /// If there are more than @p NumInits initializers, the remaining + /// initializers will be destroyed. If there are fewer than @p + /// NumInits initializers, NULL expressions will be added for the + /// unknown initializers. + void resizeInits(ASTContext &Context, unsigned NumInits); + + /// @brief Updates the initializer at index @p Init with the new + /// expression @p expr, and returns the old expression at that + /// location. + /// + /// When @p Init is out of range for this initializer list, the + /// initializer list will be extended with NULL expressions to + /// accomodate the new entry. + Expr *updateInit(unsigned Init, Expr *expr); + + /// \brief If this initializes a union, specifies which field in the + /// union to initialize. + /// + /// Typically, this field is the first named field within the + /// union. However, a designated initializer can specify the + /// initialization of a different field within the union. + FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; } + void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; } + + // Explicit InitListExpr's originate from source code (and have valid source + // locations). Implicit InitListExpr's are created by the semantic analyzer. + bool isExplicit() { + return LBraceLoc.isValid() && RBraceLoc.isValid(); + } + + SourceLocation getLBraceLoc() const { return LBraceLoc; } + void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; } + + /// @brief Retrieve the initializer list that describes the + /// syntactic form of the initializer. + /// + /// + InitListExpr *getSyntacticForm() const { return SyntacticForm; } + void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; } + + bool hadArrayRangeDesignator() const { return HadArrayRangeDesignator; } + void sawArrayRangeDesignator(bool ARD = true) { + HadArrayRangeDesignator = ARD; + } + + virtual SourceRange getSourceRange() const { + return SourceRange(LBraceLoc, RBraceLoc); + } + 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(); + + typedef std::vector<Stmt *>::iterator iterator; + typedef std::vector<Stmt *>::reverse_iterator reverse_iterator; + + iterator begin() { return InitExprs.begin(); } + iterator end() { return InitExprs.end(); } + reverse_iterator rbegin() { return InitExprs.rbegin(); } + reverse_iterator rend() { return InitExprs.rend(); } +}; + +/// @brief Represents a C99 designated initializer expression. +/// +/// A designated initializer expression (C99 6.7.8) contains one or +/// more designators (which can be field designators, array +/// designators, or GNU array-range designators) followed by an +/// expression that initializes the field or element(s) that the +/// designators refer to. For example, given: +/// +/// @code +/// struct point { +/// double x; +/// double y; +/// }; +/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; +/// @endcode +/// +/// The InitListExpr contains three DesignatedInitExprs, the first of +/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two +/// designators, one array designator for @c [2] followed by one field +/// designator for @c .y. The initalization expression will be 1.0. +class DesignatedInitExpr : public Expr { +public: + /// \brief Forward declaration of the Designator class. + class Designator; + +private: + /// The location of the '=' or ':' prior to the actual initializer + /// expression. + SourceLocation EqualOrColonLoc; + + /// Whether this designated initializer used the GNU deprecated + /// syntax rather than the C99 '=' syntax. + bool GNUSyntax : 1; + + /// The number of designators in this initializer expression. + unsigned NumDesignators : 15; + + /// \brief The designators in this designated initialization + /// expression. + Designator *Designators; + + /// The number of subexpressions of this initializer expression, + /// which contains both the initializer and any additional + /// expressions used by array and array-range designators. + unsigned NumSubExprs : 16; + + + DesignatedInitExpr(QualType Ty, unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, bool GNUSyntax, + Expr **IndexExprs, unsigned NumIndexExprs, + Expr *Init); + + explicit DesignatedInitExpr(unsigned NumSubExprs) + : Expr(DesignatedInitExprClass, EmptyShell()), + NumDesignators(0), Designators(0), NumSubExprs(NumSubExprs) { } + +public: + /// A field designator, e.g., ".x". + struct FieldDesignator { + /// Refers to the field that is being initialized. The low bit + /// of this field determines whether this is actually a pointer + /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When + /// initially constructed, a field designator will store an + /// IdentifierInfo*. After semantic analysis has resolved that + /// name, the field designator will instead store a FieldDecl*. + uintptr_t NameOrField; + + /// The location of the '.' in the designated initializer. + unsigned DotLoc; + + /// The location of the field name in the designated initializer. + unsigned FieldLoc; + }; + + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator { + /// Location of the first index expression within the designated + /// initializer expression's list of subexpressions. + unsigned Index; + /// The location of the '[' starting the array range designator. + unsigned LBracketLoc; + /// The location of the ellipsis separating the start and end + /// indices. Only valid for GNU array-range designators. + unsigned EllipsisLoc; + /// The location of the ']' terminating the array range designator. + unsigned RBracketLoc; + }; + + /// @brief Represents a single C99 designator. + /// + /// @todo This class is infuriatingly similar to clang::Designator, + /// but minor differences (storing indices vs. storing pointers) + /// keep us from reusing it. Try harder, later, to rectify these + /// differences. + class Designator { + /// @brief The kind of designator this describes. + enum { + FieldDesignator, + ArrayDesignator, + ArrayRangeDesignator + } Kind; + + union { + /// A field designator, e.g., ".x". + struct FieldDesignator Field; + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator ArrayOrRange; + }; + friend class DesignatedInitExpr; + + public: + Designator() {} + + /// @brief Initializes a field designator. + Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, + SourceLocation FieldLoc) + : Kind(FieldDesignator) { + Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01; + Field.DotLoc = DotLoc.getRawEncoding(); + Field.FieldLoc = FieldLoc.getRawEncoding(); + } + + /// @brief Initializes an array designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation RBracketLoc) + : Kind(ArrayDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// @brief Initializes a GNU array-range designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation EllipsisLoc, SourceLocation RBracketLoc) + : Kind(ArrayRangeDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + IdentifierInfo * getFieldName(); + + FieldDecl *getField() { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + if (Field.NameOrField & 0x01) + return 0; + else + return reinterpret_cast<FieldDecl *>(Field.NameOrField); + } + + void setField(FieldDecl *FD) { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + Field.NameOrField = reinterpret_cast<uintptr_t>(FD); + } + + SourceLocation getDotLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.FieldLoc); + } + + SourceLocation getLBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(Kind == ArrayRangeDesignator && + "Only valid on an array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc); + } + + unsigned getFirstExprIndex() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return ArrayOrRange.Index; + } + + SourceLocation getStartLocation() const { + if (Kind == FieldDesignator) + return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); + else + return getLBracketLoc(); + } + }; + + static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, + unsigned NumDesignators, + Expr **IndexExprs, unsigned NumIndexExprs, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, Expr *Init); + + static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs); + + /// @brief Returns the number of designators in this initializer. + unsigned size() const { return NumDesignators; } + + // Iterator access to the designators. + typedef Designator* designators_iterator; + designators_iterator designators_begin() { return Designators; } + designators_iterator designators_end() { + return Designators + NumDesignators; + } + + Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } + + void setDesignators(const Designator *Desigs, unsigned NumDesigs); + + Expr *getArrayIndex(const Designator& D); + Expr *getArrayRangeStart(const Designator& D); + Expr *getArrayRangeEnd(const Designator& D); + + /// @brief Retrieve the location of the '=' that precedes the + /// initializer value itself, if present. + SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; } + void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; } + + /// @brief Determines whether this designated initializer used the + /// deprecated GNU syntax for designated initializers. + bool usesGNUSyntax() const { return GNUSyntax; } + void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } + + /// @brief Retrieve the initializer value. + Expr *getInit() const { + return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin()); + } + + void setInit(Expr *init) { + *child_begin() = init; + } + + /// \brief Retrieve the total number of subexpressions in this + /// designated initializer expression, including the actual + /// initialized value and any expressions that occur within array + /// and array-range designators. + unsigned getNumSubExprs() const { return NumSubExprs; } + + Expr *getSubExpr(unsigned Idx) { + assert(Idx < NumSubExprs && "Subscript out of range"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + return reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx]; + } + + void setSubExpr(unsigned Idx, Expr *E) { + assert(Idx < NumSubExprs && "Subscript out of range"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx] = E; + } + + /// \brief Replaces the designator at index @p Idx with the series + /// of designators in [First, Last). + void ExpandDesignator(unsigned Idx, const Designator *First, + const Designator *Last); + + virtual SourceRange getSourceRange() const; + + virtual void Destroy(ASTContext &C); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DesignatedInitExprClass; + } + static bool classof(const DesignatedInitExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// \brief Represents an implicitly-generated value initialization of +/// an object of a given type. +/// +/// Implicit value initializations occur within semantic initializer +/// list expressions (InitListExpr) as placeholders for subobject +/// initializations not explicitly specified by the user. +/// +/// \see InitListExpr +class ImplicitValueInitExpr : public Expr { +public: + explicit ImplicitValueInitExpr(QualType ty) + : Expr(ImplicitValueInitExprClass, ty) { } + + /// \brief Construct an empty implicit value initialization. + explicit ImplicitValueInitExpr(EmptyShell Empty) + : Expr(ImplicitValueInitExprClass, Empty) { } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitValueInitExprClass; + } + static bool classof(const ImplicitValueInitExpr *) { return true; } + + virtual SourceRange getSourceRange() const { + return SourceRange(); + } + + ImplicitValueInitExpr *Clone(ASTContext &C) const; + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +//===----------------------------------------------------------------------===// +// Clang Extensions +//===----------------------------------------------------------------------===// + + +/// ExtVectorElementExpr - This represents access to specific elements of a +/// vector, and may occur on the left hand side or right hand side. For example +/// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector. +/// +/// Note that the base may have either vector or pointer to vector type, just +/// like a struct field reference. +/// +class ExtVectorElementExpr : public Expr { + Stmt *Base; + IdentifierInfo *Accessor; + SourceLocation AccessorLoc; +public: + ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor, + SourceLocation loc) + : Expr(ExtVectorElementExprClass, ty), + Base(base), Accessor(&accessor), AccessorLoc(loc) {} + + /// \brief Build an empty vector element expression. + explicit ExtVectorElementExpr(EmptyShell Empty) + : Expr(ExtVectorElementExprClass, Empty) { } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *E) { Base = E; } + + IdentifierInfo &getAccessor() const { return *Accessor; } + void setAccessor(IdentifierInfo *II) { Accessor = II; } + + SourceLocation getAccessorLoc() const { return AccessorLoc; } + void setAccessorLoc(SourceLocation L) { AccessorLoc = L; } + + /// getNumElements - Get the number of components being selected. + unsigned getNumElements() const; + + /// containsDuplicateElements - Return true if any element access is + /// repeated. + bool containsDuplicateElements() const; + + /// getEncodedElementAccess - Encode the elements accessed into an llvm + /// aggregate Constant of ConstantInt(s). + void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const; + + virtual SourceRange getSourceRange() const { + return SourceRange(getBase()->getLocStart(), AccessorLoc); + } + + /// isArrow - Return true if the base expression is a pointer to vector, + /// return false if the base expression is a vector. + bool isArrow() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExtVectorElementExprClass; + } + static bool classof(const ExtVectorElementExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +class BlockExpr : public Expr { +protected: + BlockDecl *TheBlock; + bool HasBlockDeclRefExprs; +public: + BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs) + : Expr(BlockExprClass, ty), + TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {} + + /// \brief Build an empty block expression. + explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } + + const BlockDecl *getBlockDecl() const { return TheBlock; } + BlockDecl *getBlockDecl() { return TheBlock; } + void setBlockDecl(BlockDecl *BD) { TheBlock = BD; } + + // Convenience functions for probing the underlying BlockDecl. + SourceLocation getCaretLocation() const; + const Stmt *getBody() const; + Stmt *getBody(); + + const Stmt *getBody(ASTContext &C) const { return getBody(); } + Stmt *getBody(ASTContext &C) { return getBody(); } + + virtual 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(); +}; + +/// BlockDeclRefExpr - A reference to a declared variable, function, +/// enum, etc. +class BlockDeclRefExpr : public Expr { + ValueDecl *D; + SourceLocation Loc; + bool IsByRef; +public: + BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) : + Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {} + + // \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; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + bool isByRef() const { return IsByRef; } + void setByRef(bool BR) { IsByRef = BR; } + + 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(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h new file mode 100644 index 000000000000..53386231a03f --- /dev/null +++ b/include/clang/AST/ExprCXX.h @@ -0,0 +1,1234 @@ +//===--- ExprCXX.h - Classes for representing 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 the Expr interface and subclasses for C++ expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPRCXX_H +#define LLVM_CLANG_AST_EXPRCXX_H + +#include "clang/Basic/TypeTraits.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" + +namespace clang { + + class CXXConstructorDecl; + class CXXDestructorDecl; + class CXXTemporary; + +//===--------------------------------------------------------------------===// +// C++ Expressions. +//===--------------------------------------------------------------------===// + +/// \brief A call to an overloaded operator written using operator +/// syntax. +/// +/// Represents a call to an overloaded operator written using operator +/// syntax, e.g., "x + y" or "*p". While semantically equivalent to a +/// normal call, this AST node provides better information about the +/// syntactic representation of the call. +/// +/// In a C++ template, this expression node kind will be used whenever +/// any of the arguments are type-dependent. In this case, the +/// function itself will be a (possibly empty) set of functions and +/// function templates that were found by name lookup at template +/// definition time. +class CXXOperatorCallExpr : public CallExpr { + /// \brief The overloaded operator. + OverloadedOperatorKind Operator; + +public: + CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, + Expr **args, unsigned numargs, QualType t, + SourceLocation operatorloc) + : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc), + Operator(Op) {} + + /// getOperator - Returns the kind of overloaded operator that this + /// expression refers to. + OverloadedOperatorKind getOperator() const { return Operator; } + + /// getOperatorLoc - Returns the location of the operator symbol in + /// the expression. When @c getOperator()==OO_Call, this is the + /// location of the right parentheses; when @c + /// getOperator()==OO_Subscript, this is the location of the right + /// bracket. + SourceLocation getOperatorLoc() const { return getRParenLoc(); } + + virtual SourceRange getSourceRange() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXOperatorCallExprClass; + } + static bool classof(const CXXOperatorCallExpr *) { return true; } +}; + +/// CXXMemberCallExpr - Represents a call to a member function that +/// may be written either with member call syntax (e.g., "obj.func()" +/// or "objptr->func()") or with normal function-call syntax +/// ("func()") within a member function that ends up calling a member +/// function. The callee in either case is a MemberExpr that contains +/// both the object argument and the member function, while the +/// arguments are the arguments within the parentheses (not including +/// the object argument). +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) {} + + /// getImplicitObjectArgument - Retrieves the implicit object + /// argument for the member call. For example, in "x.f(5)", this + /// operation would return "x". + Expr *getImplicitObjectArgument(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXMemberCallExprClass; + } + static bool classof(const CXXMemberCallExpr *) { 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. +/// +/// This abstract class is inherited by all of the classes +/// representing "named" casts, e.g., CXXStaticCastExpr, +/// CXXDynamicCastExpr, CXXReinterpretCastExpr, and CXXConstCastExpr. +class CXXNamedCastExpr : public ExplicitCastExpr { +private: + SourceLocation Loc; // the location of the casting op + +protected: + CXXNamedCastExpr(StmtClass SC, QualType ty, Expr *op, QualType writtenTy, + SourceLocation l) + : ExplicitCastExpr(SC, ty, op, writtenTy), Loc(l) {} + +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()); + } + static bool classof(const Stmt *T) { + switch (T->getStmtClass()) { + case CXXNamedCastExprClass: + case CXXStaticCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + return true; + default: + return false; + } + } + static bool classof(const CXXNamedCastExpr *) { return true; } +}; + +/// CXXStaticCastExpr - A C++ @c static_cast expression (C++ [expr.static.cast]). +/// +/// This expression node represents a C++ static cast, e.g., +/// @c static_cast<int>(1.0). +class CXXStaticCastExpr : public CXXNamedCastExpr { +public: + CXXStaticCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, op, writtenTy, l) {} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXStaticCastExprClass; + } + static bool classof(const CXXStaticCastExpr *) { return true; } +}; + +/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression +/// (C++ [expr.dynamic.cast]), which may perform a run-time check to +/// determine how to perform the type cast. +/// +/// This expression node represents a dynamic cast, e.g., +/// @c dynamic_cast<Derived*>(BasePtr). +class CXXDynamicCastExpr : public CXXNamedCastExpr { +public: + CXXDynamicCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, op, writtenTy, l) {} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDynamicCastExprClass; + } + static bool classof(const CXXDynamicCastExpr *) { return true; } +}; + +/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++ +/// [expr.reinterpret.cast]), which provides a differently-typed view +/// of a value but performs no actual work at run time. +/// +/// This expression node represents a reinterpret cast, e.g., +/// @c reinterpret_cast<int>(VoidPtr). +class CXXReinterpretCastExpr : public CXXNamedCastExpr { +public: + CXXReinterpretCastExpr(QualType ty, Expr *op, QualType writtenTy, + SourceLocation l) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, op, writtenTy, l) {} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXReinterpretCastExprClass; + } + static bool classof(const CXXReinterpretCastExpr *) { return true; } +}; + +/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]), +/// which can remove type qualifiers but does not change the underlying value. +/// +/// This expression node represents a const cast, e.g., +/// @c const_cast<char*>(PtrToConstChar). +class CXXConstCastExpr : public CXXNamedCastExpr { +public: + CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy, + SourceLocation l) + : CXXNamedCastExpr(CXXConstCastExprClass, ty, op, writtenTy, l) {} + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstCastExprClass; + } + static bool classof(const CXXConstCastExpr *) { return true; } +}; + +/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal. +/// +class CXXBoolLiteralExpr : public Expr { + bool Value; + SourceLocation Loc; +public: + CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + Expr(CXXBoolLiteralExprClass, Ty), Value(val), Loc(l) {} + + CXXBoolLiteralExpr* Clone(ASTContext &C) const; + + bool getValue() const { return Value; } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBoolLiteralExprClass; + } + static bool classof(const CXXBoolLiteralExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal +class CXXNullPtrLiteralExpr : public Expr { + SourceLocation Loc; +public: + CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : + Expr(CXXNullPtrLiteralExprClass, Ty), Loc(l) {} + + CXXNullPtrLiteralExpr* Clone(ASTContext &C) const; + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNullPtrLiteralExprClass; + } + static bool classof(const CXXNullPtrLiteralExpr *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets +/// the type_info that corresponds to the supplied type, or the (possibly +/// dynamic) type of the supplied expression. +/// +/// This represents code like @c typeid(int) or @c typeid(*objPtr) +class CXXTypeidExpr : public Expr { +private: + bool isTypeOp : 1; + union { + void *Ty; + Stmt *Ex; + } Operand; + SourceRange Range; + +public: + CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) : + Expr(CXXTypeidExprClass, Ty, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType() + : static_cast<Expr*>(op)->isValueDependent())), + isTypeOp(isTypeOp), Range(r) { + if (isTypeOp) + Operand.Ty = op; + else + // op was an Expr*, so cast it back to that to be safe + Operand.Ex = static_cast<Expr*>(op); + } + + bool isTypeOperand() const { return isTypeOp; } + QualType getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return QualType::getFromOpaquePtr(Operand.Ty); + } + Expr* getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + return static_cast<Expr*>(Operand.Ex); + } + + virtual SourceRange getSourceRange() const { + return Range; + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTypeidExprClass; + } + static bool classof(const CXXTypeidExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXThisExpr - Represents the "this" expression in C++, which is a +/// pointer to the object on which the current member function is +/// executing (C++ [expr.prim]p3). Example: +/// +/// @code +/// class Foo { +/// public: +/// void bar(); +/// void test() { this->bar(); } +/// }; +/// @endcode +class CXXThisExpr : public Expr { + SourceLocation Loc; + +public: + CXXThisExpr(SourceLocation L, QualType Type) + : Expr(CXXThisExprClass, Type, + // 'this' is type-dependent if the class type of the enclosing + // member function is dependent (C++ [temp.dep.expr]p2) + Type->isDependentType(), Type->isDependentType()), + Loc(L) { } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThisExprClass; + } + static bool classof(const CXXThisExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles +/// 'throw' and 'throw' assignment-expression. When +/// assignment-expression isn't present, Op will be null. +/// +class CXXThrowExpr : public Expr { + Stmt *Op; + SourceLocation ThrowLoc; +public: + // Ty is the void type which is used as the result type of the + // 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) {} + const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } + Expr *getSubExpr() { return cast_or_null<Expr>(Op); } + void setSubExpr(Expr *E) { Op = E; } + + SourceLocation getThrowLoc() const { return ThrowLoc; } + void setThrowLoc(SourceLocation L) { ThrowLoc = L; } + + virtual SourceRange getSourceRange() const { + if (getSubExpr() == 0) + return SourceRange(ThrowLoc, ThrowLoc); + return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThrowExprClass; + } + static bool classof(const CXXThrowExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a +/// function call argument that was created from the corresponding +/// parameter's default argument, when the call did not explicitly +/// supply arguments for all of the parameters. +class CXXDefaultArgExpr : public Expr { + ParmVarDecl *Param; +public: + // Param is the parameter whose default argument is used by this + // expression. + explicit CXXDefaultArgExpr(ParmVarDecl *param) + : Expr(CXXDefaultArgExprClass, + param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType()), + Param(param) { } + + // Retrieve the parameter that the argument was created from. + const ParmVarDecl *getParam() const { return Param; } + ParmVarDecl *getParam() { return Param; } + + // Retrieve the actual argument to the function call. + const Expr *getExpr() const { return Param->getDefaultArg(); } + Expr *getExpr() { return Param->getDefaultArg(); } + + virtual SourceRange getSourceRange() const { + // Default argument expressions have no representation in the + // source, so they have an empty source range. + return SourceRange(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDefaultArgExprClass; + } + static bool classof(const CXXDefaultArgExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXTemporary - Represents a C++ temporary. +class CXXTemporary { + /// Destructor - The destructor that needs to be called. + const CXXDestructorDecl *Destructor; + + CXXTemporary(const CXXDestructorDecl *destructor) + : Destructor(destructor) { } + ~CXXTemporary() { } + +public: + static CXXTemporary *Create(ASTContext &C, + const CXXDestructorDecl *Destructor); + void Destroy(ASTContext &C); + + const CXXDestructorDecl *getDestructor() const { return Destructor; } +}; + +/// CXXBindTemporaryExpr - Represents binding an expression to a temporary, +/// so its destructor can be called later. +class CXXBindTemporaryExpr : public Expr { + CXXTemporary *Temp; + + Stmt *SubExpr; + + CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr) + : Expr(CXXBindTemporaryExprClass, + subexpr->getType()), Temp(temp), SubExpr(subexpr) { } + ~CXXBindTemporaryExpr() { } + +public: + static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp, + Expr* SubExpr); + void Destroy(ASTContext &C); + + CXXTemporary *getTemporary() { return Temp; } + const CXXTemporary *getTemporary() const { return Temp; } + + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + virtual SourceRange getSourceRange() const { return SourceRange(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBindTemporaryExprClass; + } + static bool classof(const CXXBindTemporaryExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXConstructExpr - Represents a call to a C++ constructor. +class CXXConstructExpr : public Expr { + CXXConstructorDecl *Constructor; + + bool Elidable; + + Stmt **Args; + unsigned NumArgs; + + +protected: + CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + CXXConstructorDecl *d, bool elidable, + Expr **args, unsigned numargs); + ~CXXConstructExpr() { } + +public: + static CXXConstructExpr *Create(ASTContext &C, QualType T, + CXXConstructorDecl *D, bool Elidable, + Expr **Args, unsigned NumArgs); + + void Destroy(ASTContext &C); + + CXXConstructorDecl* getConstructor() const { return Constructor; } + + /// \brief Whether this construction is elidable. + bool isElidable() const { return Elidable; } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return Args; } + arg_iterator arg_end() { return Args + NumArgs; } + const_arg_iterator arg_begin() const { return Args; } + const_arg_iterator arg_end() const { return Args + NumArgs; } + + unsigned getNumArgs() const { return NumArgs; } + + virtual SourceRange getSourceRange() const { return SourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstructExprClass || + T->getStmtClass() == CXXTemporaryObjectExprClass; + } + static bool classof(const CXXConstructExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXFunctionalCastExpr - Represents an explicit C++ type conversion +/// that uses "functional" notion (C++ [expr.type.conv]). Example: @c +/// x = int(0.5); +class CXXFunctionalCastExpr : public ExplicitCastExpr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; +public: + CXXFunctionalCastExpr(QualType ty, QualType writtenTy, + SourceLocation tyBeginLoc, Expr *castExpr, + SourceLocation rParenLoc) : + ExplicitCastExpr(CXXFunctionalCastExprClass, ty, castExpr, writtenTy), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFunctionalCastExprClass; + } + static bool classof(const CXXFunctionalCastExpr *) { return true; } +}; + +/// @brief Represents a C++ functional cast expression that builds a +/// temporary object. +/// +/// This expression type represents a C++ "functional" cast +/// (C++[expr.type.conv]) with N != 1 arguments that invokes a +/// constructor to build a temporary object. If N == 0 but no +/// constructor will be called (because the functional cast is +/// performing a value-initialized an object whose class type has no +/// user-declared constructors), CXXZeroInitValueExpr will represent +/// the functional cast. Finally, with N == 1 arguments the functional +/// cast expression will be represented by CXXFunctionalCastExpr. +/// Example: +/// @code +/// struct X { X(int, float); } +/// +/// X create_X() { +/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr +/// }; +/// @endcode +class CXXTemporaryObjectExpr : public CXXConstructExpr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; + +public: + CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, + QualType writtenTy, SourceLocation tyBeginLoc, + Expr **Args,unsigned NumArgs, + SourceLocation rParenLoc); + + ~CXXTemporaryObjectExpr() { } + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTemporaryObjectExprClass; + } + static bool classof(const CXXTemporaryObjectExpr *) { return true; } +}; + +/// CXXZeroInitValueExpr - [C++ 5.2.3p2] +/// Expression "T()" which creates a value-initialized rvalue of type +/// T, which is either a non-class type or a class type without any +/// user-defined constructors. +/// +class CXXZeroInitValueExpr : public Expr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; + +public: + CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc, + SourceLocation rParenLoc ) : + Expr(CXXZeroInitValueExprClass, ty, false, false), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// @brief Whether this initialization expression was + /// implicitly-generated. + bool isImplicit() const { + return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + + CXXZeroInitValueExpr* Clone(ASTContext &C) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXZeroInitValueExprClass; + } + static bool classof(const CXXZeroInitValueExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXConditionDeclExpr - Condition declaration of a if/switch/while/for +/// statement, e.g: "if (int x = f()) {...}". +/// The main difference with DeclRefExpr is that CXXConditionDeclExpr owns the +/// decl that it references. +/// +class CXXConditionDeclExpr : public DeclRefExpr { +public: + CXXConditionDeclExpr(SourceLocation startLoc, + SourceLocation eqLoc, VarDecl *var) + : DeclRefExpr(CXXConditionDeclExprClass, var, + var->getType().getNonReferenceType(), startLoc, + var->getType()->isDependentType(), + /*FIXME:integral constant?*/ + var->getType()->isDependentType()) {} + + virtual void Destroy(ASTContext& Ctx); + + SourceLocation getStartLoc() const { return getLocation(); } + + VarDecl *getVarDecl() { return cast<VarDecl>(getDecl()); } + const VarDecl *getVarDecl() const { return cast<VarDecl>(getDecl()); } + + virtual SourceRange getSourceRange() const { + return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConditionDeclExprClass; + } + static bool classof(const CXXConditionDeclExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXNewExpr - A new expression for memory allocation and constructor calls, +/// e.g: "new CXXNewExpr(foo)". +class CXXNewExpr : public Expr { + // Was the usage ::new, i.e. is the global new to be used? + bool GlobalNew : 1; + // Was the form (type-id) used? Otherwise, it was new-type-id. + bool ParenTypeId : 1; + // Is there an initializer? If not, built-ins are uninitialized, else they're + // value-initialized. + bool Initializer : 1; + // Do we allocate an array? If so, the first SubExpr is the size expression. + bool Array : 1; + // The number of placement new arguments. + 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; + // Contains an optional array size expression, any number of optional + // placement arguments, and any number of optional constructor arguments, + // in that order. + Stmt **SubExprs; + // Points to the allocation function used. + FunctionDecl *OperatorNew; + // Points to the deallocation function used in case of error. May be null. + FunctionDecl *OperatorDelete; + // Points to the constructor used. Cannot be null if AllocType is a record; + // it would still point at the default constructor (even an implicit one). + // Must be null for all other types. + CXXConstructorDecl *Constructor; + + SourceLocation StartLoc; + SourceLocation EndLoc; + +public: + CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, + unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize, + CXXConstructorDecl *constructor, bool initializer, + Expr **constructorArgs, unsigned numConsArgs, + FunctionDecl *operatorDelete, QualType ty, + SourceLocation startLoc, SourceLocation endLoc); + ~CXXNewExpr() { + delete[] SubExprs; + } + + QualType getAllocatedType() const { + assert(getType()->isPointerType()); + return getType()->getAsPointerType()->getPointeeType(); + } + + FunctionDecl *getOperatorNew() const { return OperatorNew; } + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + CXXConstructorDecl *getConstructor() const { return Constructor; } + + bool isArray() const { return Array; } + Expr *getArraySize() { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + const Expr *getArraySize() const { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + + unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + Expr *getPlacementArg(unsigned i) { + assert(i < NumPlacementArgs && "Index out of range"); + return cast<Expr>(SubExprs[Array + i]); + } + const Expr *getPlacementArg(unsigned i) const { + assert(i < NumPlacementArgs && "Index out of range"); + return cast<Expr>(SubExprs[Array + i]); + } + + bool isGlobalNew() const { return GlobalNew; } + bool isParenTypeId() const { return ParenTypeId; } + bool hasInitializer() const { return Initializer; } + + unsigned getNumConstructorArgs() const { return NumConstructorArgs; } + Expr *getConstructorArg(unsigned i) { + assert(i < NumConstructorArgs && "Index out of range"); + return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]); + } + const Expr *getConstructorArg(unsigned i) const { + assert(i < NumConstructorArgs && "Index out of range"); + return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]); + } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator placement_arg_begin() { + return SubExprs + Array; + } + arg_iterator placement_arg_end() { + return SubExprs + Array + getNumPlacementArgs(); + } + const_arg_iterator placement_arg_begin() const { + return SubExprs + Array; + } + const_arg_iterator placement_arg_end() const { + return SubExprs + Array + getNumPlacementArgs(); + } + + arg_iterator constructor_arg_begin() { + return SubExprs + Array + getNumPlacementArgs(); + } + arg_iterator constructor_arg_end() { + return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); + } + const_arg_iterator constructor_arg_begin() const { + return SubExprs + Array + getNumPlacementArgs(); + } + const_arg_iterator constructor_arg_end() const { + return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(StartLoc, EndLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNewExprClass; + } + static bool classof(const CXXNewExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXDeleteExpr - A delete expression for memory deallocation and destructor +/// calls, e.g. "delete[] pArray". +class CXXDeleteExpr : public Expr { + // Is this a forced global delete, i.e. "::delete"? + bool GlobalDelete : 1; + // Is this the array form of delete, i.e. "delete[]"? + bool ArrayForm : 1; + // Points to the operator delete overload that is used. Could be a member. + FunctionDecl *OperatorDelete; + // The pointer expression to be deleted. + Stmt *Argument; + // Location of the expression. + SourceLocation Loc; +public: + CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, + FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) + : Expr(CXXDeleteExprClass, ty, false, false), GlobalDelete(globalDelete), + ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg), + Loc(loc) { } + + bool isGlobalDelete() const { return GlobalDelete; } + bool isArrayForm() const { return ArrayForm; } + + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + + Expr *getArgument() { return cast<Expr>(Argument); } + const Expr *getArgument() const { return cast<Expr>(Argument); } + + virtual SourceRange getSourceRange() const { + return SourceRange(Loc, Argument->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDeleteExprClass; + } + static bool classof(const CXXDeleteExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// \brief Represents the name of a function that has not been +/// resolved to any declaration. +/// +/// Unresolved function names occur when a function name is +/// encountered prior to an open parentheses ('(') in a C++ function +/// call, and the function name itself did not resolve to a +/// declaration. These function names can only be resolved when they +/// form the postfix-expression of a function call, so that +/// argument-dependent lookup finds declarations corresponding to +/// these functions. + +/// @code +/// template<typename T> void f(T x) { +/// g(x); // g is an unresolved function name (that is also a dependent name) +/// } +/// @endcode +class UnresolvedFunctionNameExpr : public Expr { + /// The name that was present in the source + DeclarationName Name; + + /// The location of this name in the source code + SourceLocation Loc; + +public: + UnresolvedFunctionNameExpr(DeclarationName N, QualType T, SourceLocation L) + : Expr(UnresolvedFunctionNameExprClass, T, false, false), Name(N), Loc(L) { } + + /// \brief Retrieves the name that occurred in the source code. + DeclarationName getName() const { return Name; } + + /// getLocation - Retrieves the location in the source code where + /// the name occurred. + SourceLocation getLocation() const { return Loc; } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + UnresolvedFunctionNameExpr* Clone(ASTContext &C) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedFunctionNameExprClass; + } + static bool classof(const UnresolvedFunctionNameExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the +/// implementation of TR1/C++0x type trait templates. +/// Example: +/// __is_pod(int) == true +/// __is_enum(std::string) == false +class UnaryTypeTraitExpr : public Expr { + /// UTT - The trait. + UnaryTypeTrait UTT; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + /// QueriedType - The type we're testing. + QualType QueriedType; + +public: + UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried, + SourceLocation rparen, QualType ty) + : Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()), + UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);} + + UnaryTypeTrait getTrait() const { return UTT; } + + QualType getQueriedType() const { return QueriedType; } + + bool EvaluateTrait() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryTypeTraitExprClass; + } + static bool classof(const UnaryTypeTraitExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// QualifiedDeclRefExpr - A reference to a declared variable, +/// function, enum, etc., that includes a qualification, e.g., +/// "N::foo". +class QualifiedDeclRefExpr : public DeclRefExpr { + /// QualifierRange - The source range that covers the + /// nested-name-specifier. + SourceRange QualifierRange; + + /// \brief The nested-name-specifier that qualifies this declaration + /// name. + NestedNameSpecifier *NNS; + +public: + QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, + bool VD, SourceRange R, NestedNameSpecifier *NNS) + : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), + QualifierRange(R), NNS(NNS) { } + + /// \brief Retrieve the source range of the nested-name-specifier. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { return NNS; } + + virtual SourceRange getSourceRange() const { + return SourceRange(QualifierRange.getBegin(), getLocation()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == QualifiedDeclRefExprClass; + } + static bool classof(const QualifiedDeclRefExpr *) { return true; } +}; + +/// \brief A qualified reference to a name whose declaration cannot +/// yet be resolved. +/// +/// UnresolvedDeclRefExpr is similar to QualifiedDeclRefExpr in that +/// it expresses a qualified reference to a declaration such as +/// X<T>::value. The difference, however, is that an +/// UnresolvedDeclRefExpr node is used only within C++ templates when +/// the qualification (e.g., X<T>::) refers to a dependent type. In +/// this case, X<T>::value cannot resolve to a declaration because the +/// declaration will differ from on instantiation of X<T> to the +/// next. Therefore, UnresolvedDeclRefExpr keeps track of the +/// qualifier (X<T>::) and the name of the entity being referenced +/// ("value"). Such expressions will instantiate to +/// QualifiedDeclRefExprs. +class UnresolvedDeclRefExpr : public Expr { + /// The name of the entity we will be referencing. + DeclarationName Name; + + /// Location of the name of the declaration we're referencing. + SourceLocation Loc; + + /// QualifierRange - The source range that covers the + /// nested-name-specifier. + SourceRange QualifierRange; + + /// \brief The nested-name-specifier that qualifies this unresolved + /// declaration name. + NestedNameSpecifier *NNS; + +public: + UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, + SourceRange R, NestedNameSpecifier *NNS) + : Expr(UnresolvedDeclRefExprClass, T, true, true), + Name(N), Loc(L), QualifierRange(R), NNS(NNS) { } + + /// \brief Retrieve the name that this expression refers to. + DeclarationName getDeclName() const { return Name; } + + /// \brief Retrieve the location of the name within the expression. + SourceLocation getLocation() const { return Loc; } + + /// \brief Retrieve the source range of the nested-name-specifier. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { return NNS; } + + virtual SourceRange getSourceRange() const { + return SourceRange(QualifierRange.getBegin(), getLocation()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedDeclRefExprClass; + } + static bool classof(const UnresolvedDeclRefExpr *) { return true; } + + virtual StmtIterator child_begin(); + virtual StmtIterator child_end(); +}; + +class CXXExprWithTemporaries : public Expr { + Stmt *SubExpr; + + CXXTemporary **Temps; + unsigned NumTemps; + + CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps, + unsigned numtemps); + ~CXXExprWithTemporaries(); + +public: + static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, + CXXTemporary **Temps, + unsigned NumTemps); + void Destroy(ASTContext &C); + + unsigned getNumTemporaries() const { return NumTemps; } + CXXTemporary *getTemporary(unsigned i) { + assert(i < NumTemps && "Index out of range"); + return Temps[i]; + } + const CXXTemporary *getTemporary(unsigned i) const { + assert(i < NumTemps && "Index out of range"); + return Temps[i]; + } + + void removeLastTemporary() { NumTemps--; } + + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + virtual SourceRange getSourceRange() const { return SourceRange(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXExprWithTemporariesClass; + } + static bool classof(const CXXExprWithTemporaries *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// \brief Describes an explicit type conversion that uses functional +/// notion but could not be resolved because one or more arguments are +/// type-dependent. +/// +/// The explicit type conversions expressed by +/// CXXUnresolvedConstructExpr have the form \c T(a1, a2, ..., aN), +/// where \c T is some type and \c a1, a2, ..., aN are values, and +/// either \C T is a dependent type or one or more of the \c a's is +/// type-dependent. For example, this would occur in a template such +/// as: +/// +/// \code +/// template<typename T, typename A1> +/// inline T make_a(const A1& a1) { +/// return T(a1); +/// } +/// \endcode +/// +/// When the returned expression is instantiated, it may resolve to a +/// 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; + + /// \brief The location of the left parentheses ('('). + SourceLocation LParenLoc; + + /// \brief The location of the right parentheses (')'). + SourceLocation RParenLoc; + + /// \brief The number of arguments used to construct the type. + unsigned NumArgs; + + CXXUnresolvedConstructExpr(SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + +public: + static CXXUnresolvedConstructExpr *Create(ASTContext &C, + SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + + /// \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; } + + /// \brief Retrieve the location of the left parentheses ('(') that + /// precedes the argument list. + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + /// \brief Retrieve the location of the right parentheses (')') that + /// follows the argument list. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + /// \brief Retrieve the number of arguments. + unsigned arg_size() const { return NumArgs; } + + typedef Expr** arg_iterator; + arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); } + arg_iterator arg_end() { return arg_begin() + NumArgs; } + + Expr *getArg(unsigned I) { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + 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(); +}; + +/// \brief +class CXXUnresolvedMemberExpr : public Expr { + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. + Stmt *Base; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + /// \brief The member to which this member expression refers, which + /// can be name, overloaded operator, or destructor. + /// FIXME: could also be a template-id, and we might have a + /// nested-name-specifier as well. + DeclarationName Member; + + /// \brief The location of the member name. + SourceLocation MemberLoc; + +public: + CXXUnresolvedMemberExpr(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + DeclarationName Member, + SourceLocation MemberLoc) + : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc), + Member(Member), MemberLoc(MemberLoc) { } + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *E) { Base = E; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMember() const { return Member; } + void setMember(DeclarationName N) { Member = N; } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(Base->getSourceRange().getBegin(), + MemberLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUnresolvedMemberExprClass; + } + static bool classof(const CXXUnresolvedMemberExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h new file mode 100644 index 000000000000..51b99610cd9d --- /dev/null +++ b/include/clang/AST/ExprObjC.h @@ -0,0 +1,494 @@ +//===--- ExprObjC.h - Classes for representing ObjC 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 the ExprObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPROBJC_H +#define LLVM_CLANG_AST_EXPROBJC_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". +class ObjCStringLiteral : public Expr { + Stmt *String; + SourceLocation AtLoc; +public: + ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) + : Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {} + explicit ObjCStringLiteral(EmptyShell Empty) + : Expr(ObjCStringLiteralClass, Empty) {} + + StringLiteral *getString() { return cast<StringLiteral>(String); } + const StringLiteral *getString() const { return cast<StringLiteral>(String); } + void setString(StringLiteral *S) { String = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, String->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCStringLiteralClass; + } + static bool classof(const ObjCStringLiteral *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type +/// and behavior as StringLiteral except that the string initializer is obtained +/// from ASTContext with the encoding type as an argument. +class ObjCEncodeExpr : public Expr { + QualType EncType; + SourceLocation AtLoc, RParenLoc; +public: + ObjCEncodeExpr(QualType T, QualType ET, + SourceLocation at, SourceLocation rp) + : Expr(ObjCEncodeExprClass, T), EncType(ET), AtLoc(at), RParenLoc(rp) {} + + explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} + + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + QualType getEncodedType() const { return EncType; } + void setEncodedType(QualType T) { EncType = T; } + + + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCEncodeExprClass; + } + static bool classof(const ObjCEncodeExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCSelectorExpr used for @selector in Objective-C. +class ObjCSelectorExpr : public Expr { + Selector SelName; + SourceLocation AtLoc, RParenLoc; +public: + ObjCSelectorExpr(QualType T, Selector selInfo, + SourceLocation at, SourceLocation rp) + : Expr(ObjCSelectorExprClass, T), SelName(selInfo), AtLoc(at), RParenLoc(rp){} + explicit ObjCSelectorExpr(EmptyShell Empty) + : Expr(ObjCSelectorExprClass, Empty) {} + + Selector getSelector() const { return SelName; } + void setSelector(Selector S) { SelName = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, RParenLoc); + } + + /// getNumArgs - Return the number of actual arguments to this call. + unsigned getNumArgs() const { return SelName.getNumArgs(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSelectorExprClass; + } + static bool classof(const ObjCSelectorExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used +/// as: @protocol(foo), as in: +/// obj conformsToProtocol:@protocol(foo)] +/// The return type is "Protocol*". +class ObjCProtocolExpr : public Expr { + ObjCProtocolDecl *Protocol; + SourceLocation AtLoc, RParenLoc; +public: + ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, + SourceLocation at, SourceLocation rp) + : Expr(ObjCProtocolExprClass, T), Protocol(protocol), + AtLoc(at), RParenLoc(rp) {} + explicit ObjCProtocolExpr(EmptyShell Empty) + : Expr(ObjCProtocolExprClass, Empty) {} + + ObjCProtocolDecl *getProtocol() const { return Protocol; } + void setProtocol(ObjCProtocolDecl *P) { Protocol = P; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCProtocolExprClass; + } + static bool classof(const ObjCProtocolExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCIvarRefExpr - A reference to an ObjC instance variable. +class ObjCIvarRefExpr : public Expr { + class ObjCIvarDecl *D; + SourceLocation Loc; + Stmt *Base; + bool IsArrow:1; // True if this is "X->F", false if this is "X.F". + bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). + +public: + ObjCIvarRefExpr(ObjCIvarDecl *d, + QualType t, SourceLocation l, Expr *base=0, + bool arrow = false, bool freeIvar = false) : + Expr(ObjCIvarRefExprClass, t), D(d), + Loc(l), Base(base), IsArrow(arrow), + IsFreeIvar(freeIvar) {} + + explicit ObjCIvarRefExpr(EmptyShell Empty) + : Expr(ObjCIvarRefExprClass, Empty) {} + + ObjCIvarDecl *getDecl() { return D; } + const ObjCIvarDecl *getDecl() const { return D; } + void setDecl(ObjCIvarDecl *d) { D = d; } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr * base) { Base = base; } + + bool isArrow() const { return IsArrow; } + bool isFreeIvar() const { return IsFreeIvar; } + void setIsArrow(bool A) { IsArrow = A; } + void setIsFreeIvar(bool A) { IsFreeIvar = A; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + virtual SourceRange getSourceRange() const { + return isFreeIvar() ? SourceRange(Loc) + : SourceRange(getBase()->getLocStart(), Loc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIvarRefExprClass; + } + static bool classof(const ObjCIvarRefExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC +/// property. +/// +class ObjCPropertyRefExpr : public Expr { +private: + ObjCPropertyDecl *AsProperty; + SourceLocation IdLoc; + Stmt *Base; +public: + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + SourceLocation l, Expr *base) + : Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) { + } + + explicit ObjCPropertyRefExpr(EmptyShell Empty) + : Expr(ObjCPropertyRefExprClass, Empty) {} + + ObjCPropertyDecl *getProperty() const { return AsProperty; } + void setProperty(ObjCPropertyDecl *D) { AsProperty = D; } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *base) { Base = base; } + + SourceLocation getLocation() const { return IdLoc; } + void setLocation(SourceLocation L) { IdLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(getBase()->getLocStart(), IdLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCPropertyRefExprClass; + } + static bool classof(const ObjCPropertyRefExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties +/// (i.e. methods following the property naming convention). KVC stands for +/// Key Value Encoding, a generic concept for accessing or setting a 'Key' +/// value for an object. +/// +class ObjCKVCRefExpr : public Expr { + ObjCMethodDecl *Setter; + ObjCMethodDecl *Getter; + SourceLocation Loc; + // FIXME: Swizzle these into a single pointer. + Stmt *Base; + ObjCInterfaceDecl *ClassProp; + SourceLocation ClassLoc; + +public: + ObjCKVCRefExpr(ObjCMethodDecl *getter, + QualType t, + ObjCMethodDecl *setter, + SourceLocation l, Expr *base) + : Expr(ObjCKVCRefExprClass, t), Setter(setter), + Getter(getter), Loc(l), Base(base), ClassProp(0), + ClassLoc(SourceLocation()) { + } + ObjCKVCRefExpr(ObjCMethodDecl *getter, + QualType t, + ObjCMethodDecl *setter, + SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL) + : Expr(ObjCKVCRefExprClass, t), Setter(setter), + Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) { + } + explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){} + + ObjCMethodDecl *getGetterMethod() const { return Getter; } + ObjCMethodDecl *getSetterMethod() const { return Setter; } + ObjCInterfaceDecl *getClassProp() const { return ClassProp; } + void setGetterMethod(ObjCMethodDecl *D) { Getter = D; } + void setSetterMethod(ObjCMethodDecl *D) { Setter = D; } + void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; } + + virtual SourceRange getSourceRange() const { + if (Base) + return SourceRange(getBase()->getLocStart(), Loc); + return SourceRange(ClassLoc, Loc); + } + const Expr *getBase() const { return cast_or_null<Expr>(Base); } + Expr *getBase() { return cast_or_null<Expr>(Base); } + void setBase(Expr *base) { Base = base; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + SourceLocation getClassLoc() const { return ClassLoc; } + void setClassLoc(SourceLocation L) { ClassLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCKVCRefExprClass; + } + static bool classof(const ObjCKVCRefExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class ObjCMessageExpr : public Expr { + // SubExprs - The receiver and arguments of the message expression. + Stmt **SubExprs; + + // NumArgs - The number of arguments (not including the receiver) to the + // message expression. + unsigned NumArgs; + + // A unigue name for this message. + Selector SelName; + + // A method prototype for this message (optional). + // FIXME: Since method decls contain the selector, and most messages have a + // prototype, consider devising a scheme for unifying SelName/MethodProto. + ObjCMethodDecl *MethodProto; + + SourceLocation LBracloc, RBracloc; + + // Constants for indexing into SubExprs. + enum { RECEIVER=0, ARGS_START=1 }; + + // Bit-swizzling flags. + enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 }; + unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; } + +public: + /// This constructor is used to represent class messages where the + /// ObjCInterfaceDecl* of the receiver is not known. + ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, + QualType retType, ObjCMethodDecl *methDecl, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned NumArgs); + + /// This constructor is used to represent class messages where the + /// ObjCInterfaceDecl* of the receiver is known. + // FIXME: clsName should be typed to ObjCInterfaceType + ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + QualType retType, ObjCMethodDecl *methDecl, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned NumArgs); + + // constructor for instance messages. + ObjCMessageExpr(Expr *receiver, Selector selInfo, + QualType retType, ObjCMethodDecl *methDecl, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned NumArgs); + + explicit ObjCMessageExpr(EmptyShell Empty) + : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {} + + ~ObjCMessageExpr() { + delete [] SubExprs; + } + + /// getReceiver - Returns the receiver of the message expression. + /// This can be NULL if the message is for class methods. For + /// class methods, use getClassName. + /// FIXME: need to handle/detect 'super' usage within a class method. + Expr *getReceiver() { + uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; + return (x & Flags) == IsInstMeth ? (Expr*) x : 0; + } + const Expr *getReceiver() const { + return const_cast<ObjCMessageExpr*>(this)->getReceiver(); + } + // FIXME: need setters for different receiver types. + void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; } + Selector getSelector() const { return SelName; } + void setSelector(Selector S) { SelName = S; } + + const ObjCMethodDecl *getMethodDecl() const { return MethodProto; } + ObjCMethodDecl *getMethodDecl() { return MethodProto; } + void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; } + + typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo; + + /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl* + /// and IdentifierInfo* of the invoked class. Both can be NULL if this + /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none + /// was available when this ObjCMessageExpr object was constructed. + ClassInfo getClassInfo() const; + void setClassInfo(const ClassInfo &C); + + /// getClassName - For class methods, this returns the invoked class, + /// and returns NULL otherwise. For instance methods, use getReceiver. + IdentifierInfo *getClassName() const { + return getClassInfo().second; + } + + /// getNumArgs - Return the number of actual arguments to this call. + unsigned getNumArgs() const { return NumArgs; } + void setNumArgs(unsigned nArgs) { + NumArgs = nArgs; + // FIXME: should always allocate SubExprs via the ASTContext's + // allocator. + if (!SubExprs) + SubExprs = new Stmt* [NumArgs + 1]; + } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+ARGS_START]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+ARGS_START]); + } + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + SubExprs[Arg+ARGS_START] = ArgExpr; + } + + SourceLocation getLeftLoc() const { return LBracloc; } + SourceLocation getRightLoc() const { return RBracloc; } + + void setLeftLoc(SourceLocation L) { LBracloc = L; } + void setRightLoc(SourceLocation L) { RBracloc = L; } + + void setSourceRange(SourceRange R) { + LBracloc = R.getBegin(); + RBracloc = R.getEnd(); + } + virtual SourceRange getSourceRange() const { + return SourceRange(LBracloc, RBracloc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCMessageExprClass; + } + static bool classof(const ObjCMessageExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return &SubExprs[ARGS_START]; } + arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; } + const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; } + const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; } +}; + +/// ObjCSuperExpr - Represents the "super" expression in Objective-C, +/// which refers to the object on which the current method is executing. +class ObjCSuperExpr : public Expr { + SourceLocation Loc; +public: + ObjCSuperExpr(SourceLocation L, QualType Type) + : Expr(ObjCSuperExprClass, Type), Loc(L) { } + explicit ObjCSuperExpr(EmptyShell Empty) : Expr(ObjCSuperExprClass, Empty) {} + + SourceLocation getLoc() const { return Loc; } + void setLoc(SourceLocation L) { Loc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSuperExprClass; + } + static bool classof(const ObjCSuperExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h new file mode 100644 index 000000000000..4219bd507a90 --- /dev/null +++ b/include/clang/AST/ExternalASTSource.h @@ -0,0 +1,184 @@ +//===--- ExternalASTSource.h - Abstract External AST 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 ExternalASTSource interface, which enables +// construction of AST nodes from some external source.x +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H +#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +namespace clang { + +class ASTConsumer; +class Decl; +class DeclContext; +class ExternalSemaSource; // layering violation required for downcasting +class Stmt; + +/// \brief The deserialized representation of a set of declarations +/// with the same name that are visible in a given context. +struct VisibleDeclaration { + /// \brief The name of the declarations. + DeclarationName Name; + + /// \brief The ID numbers of all of the declarations with this name. + /// + /// These declarations have not necessarily been de-serialized. + llvm::SmallVector<unsigned, 4> Declarations; +}; + +/// \brief Abstract interface for external sources of AST nodes. +/// +/// External AST sources provide AST nodes constructed from some +/// external source, such as a precompiled header. External AST +/// sources can resolve types and declarations from abstract IDs into +/// actual type and declaration nodes, and read parts of declaration +/// contexts. +class ExternalASTSource { + /// \brief Whether this AST source also provides information for + /// semantic analysis. + bool SemaSource; + + friend class ExternalSemaSource; + +public: + ExternalASTSource() : SemaSource(false) { } + + virtual ~ExternalASTSource(); + + /// \brief Resolve a type ID into a type, potentially building a new + /// type. + virtual QualType GetType(uint32_t ID) = 0; + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + virtual Decl *GetDecl(uint32_t ID) = 0; + + /// \brief Resolve the offset of a statement in the decl stream into a + /// statement. + /// + /// This operation will read a new statement from the external + /// source each time it is called, and is meant to be used via a + /// LazyOffsetPtr. + virtual Stmt *GetDeclStmt(uint64_t Offset) = 0; + + /// \brief Read all of the declarations lexically stored in a + /// declaration context. + /// + /// \param DC The declaration context whose declarations will be + /// read. + /// + /// \param Decls Vector that will contain the declarations loaded + /// from the external source. The caller is responsible for merging + /// these declarations with any declarations already stored in the + /// declaration context. + /// + /// \returns true if there was an error while reading the + /// declarations for this declaration context. + virtual bool ReadDeclsLexicallyInContext(DeclContext *DC, + llvm::SmallVectorImpl<uint32_t> &Decls) = 0; + + /// \brief Read all of the declarations visible from a declaration + /// context. + /// + /// \param DC The declaration context whose visible declarations + /// will be read. + /// + /// \param Decls A vector of visible declaration structures, + /// providing the mapping from each name visible in the declaration + /// context to the declaration IDs of declarations with that name. + /// + /// \returns true if there was an error while reading the + /// declarations for this declaration context. + virtual bool ReadDeclsVisibleInContext(DeclContext *DC, + llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0; + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + virtual void StartTranslationUnit(ASTConsumer *Consumer) { } + + /// \brief Print any statistics that have been gathered regarding + /// the external AST source. + virtual void PrintStats(); +}; + +/// \brief A lazy pointer to an AST node (of base type T) that resides +/// within an external AST source. +/// +/// The AST node is identified within the external AST source by a +/// 63-bit offset, and can be retrieved via an operation on the +/// external AST source itself. +template<typename T, T* (ExternalASTSource::*Get)(uint64_t Offset)> +struct LazyOffsetPtr { + /// \brief Either a pointer to an AST node or the offset within the + /// external AST source where the AST node can be found. + /// + /// If the low bit is clear, a pointer to the AST node. If the low + /// bit is set, the upper 63 bits are the offset. + mutable uint64_t Ptr; + +public: + LazyOffsetPtr() : Ptr(0) { } + + explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { } + explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + } + + LazyOffsetPtr &operator=(T *Ptr) { + this->Ptr = reinterpret_cast<uint64_t>(Ptr); + return *this; + } + + LazyOffsetPtr &operator=(uint64_t Offset) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + else + Ptr = (Offset << 1) | 0x01; + + return *this; + } + + /// \brief Whether this pointer is non-NULL. + /// + /// This operation does not require the AST node to be deserialized. + operator bool() const { return Ptr != 0; } + + /// \brief Whether this pointer is currently stored as an offset. + bool isOffset() const { return Ptr & 0x01; } + + /// \brief Retrieve the pointer to the AST node that this lazy pointer + /// + /// \param Source the external AST source. + /// + /// \returns a pointer to the AST node. + T* get(ExternalASTSource *Source) const { + if (isOffset()) { + assert(Source && + "Cannot deserialize a lazy pointer without an AST source"); + Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); + } + return reinterpret_cast<T*>(Ptr); + } +}; + +/// \brief A lazy pointer to a statement. +typedef LazyOffsetPtr<Stmt, &ExternalASTSource::GetDeclStmt> LazyDeclStmtPtr; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h new file mode 100644 index 000000000000..4eea1031f063 --- /dev/null +++ b/include/clang/AST/NestedNameSpecifier.h @@ -0,0 +1,183 @@ +//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class ASTContext; +class NamespaceDecl; +class IdentifierInfo; +class PrintingPolicy; +class Type; + +/// \brief Represents a C++ nested name specifier, such as +/// "::std::vector<int>::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, identifier +/// (for dependent names), or the global specifier ('::', must be the +/// first specifier). +class NestedNameSpecifier : public llvm::FoldingSetNode { + /// \brief The nested name specifier that precedes this nested name + /// specifier. + /// + /// The pointer is the nested-name-specifier that precedes this + /// one. The integer stores one of the first four values of type + /// SpecifierKind. + llvm::PointerIntPair<NestedNameSpecifier *, 2> Prefix; + + /// \brief The last component in the nested name specifier, which + /// can be an identifier, a declaration, or a type. + /// + /// When the pointer is NULL, this specifier represents the global + /// specifier '::'. Otherwise, the pointer is one of + /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of + /// specifier as encoded within the prefix. + void* Specifier; + +public: + /// \brief The kind of specifier that completes this nested name + /// specifier. + enum SpecifierKind { + /// \brief An identifier, stored as an IdentifierInfo*. + Identifier = 0, + /// \brief A namespace, stored as a Namespace*. + Namespace = 1, + /// \brief A type, stored as a Type*. + TypeSpec = 2, + /// \brief A type that was preceded by the 'template' keyword, + /// stored as a Type*. + TypeSpecWithTemplate = 3, + /// \brief The global specifier '::'. There is no stored value. + Global = 4 + }; + +private: + /// \brief Builds the global specifier. + NestedNameSpecifier() : Prefix(0, 0), Specifier(0) { } + + /// \brief Copy constructor used internally to clone nested name + /// specifiers. + NestedNameSpecifier(const NestedNameSpecifier &Other) + : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), + Specifier(Other.Specifier) { + } + + NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement + + /// \brief Either find or insert the given nested name specifier + /// mockup in the given context. + static NestedNameSpecifier *FindOrInsert(ASTContext &Context, + const NestedNameSpecifier &Mockup); + +public: + /// \brief Builds a specifier combining a prefix and an identifier. + /// + /// The prefix must be dependent, since nested name specifiers + /// referencing an identifier are only permitted when the identifier + /// cannot be resolved. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + IdentifierInfo *II); + + /// \brief Builds a nested name specifier that names a namespace. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceDecl *NS); + + /// \brief Builds a nested name specifier that names a type. + static NestedNameSpecifier *Create(ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, Type *T); + + /// \brief Returns the nested name specifier representing the global + /// scope. + static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context); + + /// \brief Return the prefix of this nested name specifier. + /// + /// The prefix contains all of the parts of the nested name + /// specifier that preced this current specifier. For example, for a + /// nested name specifier that represents "foo::bar::", the current + /// specifier will contain "bar::" and the prefix will contain + /// "foo::". + NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } + + /// \brief Determine what kind of nested name specifier is stored. + SpecifierKind getKind() const { + if (Specifier == 0) + return Global; + return (SpecifierKind)Prefix.getInt(); + } + + /// \brief Retrieve the identifier stored in this nested name + /// specifier. + IdentifierInfo *getAsIdentifier() const { + if (Prefix.getInt() == Identifier) + return (IdentifierInfo *)Specifier; + + return 0; + } + + /// \brief Retrieve the namespace stored in this nested name + /// specifier. + NamespaceDecl *getAsNamespace() const { + if (Prefix.getInt() == Namespace) + return (NamespaceDecl *)Specifier; + + return 0; + } + + /// \brief Retrieve the type stored in this nested name specifier. + Type *getAsType() const { + if (Prefix.getInt() == TypeSpec || + Prefix.getInt() == TypeSpecWithTemplate) + return (Type *)Specifier; + + return 0; + } + + /// \brief Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const; + + /// \brief Print this nested name specifier to the given output + /// stream. + void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Prefix.getOpaqueValue()); + ID.AddPointer(Specifier); + } + + void Destroy(ASTContext &Context); + + /// \brief Dump the nested name specifier to standard output to aid + /// in debugging. + void dump(); +}; + +} + +#endif diff --git a/include/clang/AST/PPCBuiltins.def b/include/clang/AST/PPCBuiltins.def new file mode 100644 index 000000000000..b8c791286e55 --- /dev/null +++ b/include/clang/AST/PPCBuiltins.def @@ -0,0 +1,24 @@ +//===--- PPCBuiltins.def - PowerPC Builtin function database ----*- 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 PowerPC-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: this needs to be the full list supported by GCC. Right now, I'm just +// adding stuff on demand. + +// The format of this database matches clang/AST/Builtins.def. + +// This is just a placeholder, the types and attributes are wrong. +BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc") +// FIXME: Obviously incomplete. + +#undef BUILTIN diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h new file mode 100644 index 000000000000..c669991ccc08 --- /dev/null +++ b/include/clang/AST/ParentMap.h @@ -0,0 +1,50 @@ +//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- 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 ParentMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARENTMAP_H +#define LLVM_CLANG_PARENTMAP_H + +namespace clang { +class Stmt; +class Expr; + +class ParentMap { + void* Impl; +public: + ParentMap(Stmt* ASTRoot); + ~ParentMap(); + + Stmt *getParent(Stmt*) const; + Stmt *getParentIgnoreParens(Stmt *) const; + + const Stmt *getParent(const Stmt* S) const { + return getParent(const_cast<Stmt*>(S)); + } + + const Stmt *getParentIgnoreParens(const Stmt *S) const { + return getParentIgnoreParens(const_cast<Stmt*>(S)); + } + + bool hasParent(Stmt* S) const { + return getParent(S) != 0; + } + + bool isConsumedExpr(Expr *E) const; + + bool isConsumedExpr(const Expr *E) const { + return isConsumedExpr(const_cast<Expr*>(E)); + } +}; + +} // end clang namespace +#endif diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h new file mode 100644 index 000000000000..385602b1fb9c --- /dev/null +++ b/include/clang/AST/PrettyPrinter.h @@ -0,0 +1,86 @@ +//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- 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 PrinterHelper interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H +#define LLVM_CLANG_AST_PRETTY_PRINTER_H + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class Stmt; +class TagDecl; + +class PrinterHelper { +public: + virtual ~PrinterHelper(); + virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0; +}; + +/// \brief Describes how types, statements, expressions, and +/// declarations should be printed. +struct PrintingPolicy { + /// \brief Create a default printing policy for C. + PrintingPolicy() + : Indentation(2), CPlusPlus(false), SuppressSpecifiers(false), + SuppressTag(false), SuppressTagKind(false), Dump(false) { } + + /// \brief The number of spaces to use to indent each line. + unsigned Indentation : 8; + + /// \brief Whether we're printing C++ code (otherwise, we're + /// printing C code). + bool CPlusPlus : 1; + + /// \brief Whether we should suppress printing of the actual specifiers for + /// the given type or declaration. + /// + /// This flag is only used when we are printing declarators beyond + /// the first declarator within a declaration group. For example, given: + /// + /// \code + /// const int *x, *y; + /// \endcode + /// + /// SuppressSpecifiers will be false when printing the + /// declaration for "x", so that we will print "int *x"; it will be + /// \c true when we print "y", so that we suppress printing the + /// "const int" type specifier and instead only print the "*y". + bool SuppressSpecifiers : 1; + + /// \brief Whether type printing should skip printing the actual tag type. + /// + /// This is used when the caller needs to print a tag definition in front + /// of the type, as in constructs like the following: + /// + /// \code + /// typedef struct { int x, y; } Point; + /// \endcode + bool SuppressTag : 1; + + /// \brief If we are printing a tag type, suppresses printing of the + /// kind of tag, e.g., "struct", "union", "enum". + bool SuppressTagKind : 1; + + /// \brief True when we are "dumping" rather than "pretty-printing", + /// where dumping involves printing the internal details of the AST + /// and pretty-printing involves printing something similar to + /// source code. + bool Dump : 1; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h new file mode 100644 index 000000000000..ab184563da23 --- /dev/null +++ b/include/clang/AST/RecordLayout.h @@ -0,0 +1,103 @@ +//===--- RecordLayout.h - Layout information for a struct/union -*- 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 RecordLayout interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LAYOUTINFO_H +#define LLVM_CLANG_AST_LAYOUTINFO_H + +#include "llvm/Support/DataTypes.h" + +namespace clang { + class ASTContext; + class RecordDecl; + +/// ASTRecordLayout - +/// This class contains layout information for one RecordDecl, +/// which is a struct/union/class. The decl represented must be a definition, +/// not a forward declaration. +/// This class is also used to contain layout information for one +/// ObjCInterfaceDecl. FIXME - Find appropriate name. +/// These objects are managed by ASTContext. +class ASTRecordLayout { + uint64_t Size; // Size of record in bits. + uint64_t NextOffset; // Next available offset + uint64_t *FieldOffsets; + unsigned Alignment; // Alignment of record in bits. + unsigned FieldCount; // Number of fields + friend class ASTContext; + + ASTRecordLayout(uint64_t S = 0, unsigned A = 8) + : Size(S), NextOffset(S), Alignment(A), FieldCount(0) {} + ~ASTRecordLayout() { + delete [] FieldOffsets; + } + + /// Initialize record layout. N is the number of fields in this record. + void InitializeLayout(unsigned N) { + FieldCount = N; + FieldOffsets = new uint64_t[N]; + } + + /// Finalize record layout. Adjust record size based on the alignment. + void FinalizeLayout(bool ForceNonEmpty = false) { + // In C++, records cannot be of size 0. + if (ForceNonEmpty && Size == 0) + Size = 8; + // Finally, round the size of the record up to the alignment of the + // record itself. + Size = (Size + (Alignment-1)) & ~(Alignment-1); + } + + void SetFieldOffset(unsigned FieldNo, uint64_t Offset) { + assert (FieldNo < FieldCount && "Invalid Field No"); + FieldOffsets[FieldNo] = Offset; + } + + void SetAlignment(unsigned A) { Alignment = A; } + + /// LayoutField - Field layout. StructPacking is the specified + /// packing alignment (maximum alignment) in bits to use for the + /// structure, or 0 if no packing alignment is specified. + void LayoutField(const FieldDecl *FD, unsigned FieldNo, + bool IsUnion, unsigned StructPacking, + ASTContext &Context); + + ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT + void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT +public: + + /// getAlignment - Get the record alignment in bits. + unsigned getAlignment() const { return Alignment; } + + /// getSize - Get the record size in bits. + uint64_t getSize() const { return Size; } + + /// getFieldCount - Get the number of fields in the layout. + unsigned getFieldCount() const { return FieldCount; } + + /// getFieldOffset - Get the offset of the given field index, in + /// bits. + uint64_t getFieldOffset(unsigned FieldNo) const { + assert (FieldNo < FieldCount && "Invalid Field No"); + return FieldOffsets[FieldNo]; + } + + /// getNextOffset - Get the next available (unused) offset in the + /// structure, in bits. + uint64_t getNextOffset() const { + return NextOffset; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h new file mode 100644 index 000000000000..3656333d7423 --- /dev/null +++ b/include/clang/AST/Stmt.h @@ -0,0 +1,1223 @@ +//===--- Stmt.h - Classes for representing statements -----------*- 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 Stmt interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_H +#define LLVM_CLANG_AST_STMT_H + +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/StmtIterator.h" +#include "clang/AST/DeclGroup.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator.h" +#include "clang/AST/ASTContext.h" +#include <string> +using llvm::dyn_cast_or_null; + +namespace clang { + class ASTContext; + class Expr; + class Decl; + class ParmVarDecl; + class QualType; + class IdentifierInfo; + class SourceManager; + class StringLiteral; + class SwitchStmt; + + //===----------------------------------------------------------------------===// + // ExprIterator - Iterators for iterating over Stmt* arrays that contain + // only Expr*. This is needed because AST nodes use Stmt* arrays to store + // references to children (to be compatible with StmtIterator). + //===----------------------------------------------------------------------===// + + class Stmt; + class Expr; + + class ExprIterator { + Stmt** I; + public: + ExprIterator(Stmt** i) : I(i) {} + ExprIterator() : I(0) {} + ExprIterator& operator++() { ++I; return *this; } + ExprIterator operator-(size_t i) { return I-i; } + ExprIterator operator+(size_t i) { return I+i; } + Expr* operator[](size_t idx); + // FIXME: Verify that this will correctly return a signed distance. + signed operator-(const ExprIterator& R) const { return I - R.I; } + Expr* operator*() const; + Expr* operator->() const; + bool operator==(const ExprIterator& R) const { return I == R.I; } + bool operator!=(const ExprIterator& R) const { return I != R.I; } + bool operator>(const ExprIterator& R) const { return I > R.I; } + bool operator>=(const ExprIterator& R) const { return I >= R.I; } + }; + + class ConstExprIterator { + Stmt* const * I; + public: + ConstExprIterator(Stmt* const* i) : I(i) {} + ConstExprIterator() : I(0) {} + ConstExprIterator& operator++() { ++I; return *this; } + ConstExprIterator operator+(size_t i) { return I+i; } + ConstExprIterator operator-(size_t i) { return I-i; } + const Expr * operator[](size_t idx) const; + signed operator-(const ConstExprIterator& R) const { return I - R.I; } + const Expr * operator*() const; + const Expr * operator->() const; + bool operator==(const ConstExprIterator& R) const { return I == R.I; } + bool operator!=(const ConstExprIterator& R) const { return I != R.I; } + bool operator>(const ConstExprIterator& R) const { return I > R.I; } + bool operator>=(const ConstExprIterator& R) const { return I >= R.I; } + }; + +//===----------------------------------------------------------------------===// +// AST classes for statements. +//===----------------------------------------------------------------------===// + +/// Stmt - This represents one statement. +/// +class Stmt { +public: + enum StmtClass { + NoStmtClass = 0, +#define STMT(CLASS, PARENT) CLASS##Class, +#define FIRST_STMT(CLASS) firstStmtConstant = CLASS##Class, +#define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class, +#define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class, +#define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class +#include "clang/AST/StmtNodes.def" +}; +private: + const StmtClass sClass; + + // Make vanilla 'new' and 'delete' illegal for Stmts. +protected: + void* operator new(size_t bytes) throw() { + assert(0 && "Stmts cannot be allocated with regular 'new'."); + return 0; + } + void operator delete(void* data) throw() { + assert(0 && "Stmts cannot be released with regular 'delete'."); + } + +public: + // Only allow allocation of Stmts using the allocator in ASTContext + // or by doing a placement new. + void* operator new(size_t bytes, ASTContext& C, + unsigned alignment = 16) throw() { + return ::operator new(bytes, C, alignment); + } + + void* operator new(size_t bytes, ASTContext* C, + unsigned alignment = 16) throw() { + return ::operator new(bytes, *C, alignment); + } + + void* operator new(size_t bytes, void* mem) throw() { + return mem; + } + + void operator delete(void*, ASTContext&, unsigned) throw() { } + void operator delete(void*, ASTContext*, unsigned) throw() { } + void operator delete(void*, std::size_t) throw() { } + void operator delete(void*, void*) throw() { } + +public: + /// \brief A placeholder type used to construct an empty shell of a + /// type, that will be filled in later (e.g., by some + /// de-serialization). + struct EmptyShell { }; + +protected: + /// DestroyChildren - Invoked by destructors of subclasses of Stmt to + /// recursively release child AST nodes. + void DestroyChildren(ASTContext& Ctx); + + /// \brief Construct an empty statement. + explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC) { + if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); + } + +public: + Stmt(StmtClass SC) : sClass(SC) { + if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); + } + virtual ~Stmt() {} + + virtual void Destroy(ASTContext &Ctx); + + StmtClass getStmtClass() const { return 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; + SourceLocation getLocStart() const { return getSourceRange().getBegin(); } + SourceLocation getLocEnd() const { return getSourceRange().getEnd(); } + + // global temp stats (until we have a per-module visitor) + static void addStmtClass(const StmtClass s); + static bool CollectingStats(bool enable=false); + static void PrintStats(); + + /// dump - This does a local dump of the specified AST fragment. It dumps the + /// specified node and a few nodes underneath it, but not the whole subtree. + /// This is useful in a debugger. + void dump() const; + void dump(SourceManager &SM) const; + + /// dumpAll - This does a dump of the specified AST fragment and all subtrees. + void dumpAll() const; + void dumpAll(SourceManager &SM) const; + + /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST + /// back to its original source language syntax. + void dumpPretty(ASTContext& Context) const; + void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper = 0, + const PrintingPolicy &Policy = PrintingPolicy(), + unsigned Indentation = 0) const { + printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation); + } + void printPretty(llvm::raw_ostream &OS, ASTContext& Context, + PrinterHelper *Helper = 0, + const PrintingPolicy &Policy = PrintingPolicy(), + unsigned Indentation = 0) const; + + /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only + /// works on systems with GraphViz (Mac OS X) or dot+gv installed. + void viewAST() const; + + // Implement isa<T> support. + static bool classof(const Stmt *) { return true; } + + /// hasImplicitControlFlow - Some statements (e.g. short circuited operations) + /// contain implicit control-flow in the order their subexpressions + /// are evaluated. This predicate returns true if this statement has + /// such implicit control-flow. Such statements are also specially handled + /// 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. + typedef StmtIterator child_iterator; + typedef ConstStmtIterator const_child_iterator; + + virtual child_iterator child_begin() = 0; + virtual child_iterator child_end() = 0; + + const_child_iterator child_begin() const { + return const_child_iterator(const_cast<Stmt*>(this)->child_begin()); + } + + const_child_iterator child_end() const { + return const_child_iterator(const_cast<Stmt*>(this)->child_end()); + } +}; + +/// DeclStmt - Adaptor class for mixing declarations with statements and +/// expressions. For example, CompoundStmt mixes statements, expressions +/// and declarations (variables, types). Another example is ForStmt, where +/// the first statement can be an expression or a declaration. +/// +class DeclStmt : public Stmt { + DeclGroupRef DG; + SourceLocation StartLoc, EndLoc; +public: + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, + SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), + StartLoc(startLoc), EndLoc(endLoc) {} + + /// \brief Build an empty declaration statement. + explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } + + virtual void Destroy(ASTContext& Ctx); + + /// isSingleDecl - This method returns true if this DeclStmt refers + /// to a single Decl. + bool isSingleDecl() const { + return DG.isSingleDecl(); + } + + const Decl *getSingleDecl() const { return DG.getSingleDecl(); } + Decl *getSingleDecl() { return DG.getSingleDecl(); } + + const DeclGroupRef getDeclGroup() const { return DG; } + DeclGroupRef getDeclGroup() { return DG; } + void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } + + SourceLocation getStartLoc() const { return StartLoc; } + void setStartLoc(SourceLocation L) { StartLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + + SourceRange getSourceRange() const { + return SourceRange(StartLoc, EndLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclStmtClass; + } + static bool classof(const DeclStmt *) { return true; } + + // Iterators over subexpressions. + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + typedef DeclGroupRef::iterator decl_iterator; + typedef DeclGroupRef::const_iterator const_decl_iterator; + + decl_iterator decl_begin() { return DG.begin(); } + decl_iterator decl_end() { return DG.end(); } + const_decl_iterator decl_begin() const { return DG.begin(); } + const_decl_iterator decl_end() const { return DG.end(); } +}; + +/// NullStmt - This is the null statement ";": C99 6.8.3p3. +/// +class NullStmt : public Stmt { + SourceLocation SemiLoc; +public: + NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {} + + /// \brief Build an empty null statement. + explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { } + + NullStmt* Clone(ASTContext &C) const; + + SourceLocation getSemiLoc() const { return SemiLoc; } + void setSemiLoc(SourceLocation L) { SemiLoc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NullStmtClass; + } + static bool classof(const NullStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// 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) { + if (NumStmts == 0) { + Body = 0; + return; + } + + Body = new (C) Stmt*[NumStmts]; + memcpy(Body, StmtStart, numStmts * sizeof(*Body)); + } + + // \brief Build an empty compound statement. + explicit CompoundStmt(EmptyShell Empty) + : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { } + + void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); + + bool body_empty() const { return NumStmts == 0; } + unsigned size() const { return NumStmts; } + + 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; } + + 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; } + + typedef std::reverse_iterator<body_iterator> reverse_body_iterator; + reverse_body_iterator body_rbegin() { + return reverse_body_iterator(body_end()); + } + reverse_body_iterator body_rend() { + return reverse_body_iterator(body_begin()); + } + + typedef std::reverse_iterator<const_body_iterator> + const_reverse_body_iterator; + + const_reverse_body_iterator body_rbegin() const { + return const_reverse_body_iterator(body_end()); + } + + const_reverse_body_iterator body_rend() const { + return const_reverse_body_iterator(body_begin()); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(LBracLoc, RBracLoc); + } + + SourceLocation getLBracLoc() const { return LBracLoc; } + void setLBracLoc(SourceLocation L) { LBracLoc = L; } + SourceLocation getRBracLoc() const { return RBracLoc; } + void setRBracLoc(SourceLocation L) { RBracLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundStmtClass; + } + static bool classof(const CompoundStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +// SwitchCase is the base class for CaseStmt and DefaultStmt, +class SwitchCase : public Stmt { +protected: + // A pointer to the following CaseStmt or DefaultStmt class, + // used by SwitchStmt. + SwitchCase *NextSwitchCase; + + SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {} + +public: + const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } + + SwitchCase *getNextSwitchCase() { return NextSwitchCase; } + + void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } + + Stmt *getSubStmt() { return v_getSubStmt(); } + + virtual SourceRange getSourceRange() const { return SourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass || + T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const SwitchCase *) { return true; } +protected: + virtual Stmt* v_getSubStmt() = 0; +}; + +class CaseStmt : public SwitchCase { + enum { SUBSTMT, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for + // GNU "case 1 ... 4" extension + SourceLocation CaseLoc; + SourceLocation EllipsisLoc; + SourceLocation ColonLoc; + + virtual Stmt* v_getSubStmt() { return getSubStmt(); } +public: + CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, + SourceLocation ellipsisLoc, SourceLocation colonLoc) + : SwitchCase(CaseStmtClass) { + SubExprs[SUBSTMT] = 0; + SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); + SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); + CaseLoc = caseLoc; + EllipsisLoc = ellipsisLoc; + ColonLoc = colonLoc; + } + + /// \brief Build an empty switch case statement. + explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { } + + SourceLocation getCaseLoc() const { return CaseLoc; } + void setCaseLoc(SourceLocation L) { CaseLoc = L; } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } + Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } + Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + + const Expr *getLHS() const { + return reinterpret_cast<const Expr*>(SubExprs[LHS]); + } + const Expr *getRHS() const { + return reinterpret_cast<const Expr*>(SubExprs[RHS]); + } + const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } + + void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } + void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } + void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } + + + virtual SourceRange getSourceRange() const { + // Handle deeply nested case statements with iteration instead of recursion. + const CaseStmt *CS = this; + while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) + CS = CS2; + + return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass; + } + static bool classof(const CaseStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +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), + ColonLoc(CL) {} + + /// \brief Build an empty default statement. + explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { } + + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceLocation getDefaultLoc() const { return DefaultLoc; } + void setDefaultLoc(SourceLocation L) { DefaultLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(DefaultLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const DefaultStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class LabelStmt : public Stmt { + IdentifierInfo *Label; + Stmt *SubStmt; + SourceLocation IdentLoc; +public: + LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) + : Stmt(LabelStmtClass), Label(label), + SubStmt(substmt), IdentLoc(IL) {} + + // \brief Build an empty label statement. + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } + + SourceLocation getIdentLoc() const { return IdentLoc; } + IdentifierInfo *getID() const { return Label; } + void setID(IdentifierInfo *II) { Label = II; } + 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 { + return SourceRange(IdentLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == LabelStmtClass; + } + static bool classof(const LabelStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// IfStmt - This represents an if/then/else. +/// +class IfStmt : public Stmt { + enum { COND, THEN, ELSE, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation IfLoc; + SourceLocation ElseLoc; +public: + IfStmt(SourceLocation IL, Expr *cond, Stmt *then, + SourceLocation EL = SourceLocation(), Stmt *elsev = 0) + : Stmt(IfStmtClass) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[THEN] = then; + SubExprs[ELSE] = elsev; + IfLoc = IL; + ElseLoc = EL; + } + + /// \brief Build an empty if/then/else statement + explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + const Stmt *getThen() const { return SubExprs[THEN]; } + void setThen(Stmt *S) { SubExprs[THEN] = S; } + const Stmt *getElse() const { return SubExprs[ELSE]; } + void setElse(Stmt *S) { SubExprs[ELSE] = S; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Stmt *getThen() { return SubExprs[THEN]; } + Stmt *getElse() { return SubExprs[ELSE]; } + + SourceLocation getIfLoc() const { return IfLoc; } + void setIfLoc(SourceLocation L) { IfLoc = L; } + SourceLocation getElseLoc() const { return ElseLoc; } + void setElseLoc(SourceLocation L) { ElseLoc = L; } + + virtual SourceRange getSourceRange() const { + if (SubExprs[ELSE]) + return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); + else + return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IfStmtClass; + } + static bool classof(const IfStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// SwitchStmt - This represents a 'switch' stmt. +/// +class SwitchStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + // This points to a linked list of case and default statements. + SwitchCase *FirstCase; + SourceLocation SwitchLoc; +public: + SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = NULL; + } + + /// \brief Build a empty switch statement. + explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Stmt *getBody() const { return SubExprs[BODY]; } + const SwitchCase *getSwitchCaseList() const { return FirstCase; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + SwitchCase *getSwitchCaseList() { return FirstCase; } + void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } + + SourceLocation getSwitchLoc() const { return SwitchLoc; } + void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + + void setBody(Stmt *S, SourceLocation SL) { + SubExprs[BODY] = S; + SwitchLoc = SL; + } + void addSwitchCase(SwitchCase *SC) { + assert(!SC->getNextSwitchCase() && "case/default already added to a switch"); + SC->setNextSwitchCase(FirstCase); + FirstCase = SC; + } + virtual SourceRange getSourceRange() const { + return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); + } + 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(); +}; + + +/// WhileStmt - This represents a 'while' stmt. +/// +class WhileStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation WhileLoc; +public: + WhileStmt(Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + WhileLoc = WL; + } + + /// \brief Build an empty while statement. + explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == WhileStmtClass; + } + static bool classof(const WhileStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// DoStmt - This represents a 'do/while' stmt. +/// +class DoStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation DoLoc; + SourceLocation WhileLoc; + +public: + DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL) + : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + DoLoc = DL; + WhileLoc = WL; + } + + /// \brief Build an empty do-while statement. + explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getDoLoc() const { return DoLoc; } + void setDoLoc(SourceLocation L) { DoLoc = L; } + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(DoLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DoStmtClass; + } + static bool classof(const DoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of +/// the init/cond/inc parts of the ForStmt will be null if they were not +/// specified in the source. +/// +class ForStmt : public Stmt { + enum { INIT, COND, INC, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + SourceLocation ForLoc; + SourceLocation LParenLoc, RParenLoc; + +public: + ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL, + SourceLocation LP, SourceLocation RP) + : Stmt(ForStmtClass) { + SubExprs[INIT] = Init; + SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); + SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[BODY] = Body; + ForLoc = FL; + LParenLoc = LP; + RParenLoc = RP; + } + + /// \brief Build an empty for statement. + explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } + + Stmt *getInit() { return SubExprs[INIT]; } + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getInit() const { return SubExprs[INIT]; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setInit(Stmt *S) { SubExprs[INIT] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation L) { ForLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ForStmtClass; + } + static bool classof(const ForStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// GotoStmt - This represents a direct goto. +/// +class GotoStmt : public Stmt { + LabelStmt *Label; + SourceLocation GotoLoc; + SourceLocation LabelLoc; +public: + GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) + : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + + /// \brief Build an empty goto statement. + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + + LabelStmt *getLabel() const { return Label; } + void setLabel(LabelStmt *S) { Label = S; } + + 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 { + return SourceRange(GotoLoc, LabelLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GotoStmtClass; + } + static bool classof(const GotoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// IndirectGotoStmt - This represents an indirect goto. +/// +class IndirectGotoStmt : public Stmt { + SourceLocation GotoLoc; + SourceLocation StarLoc; + Stmt *Target; +public: + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, + Expr *target) + : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), + Target((Stmt*)target) {} + + /// \brief Build an empty indirect goto statement. + explicit IndirectGotoStmt(EmptyShell Empty) + : Stmt(IndirectGotoStmtClass, Empty) { } + + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoLoc; } + void setStarLoc(SourceLocation L) { StarLoc = L; } + SourceLocation getStarLoc() const { return StarLoc; } + + Expr *getTarget(); + const Expr *getTarget() const; + void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } + + virtual SourceRange getSourceRange() const { + return SourceRange(GotoLoc, Target->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IndirectGotoStmtClass; + } + static bool classof(const IndirectGotoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ContinueStmt - This represents a continue. +/// +class ContinueStmt : public Stmt { + SourceLocation ContinueLoc; +public: + ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} + + /// \brief Build an empty continue statement. + explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } + + SourceLocation getContinueLoc() const { return ContinueLoc; } + void setContinueLoc(SourceLocation L) { ContinueLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(ContinueLoc); + } + + ContinueStmt* Clone(ASTContext &C) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ContinueStmtClass; + } + static bool classof(const ContinueStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// BreakStmt - This represents a break. +/// +class BreakStmt : public Stmt { + SourceLocation BreakLoc; +public: + BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {} + + /// \brief Build an empty break statement. + explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } + + SourceLocation getBreakLoc() const { return BreakLoc; } + void setBreakLoc(SourceLocation L) { BreakLoc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); } + + BreakStmt* Clone(ASTContext &C) const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BreakStmtClass; + } + static bool classof(const BreakStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ReturnStmt - This represents a return, optionally of an expression: +/// return; +/// return 4; +/// +/// Note that GCC allows return with no argument in a function declared to +/// return a value, and it allows returning a value in functions declared to +/// return void. We explicitly model this in the AST, which means you can't +/// depend on the return type of the function and the presence of an argument. +/// +class ReturnStmt : public Stmt { + Stmt *RetExpr; + SourceLocation RetLoc; +public: + ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass), + RetExpr((Stmt*) E), RetLoc(RL) {} + + /// \brief Build an empty return expression. + explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } + + const Expr *getRetValue() const; + Expr *getRetValue(); + void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + + SourceLocation getReturnLoc() const { return RetLoc; } + void setReturnLoc(SourceLocation L) { RetLoc = L; } + + virtual SourceRange getSourceRange() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ReturnStmtClass; + } + static bool classof(const ReturnStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// AsmStmt - This represents a GNU inline-assembly statement extension. +/// +class AsmStmt : public Stmt { + SourceLocation AsmLoc, RParenLoc; + StringLiteral *AsmStr; + + bool IsSimple; + bool IsVolatile; + + unsigned NumOutputs; + unsigned NumInputs; + + llvm::SmallVector<std::string, 4> Names; + llvm::SmallVector<StringLiteral*, 4> Constraints; + llvm::SmallVector<Stmt*, 4> Exprs; + + llvm::SmallVector<StringLiteral*, 4> Clobbers; +public: + AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, + unsigned numoutputs, unsigned numinputs, + std::string *names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc); + + /// \brief Build an empty inline-assembly statement. + explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty) { } + + SourceLocation getAsmLoc() const { return AsmLoc; } + void setAsmLoc(SourceLocation L) { AsmLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + bool isVolatile() const { return IsVolatile; } + void setVolatile(bool V) { IsVolatile = V; } + bool isSimple() const { return IsSimple; } + void setSimple(bool V) { IsSimple = false; } + + //===--- Asm String Analysis ---===// + + const StringLiteral *getAsmString() const { return AsmStr; } + StringLiteral *getAsmString() { return AsmStr; } + void setAsmString(StringLiteral *E) { AsmStr = E; } + + /// AsmStringPiece - this is part of a decomposed asm string specification + /// (for use with the AnalyzeAsmString function below). An asm string is + /// considered to be a concatenation of these parts. + class AsmStringPiece { + public: + enum Kind { + String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". + Operand // Operand reference, with optional modifier %c4. + }; + private: + Kind MyKind; + std::string Str; + unsigned OperandNo; + public: + AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} + AsmStringPiece(unsigned OpNo, char Modifier) + : MyKind(Operand), Str(), OperandNo(OpNo) { + Str += Modifier; + } + + bool isString() const { return MyKind == String; } + bool isOperand() const { return MyKind == Operand; } + + const std::string &getString() const { + assert(isString()); + return Str; + } + + unsigned getOperandNo() const { + assert(isOperand()); + return OperandNo; + } + + /// getModifier - Get the modifier for this operand, if present. This + /// returns '\0' if there was no modifier. + char getModifier() const { + assert(isOperand()); + return Str[0]; + } + }; + + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing + /// it into pieces. If the asm string is erroneous, emit errors and return + /// true, otherwise return false. This handles canonicalization and + /// translation of strings from GCC syntax to LLVM IR syntax, and handles + //// flattening of named references like %[foo] to Operand AsmStringPiece's. + unsigned AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece> &Pieces, + ASTContext &C, unsigned &DiagOffs) const; + + + //===--- Output operands ---===// + + unsigned getNumOutputs() const { return NumOutputs; } + + const std::string &getOutputName(unsigned i) const { + return Names[i]; + } + + /// getOutputConstraint - Return the constraint string for the specified + /// output operand. All output constraints are known to be non-empty (either + /// '=' or '+'). + std::string getOutputConstraint(unsigned i) const; + + const StringLiteral *getOutputConstraintLiteral(unsigned i) const { + return Constraints[i]; + } + StringLiteral *getOutputConstraintLiteral(unsigned i) { + return Constraints[i]; + } + + + Expr *getOutputExpr(unsigned i); + + const Expr *getOutputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getOutputExpr(i); + } + + /// isOutputPlusConstraint - Return true if the specified output constraint + /// is a "+" constraint (which is both an input and an output) or false if it + /// is an "=" constraint (just an output). + bool isOutputPlusConstraint(unsigned i) const { + return getOutputConstraint(i)[0] == '+'; + } + + /// getNumPlusOperands - Return the number of output operands that have a "+" + /// constraint. + unsigned getNumPlusOperands() const; + + //===--- Input operands ---===// + + unsigned getNumInputs() const { return NumInputs; } + + const std::string &getInputName(unsigned i) const { + return Names[i + NumOutputs]; + } + + /// getInputConstraint - Return the specified input constraint. Unlike output + /// constraints, these can be empty. + std::string getInputConstraint(unsigned i) const; + + const StringLiteral *getInputConstraintLiteral(unsigned i) const { + return Constraints[i + NumOutputs]; + } + StringLiteral *getInputConstraintLiteral(unsigned i) { + return Constraints[i + NumOutputs]; + } + + + Expr *getInputExpr(unsigned i); + + const Expr *getInputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getInputExpr(i); + } + + void setOutputsAndInputs(unsigned NumOutputs, + unsigned NumInputs, + const std::string *Names, + StringLiteral **Constraints, + Stmt **Exprs); + + //===--- Other ---===// + + /// getNamedOperand - Given a symbolic operand reference like %[foo], + /// translate this into a numeric value needed to reference the same operand. + /// This returns -1 if the operand name is invalid. + int getNamedOperand(const std::string &SymbolicName) const; + + + + unsigned getNumClobbers() const { return Clobbers.size(); } + StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } + const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } + void setClobbers(StringLiteral **Clobbers, unsigned NumClobbers); + + virtual SourceRange getSourceRange() const { + return SourceRange(AsmLoc, RParenLoc); + } + + static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;} + static bool classof(const AsmStmt *) { return true; } + + // Input expr iterators. + + typedef ExprIterator inputs_iterator; + typedef ConstExprIterator const_inputs_iterator; + + inputs_iterator begin_inputs() { + return Exprs.data() + NumOutputs; + } + + inputs_iterator end_inputs() { + return Exprs.data() + NumOutputs + NumInputs; + } + + const_inputs_iterator begin_inputs() const { + return Exprs.data() + NumOutputs; + } + + const_inputs_iterator end_inputs() const { + return Exprs.data() + NumOutputs + NumInputs; + } + + // Output expr iterators. + + typedef ExprIterator outputs_iterator; + typedef ConstExprIterator const_outputs_iterator; + + outputs_iterator begin_outputs() { + return Exprs.data(); + } + outputs_iterator end_outputs() { + return Exprs.data() + NumOutputs; + } + + const_outputs_iterator begin_outputs() const { + return Exprs.data(); + } + const_outputs_iterator end_outputs() const { + return Exprs.data() + NumOutputs; + } + + // Input name iterator. + + const std::string *begin_output_names() const { + return &Names[0]; + } + + const std::string *end_output_names() const { + return &Names[0] + NumOutputs; + } + + // Child iterators + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h new file mode 100644 index 000000000000..2338f1457a84 --- /dev/null +++ b/include/clang/AST/StmtCXX.h @@ -0,0 +1,100 @@ +//===--- StmtCXX.h - Classes for representing C++ statements ----*- 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 C++ statement AST node classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTCXX_H +#define LLVM_CLANG_AST_STMTCXX_H + +#include "clang/AST/Stmt.h" + +namespace clang { + +class VarDecl; + +/// CXXCatchStmt - This represents a C++ catch block. +/// +class CXXCatchStmt : public Stmt { + SourceLocation CatchLoc; + /// The exception-declaration of the type. + VarDecl *ExceptionDecl; + /// The handler block. + Stmt *HandlerBlock; + +public: + CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) + : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), + HandlerBlock(handlerBlock) {} + + virtual void Destroy(ASTContext& Ctx); + + virtual SourceRange getSourceRange() const { + return SourceRange(CatchLoc, HandlerBlock->getLocEnd()); + } + + SourceLocation getCatchLoc() const { return CatchLoc; } + VarDecl *getExceptionDecl() { return ExceptionDecl; } + QualType getCaughtType(); + Stmt *getHandlerBlock() { return HandlerBlock; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXCatchStmtClass; + } + static bool classof(const CXXCatchStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CXXTryStmt - A C++ try block, including all handlers. +/// +class CXXTryStmt : public Stmt { + SourceLocation TryLoc; + // First place is the guarded CompoundStatement. Subsequent are the handlers. + // More than three handlers should be rare. + llvm::SmallVector<Stmt*, 4> Stmts; + +public: + CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers); + + virtual SourceRange getSourceRange() const { + return SourceRange(TryLoc, Stmts.back()->getLocEnd()); + } + + SourceLocation getTryLoc() const { return TryLoc; } + + CompoundStmt *getTryBlock() { return llvm::cast<CompoundStmt>(Stmts[0]); } + const CompoundStmt *getTryBlock() const { + return llvm::cast<CompoundStmt>(Stmts[0]); + } + + unsigned getNumHandlers() const { return Stmts.size() - 1; } + CXXCatchStmt *getHandler(unsigned i) { + return llvm::cast<CXXCatchStmt>(Stmts[i + 1]); + } + const CXXCatchStmt *getHandler(unsigned i) const { + return llvm::cast<CXXCatchStmt>(Stmts[i + 1]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTryStmtClass; + } + static bool classof(const CXXTryStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +} // end namespace clang + +#endif diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h new file mode 100644 index 000000000000..1bfac6a9587e --- /dev/null +++ b/include/clang/AST/StmtGraphTraits.h @@ -0,0 +1,83 @@ +//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- 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 a template specialization of llvm::GraphTraits to +// treat ASTs (Stmt*) as graphs +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H +#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H + +#include "clang/AST/Stmt.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" + +namespace llvm { + +//template <typename T> struct GraphTraits; + + +template <> struct GraphTraits<clang::Stmt*> { + typedef clang::Stmt NodeType; + typedef clang::Stmt::child_iterator ChildIteratorType; + typedef llvm::df_iterator<clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(clang::Stmt* S) { + return df_end(S); + } +}; + + +template <> struct GraphTraits<const clang::Stmt*> { + typedef const clang::Stmt NodeType; + typedef clang::Stmt::const_child_iterator ChildIteratorType; + typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(const clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(const clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(const clang::Stmt* S) { + return df_end(S); + } +}; + + +} // end namespace llvm + +#endif diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h new file mode 100644 index 000000000000..35bd5ada0256 --- /dev/null +++ b/include/clang/AST/StmtIterator.h @@ -0,0 +1,145 @@ +//===--- StmtIterator.h - Iterators for Statements ------------------------===// +// +// 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 StmtIterator and ConstStmtIterator classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_ITR_H +#define LLVM_CLANG_AST_STMT_ITR_H + +#include "llvm/ADT/iterator.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class Stmt; +class Decl; +class VariableArrayType; + +class StmtIteratorBase { +protected: + enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3, + Flags = 0x3 }; + + union { Stmt** stmt; Decl* decl; Decl** DGI; }; + uintptr_t RawVAPtr; + Decl** DGE; + + bool inDecl() const { + return (RawVAPtr & Flags) == DeclMode; + } + + bool inDeclGroup() const { + return (RawVAPtr & Flags) == DeclGroupMode; + } + + bool inSizeOfTypeVA() const { + return (RawVAPtr & Flags) == SizeOfTypeVAMode; + } + + bool inStmt() const { + return (RawVAPtr & Flags) == 0; + } + + VariableArrayType* getVAPtr() const { + return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags); + } + + void setVAPtr(VariableArrayType* P) { + assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); + RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); + } + + void NextDecl(bool ImmediateAdvance = true); + bool HandleDecl(Decl* D); + void NextVA(); + + Stmt*& GetDeclExpr() const; + + StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {} + StmtIteratorBase(Decl* d); + StmtIteratorBase(VariableArrayType* t); + StmtIteratorBase(Decl** dgi, Decl** dge); + StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {} +}; + + +template <typename DERIVED, typename REFERENCE> +class StmtIteratorImpl : public StmtIteratorBase, + public std::iterator<std::forward_iterator_tag, + REFERENCE, ptrdiff_t, + REFERENCE, REFERENCE> { +protected: + StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {} +public: + StmtIteratorImpl() {} + StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {} + StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {} + StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {} + StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {} + + DERIVED& operator++() { + if (inDecl() || inDeclGroup()) { + if (getVAPtr()) NextVA(); + else NextDecl(); + } + else if (inSizeOfTypeVA()) + NextVA(); + else + ++stmt; + + return static_cast<DERIVED&>(*this); + } + + DERIVED operator++(int) { + DERIVED tmp = static_cast<DERIVED&>(*this); + operator++(); + return tmp; + } + + bool operator==(const DERIVED& RHS) const { + return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr; + } + + bool operator!=(const DERIVED& RHS) const { + return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr; + } + + REFERENCE operator*() const { + return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr()); + } + + REFERENCE operator->() const { return operator*(); } +}; + +struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { + explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} + + StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {} + StmtIterator(Decl** dgi, Decl** dge) + : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} + + StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} + StmtIterator(Decl* D) : StmtIteratorImpl<StmtIterator,Stmt*&>(D) {} +}; + +struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, + const Stmt*> { + explicit ConstStmtIterator() : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {} + + ConstStmtIterator(const StmtIterator& RHS) : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def new file mode 100644 index 000000000000..ab6524663d63 --- /dev/null +++ b/include/clang/AST/StmtNodes.def @@ -0,0 +1,156 @@ +//===-- StmtNodes.def - Metadata about Stmt AST nodes -----------*- 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 AST Node info database. +// +//===----------------------------------------------------------------------===// + +#ifndef FIRST_STMT +#define FIRST_STMT(CLASS) +#define LAST_STMT(CLASS) +#endif + +#ifndef FIRST_EXPR +#define FIRST_EXPR(CLASS) +#define LAST_EXPR(CLASS) +#endif + +#ifndef EXPR +# define EXPR(Type, Base) STMT(Type, Base) +#endif + +// Normal Statements. +STMT(NullStmt , Stmt) +FIRST_STMT(NullStmt) +STMT(CompoundStmt , Stmt) +STMT(CaseStmt , SwitchCase) +STMT(DefaultStmt , SwitchCase) +STMT(LabelStmt , Stmt) +STMT(IfStmt , Stmt) +STMT(SwitchStmt , Stmt) +STMT(WhileStmt , Stmt) +STMT(DoStmt , Stmt) +STMT(ForStmt , Stmt) +STMT(GotoStmt , Stmt) +STMT(IndirectGotoStmt, Stmt) +STMT(ContinueStmt , Stmt) +STMT(BreakStmt , Stmt) +STMT(ReturnStmt , Stmt) +STMT(DeclStmt , Stmt) +STMT(SwitchCase , Stmt) + +// GNU Stmt Extensions +STMT(AsmStmt , Stmt) + +// Obj-C statements +STMT(ObjCAtTryStmt , Stmt) +STMT(ObjCAtCatchStmt , Stmt) +STMT(ObjCAtFinallyStmt , Stmt) +STMT(ObjCAtThrowStmt , Stmt) +STMT(ObjCAtSynchronizedStmt , Stmt) +// Obj-C2 statements +STMT(ObjCForCollectionStmt, Stmt) + +// C++ statements +STMT(CXXCatchStmt, Stmt) +STMT(CXXTryStmt , Stmt) + +LAST_STMT(CXXTryStmt) + +// Expressions. +EXPR(Expr , Stmt) +FIRST_EXPR(Expr) +EXPR(PredefinedExpr , Expr) +EXPR(DeclRefExpr , Expr) +EXPR(IntegerLiteral , Expr) +EXPR(FloatingLiteral , Expr) +EXPR(ImaginaryLiteral , Expr) +EXPR(StringLiteral , Expr) +EXPR(CharacterLiteral , Expr) +EXPR(ParenExpr , Expr) +EXPR(UnaryOperator , Expr) +EXPR(SizeOfAlignOfExpr , Expr) +EXPR(ArraySubscriptExpr , Expr) +EXPR(CallExpr , Expr) +EXPR(MemberExpr , Expr) +EXPR(CastExpr , Expr) +EXPR(BinaryOperator , Expr) +EXPR(CompoundAssignOperator, BinaryOperator) +EXPR(ConditionalOperator , Expr) +EXPR(ImplicitCastExpr , CastExpr) +EXPR(ExplicitCastExpr , CastExpr) +EXPR(CStyleCastExpr , ExplicitCastExpr) +EXPR(CompoundLiteralExpr , Expr) +EXPR(ExtVectorElementExpr , Expr) +EXPR(InitListExpr , Expr) +EXPR(DesignatedInitExpr , Expr) +EXPR(ImplicitValueInitExpr , Expr) +EXPR(VAArgExpr , Expr) + +// GNU Extensions. +EXPR(AddrLabelExpr , Expr) +EXPR(StmtExpr , Expr) +EXPR(TypesCompatibleExpr , Expr) +EXPR(ChooseExpr , Expr) +EXPR(GNUNullExpr , Expr) + +// C++ Expressions. +EXPR(CXXOperatorCallExpr , CallExpr) +EXPR(CXXMemberCallExpr , CallExpr) +EXPR(CXXNamedCastExpr , ExplicitCastExpr) +EXPR(CXXStaticCastExpr , CXXNamedCastExpr) +EXPR(CXXDynamicCastExpr , CXXNamedCastExpr) +EXPR(CXXReinterpretCastExpr , CXXNamedCastExpr) +EXPR(CXXConstCastExpr , CXXNamedCastExpr) +EXPR(CXXFunctionalCastExpr , ExplicitCastExpr) +EXPR(CXXTypeidExpr , Expr) +EXPR(CXXBoolLiteralExpr , Expr) +EXPR(CXXNullPtrLiteralExpr , Expr) +EXPR(CXXThisExpr , Expr) +EXPR(CXXThrowExpr , Expr) +EXPR(CXXDefaultArgExpr , Expr) +EXPR(CXXZeroInitValueExpr , Expr) +EXPR(CXXConditionDeclExpr , DeclRefExpr) +EXPR(CXXNewExpr , Expr) +EXPR(CXXDeleteExpr , Expr) +EXPR(UnresolvedFunctionNameExpr , Expr) +EXPR(UnaryTypeTraitExpr , Expr) +EXPR(QualifiedDeclRefExpr , DeclRefExpr) +EXPR(UnresolvedDeclRefExpr , Expr) +EXPR(CXXConstructExpr , Expr) +EXPR(CXXBindTemporaryExpr , Expr) +EXPR(CXXExprWithTemporaries , Expr) +EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) +EXPR(CXXUnresolvedConstructExpr, Expr) +EXPR(CXXUnresolvedMemberExpr, Expr) + +// Obj-C Expressions. +EXPR(ObjCStringLiteral , Expr) +EXPR(ObjCEncodeExpr , Expr) +EXPR(ObjCMessageExpr , Expr) +EXPR(ObjCSelectorExpr , Expr) +EXPR(ObjCProtocolExpr , Expr) +EXPR(ObjCIvarRefExpr , Expr) +EXPR(ObjCPropertyRefExpr , Expr) +EXPR(ObjCKVCRefExpr , Expr) +EXPR(ObjCSuperExpr , Expr) + +// Clang Extensions. +EXPR(ShuffleVectorExpr , Expr) +EXPR(BlockExpr , Expr) +EXPR(BlockDeclRefExpr , Expr) + +LAST_EXPR(BlockDeclRefExpr) + +#undef STMT +#undef EXPR +#undef FIRST_STMT +#undef LAST_STMT +#undef FIRST_EXPR +#undef LAST_EXPR diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h new file mode 100644 index 000000000000..8ae707174403 --- /dev/null +++ b/include/clang/AST/StmtObjC.h @@ -0,0 +1,307 @@ +//===--- StmtObjC.h - Classes for representing ObjC statements --*- 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 Objective-C statement AST node classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTOBJC_H +#define LLVM_CLANG_AST_STMTOBJC_H + +#include "clang/AST/Stmt.h" + +namespace clang { + +/// ObjCForCollectionStmt - This represents Objective-c's collection statement; +/// represented as 'for (element 'in' collection-expression)' stmt. +/// +class ObjCForCollectionStmt : public Stmt { + enum { ELEM, COLLECTION, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt. + SourceLocation ForLoc; + SourceLocation RParenLoc; +public: + ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, + SourceLocation FCL, SourceLocation RPL); + explicit ObjCForCollectionStmt(EmptyShell Empty) : + Stmt(ObjCForCollectionStmtClass, Empty) { } + + Stmt *getElement() { return SubExprs[ELEM]; } + Expr *getCollection() { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getElement() const { return SubExprs[ELEM]; } + const Expr *getCollection() const { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setElement(Stmt *S) { SubExprs[ELEM] = S; } + void setCollection(Expr *E) { + SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E); + } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation Loc) { ForLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCForCollectionStmtClass; + } + static bool classof(const ObjCForCollectionStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCAtCatchStmt - This represents objective-c's @catch statement. +class ObjCAtCatchStmt : public Stmt { +private: + enum { BODY, NEXT_CATCH, END_EXPR }; + ParmVarDecl *ExceptionDecl; + Stmt *SubExprs[END_EXPR]; + SourceLocation AtCatchLoc, RParenLoc; + +public: + ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, + ParmVarDecl *catchVarDecl, + Stmt *atCatchStmt, Stmt *atCatchList); + + explicit ObjCAtCatchStmt(EmptyShell Empty) : + Stmt(ObjCAtCatchStmtClass, Empty) { } + + const Stmt *getCatchBody() const { return SubExprs[BODY]; } + Stmt *getCatchBody() { return SubExprs[BODY]; } + void setCatchBody(Stmt *S) { SubExprs[BODY] = S; } + + const ObjCAtCatchStmt *getNextCatchStmt() const { + return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]); + } + ObjCAtCatchStmt *getNextCatchStmt() { + return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]); + } + void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; } + + const ParmVarDecl *getCatchParamDecl() const { + return ExceptionDecl; + } + ParmVarDecl *getCatchParamDecl() { + return ExceptionDecl; + } + void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; } + + SourceLocation getAtCatchLoc() const { return AtCatchLoc; } + void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd()); + } + + bool hasEllipsis() const { return getCatchParamDecl() == 0; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtCatchStmtClass; + } + static bool classof(const ObjCAtCatchStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement +class ObjCAtFinallyStmt : public Stmt { + Stmt *AtFinallyStmt; + SourceLocation AtFinallyLoc; +public: + ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt) + : Stmt(ObjCAtFinallyStmtClass), + AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {} + + explicit ObjCAtFinallyStmt(EmptyShell Empty) : + Stmt(ObjCAtFinallyStmtClass, Empty) { } + + const Stmt *getFinallyBody() const { return AtFinallyStmt; } + Stmt *getFinallyBody() { return AtFinallyStmt; } + void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); + } + + SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } + void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtFinallyStmtClass; + } + static bool classof(const ObjCAtFinallyStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCAtTryStmt - This represent objective-c's over-all +/// @try ... @catch ... @finally statement. +class ObjCAtTryStmt : public Stmt { +private: + enum { TRY, CATCH, FINALLY, END_EXPR }; + Stmt* SubStmts[END_EXPR]; + + SourceLocation AtTryLoc; +public: + ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt *atCatchStmt, + Stmt *atFinallyStmt) + : Stmt(ObjCAtTryStmtClass) { + SubStmts[TRY] = atTryStmt; + SubStmts[CATCH] = atCatchStmt; + SubStmts[FINALLY] = atFinallyStmt; + AtTryLoc = atTryLoc; + } + explicit ObjCAtTryStmt(EmptyShell Empty) : + Stmt(ObjCAtTryStmtClass, Empty) { } + + SourceLocation getAtTryLoc() const { return AtTryLoc; } + void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } + + const Stmt *getTryBody() const { return SubStmts[TRY]; } + Stmt *getTryBody() { return SubStmts[TRY]; } + void setTryBody(Stmt *S) { SubStmts[TRY] = S; } + + const ObjCAtCatchStmt *getCatchStmts() const { + return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); + } + ObjCAtCatchStmt *getCatchStmts() { + return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]); + } + void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; } + + const ObjCAtFinallyStmt *getFinallyStmt() const { + return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); + } + ObjCAtFinallyStmt *getFinallyStmt() { + return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]); + } + void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd()); + } + + 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(); +}; + +/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement. +/// Example: @synchronized (sem) { +/// do-something; +/// } +/// +class ObjCAtSynchronizedStmt : public Stmt { +private: + enum { SYNC_EXPR, SYNC_BODY, END_EXPR }; + Stmt* SubStmts[END_EXPR]; + SourceLocation AtSynchronizedLoc; + +public: + ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, + Stmt *synchBody) + : Stmt(ObjCAtSynchronizedStmtClass) { + SubStmts[SYNC_EXPR] = synchExpr; + SubStmts[SYNC_BODY] = synchBody; + AtSynchronizedLoc = atSynchronizedLoc; + } + explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : + Stmt(ObjCAtSynchronizedStmtClass, Empty) { } + + SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } + void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; } + + const CompoundStmt *getSynchBody() const { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + CompoundStmt *getSynchBody() { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } + + const Expr *getSynchExpr() const { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + Expr *getSynchExpr() { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtSynchronizedStmtClass; + } + static bool classof(const ObjCAtSynchronizedStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// ObjCAtThrowStmt - This represents objective-c's @throw statement. +class ObjCAtThrowStmt : public Stmt { + Stmt *Throw; + SourceLocation AtThrowLoc; +public: + ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr) + : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) { + AtThrowLoc = atThrowLoc; + } + explicit ObjCAtThrowStmt(EmptyShell Empty) : + Stmt(ObjCAtThrowStmtClass, Empty) { } + + const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); } + Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } + void setThrowExpr(Stmt *S) { Throw = S; } + + SourceLocation getThrowLoc() { return AtThrowLoc; } + void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } + + virtual SourceRange getSourceRange() const { + if (Throw) + return SourceRange(AtThrowLoc, Throw->getLocEnd()); + else + return SourceRange(AtThrowLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtThrowStmtClass; + } + static bool classof(const ObjCAtThrowStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h new file mode 100644 index 000000000000..4f4066ab8602 --- /dev/null +++ b/include/clang/AST/StmtVisitor.h @@ -0,0 +1,176 @@ +//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StmtVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTVISITOR_H +#define LLVM_CLANG_AST_STMTVISITOR_H + +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" + +namespace clang { + +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S)) + +/// StmtVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +template<typename ImplClass, typename RetTy=void> +class StmtVisitor { +public: + RetTy Visit(Stmt *S) { + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { + default: assert(0 && "Unknown binary operator!"); + case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator); + case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator); + case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator); + case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator); + case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator); + case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator); + case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator); + case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator); + case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator); + + case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator); + case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator); + case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator); + case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator); + case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator); + case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator); + + case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator); + case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator); + case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator); + case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator); + case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator); + case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator); + case BinaryOperator::MulAssign: + DISPATCH(BinMulAssign, CompoundAssignOperator); + case BinaryOperator::DivAssign: + DISPATCH(BinDivAssign, CompoundAssignOperator); + case BinaryOperator::RemAssign: + DISPATCH(BinRemAssign, CompoundAssignOperator); + case BinaryOperator::AddAssign: + DISPATCH(BinAddAssign, CompoundAssignOperator); + case BinaryOperator::SubAssign: + DISPATCH(BinSubAssign, CompoundAssignOperator); + case BinaryOperator::ShlAssign: + DISPATCH(BinShlAssign, CompoundAssignOperator); + case BinaryOperator::ShrAssign: + DISPATCH(BinShrAssign, CompoundAssignOperator); + case BinaryOperator::AndAssign: + DISPATCH(BinAndAssign, CompoundAssignOperator); + case BinaryOperator::OrAssign: + DISPATCH(BinOrAssign, CompoundAssignOperator); + case BinaryOperator::XorAssign: + DISPATCH(BinXorAssign, CompoundAssignOperator); + case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator); + } + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { + default: assert(0 && "Unknown unary operator!"); + case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator); + case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator); + case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator); + case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator); + case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator); + case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator); + case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator); + case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator); + case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator); + case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator); + case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator); + case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator); + case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator); + case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator); + } + } + + // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. + switch (S->getStmtClass()) { + default: assert(0 && "Unknown stmt kind!"); +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS); +#include "clang/AST/StmtNodes.def" + } + } + + // If the implementation chooses not to implement a certain visit method, fall + // back on VisitExpr or whatever else is the superclass. +#define STMT(CLASS, PARENT) \ + RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); } +#include "clang/AST/StmtNodes.def" + + // If the implementation doesn't implement binary operator methods, fall back + // on VisitBinaryOperator. +#define BINOP_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(BinaryOperator *S) { \ + DISPATCH(BinaryOperator, BinaryOperator); \ + } + BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) + BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) + BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) + BINOP_FALLBACK(Shr) + + BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) + BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) + BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) + BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr) + + BINOP_FALLBACK(Assign) + BINOP_FALLBACK(Comma) +#undef BINOP_FALLBACK + + // If the implementation doesn't implement compound assignment operator + // methods, fall back on VisitCompoundAssignOperator. +#define CAO_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(CompoundAssignOperator *S) { \ + DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \ + } + CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) + CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign) + CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign) + CAO_FALLBACK(XorAssign) +#undef CAO_FALLBACK + + // If the implementation doesn't implement unary operator methods, fall back + // on VisitUnaryOperator. +#define UNARYOP_FALLBACK(NAME) \ + RetTy VisitUnary ## NAME(UnaryOperator *S) { \ + DISPATCH(UnaryOperator, UnaryOperator); \ + } + UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) + UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec) + UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref) + + UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) + UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) + UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) + UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf) +#undef UNARYOP_FALLBACK + + // Base case, ignore it. :) + RetTy VisitStmt(Stmt *Node) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif diff --git a/include/clang/AST/TargetBuiltins.h b/include/clang/AST/TargetBuiltins.h new file mode 100644 index 000000000000..d425a9b8ecad --- /dev/null +++ b/include/clang/AST/TargetBuiltins.h @@ -0,0 +1,38 @@ +//===--- TargetBuiltins.h - Target specific builtin IDs -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TARGET_BUILTINS_H +#define LLVM_CLANG_AST_TARGET_BUILTINS_H + +#include "clang/AST/Builtins.h" +#undef PPC + +namespace clang { + /// X86 builtins + namespace X86 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "X86Builtins.def" + LastTSBuiltin + }; + } + + /// PPC builtins + namespace PPC { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "PPCBuiltins.def" + LastTSBuiltin + }; + } +} // end namespace clang. + +#endif diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h new file mode 100644 index 000000000000..511934c1dbf5 --- /dev/null +++ b/include/clang/AST/TemplateName.h @@ -0,0 +1,258 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATENAME_H +#define LLVM_CLANG_AST_TEMPLATENAME_H + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class DependentTemplateName; +class IdentifierInfo; +class NestedNameSpecifier; +class PrintingPolicy; +class QualifiedTemplateName; +class TemplateDecl; + +/// \brief Represents a C++ template name within the type system. +/// +/// A C++ template name refers to a template within the C++ type +/// system. In most cases, a template name is simply a reference to a +/// class template, e.g. +/// +/// \code +/// template<typename T> class X { }; +/// +/// X<int> xi; +/// \endcode +/// +/// Here, the 'X' in \c X<int> is a template name that refers to the +/// declaration of the class template X, above. Template names can +/// also refer to function templates, C++0x template aliases, etc. +/// +/// Some template names are dependent. For example, consider: +/// +/// \code +/// template<typename MetaFun, typename T1, typename T2> struct apply2 { +/// typedef typename MetaFun::template apply<T1, T2>::type type; +/// }; +/// \endcode +/// +/// Here, "apply" is treated as a template name within the typename +/// specifier in the typedef. "apply" is a nested template, and can +/// only be understood in the context of +class TemplateName { + typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *, + DependentTemplateName *> StorageType; + + StorageType Storage; + + explicit TemplateName(void *Ptr) { + Storage = StorageType::getFromOpaqueValue(Ptr); + } + +public: + TemplateName() : Storage() { } + explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } + explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } + explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } + + /// \brief Retrieve the the underlying template declaration that + /// this template name refers to, if known. + /// + /// \returns The template declaration that this template name refers + /// to, if any. If the template name does not refer to a specific + /// declaration because it is a dependent name, returns NULL. + TemplateDecl *getAsTemplateDecl() const; + + /// \brief Retrieve the underlying qualified template name + /// structure, if any. + QualifiedTemplateName *getAsQualifiedTemplateName() const { + return Storage.dyn_cast<QualifiedTemplateName *>(); + } + + /// \brief Retrieve the underlying dependent template name + /// structure, if any. + DependentTemplateName *getAsDependentTemplateName() const { + return Storage.dyn_cast<DependentTemplateName *>(); + } + + /// \brief Determines whether this is a dependent template name. + bool isDependent() const; + + /// \brief Print the template name. + /// + /// \param OS the output stream to which the template name will be + /// printed. + /// + /// \param SuppressNNS if true, don't print the + /// nested-name-specifier that precedes the template name (if it has + /// one). + void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, + bool SuppressNNS = false) const; + + /// \brief Debugging aid that dumps the template name to standard + /// error. + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Storage.getOpaqueValue()); + } + + /// \brief Retrieve the template name as a void pointer. + void *getAsVoidPointer() const { return Storage.getOpaqueValue(); } + + /// \brief Build a template name from a void pointer. + static TemplateName getFromVoidPointer(void *Ptr) { + return TemplateName(Ptr); + } +}; + +/// \brief Represents a template name that was expressed as a +/// qualified name. +/// +/// This kind of template name refers to a template name that was +/// preceded by a nested name specifier, e.g., \c std::vector. Here, +/// the nested name specifier is "std::" and the template name is the +/// declaration for "vector". The QualifiedTemplateName class is only +/// used to provide "sugar" for template names that were expressed +/// with a qualified name, and has no semantic meaning. In this +/// manner, it is to TemplateName what QualifiedNameType is to Type, +/// providing extra syntactic sugar for downstream clients. +class QualifiedTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template name. + /// + /// The bit is used to indicate whether the "template" keyword was + /// present before the template name itself. Note that the + /// "template" keyword is always redundant in this case (otherwise, + /// the template name would be a dependent name and we would express + /// this name with DependentTemplateName). + llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; + + /// \brief The template declaration that this qualified name refers + /// to. + TemplateDecl *Template; + + friend class ASTContext; + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + TemplateDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + + /// \brief Whether the template name was prefixed by the "template" + /// keyword. + bool hasTemplateKeyword() const { return Qualifier.getInt(); } + + /// \brief The template declaration to which this qualified name + /// refers. + TemplateDecl *getTemplateDecl() const { return Template; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + bool TemplateKeyword, TemplateDecl *Template) { + ID.AddPointer(NNS); + ID.AddBoolean(TemplateKeyword); + ID.AddPointer(Template); + } +}; + +/// \brief Represents a dependent template name that cannot be +/// resolved prior to template instantiation. +/// +/// This kind of template name refers to a dependent template name, +/// including its nested name specifier. For example, +/// DependentTemplateName can refer to "MetaFun::template apply", +/// where "MetaFun::" is the nested name specifier and "apply" is the +/// template name referenced. The "template" keyword is implied. +class DependentTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template + /// name. + NestedNameSpecifier *Qualifier; + + /// \brief The dependent template name. + const IdentifierInfo *Name; + + /// \brief The canonical template name to which this dependent + /// template name refers. + /// + /// The canonical template name for a dependent template name is + /// another dependent template name whose nested name specifier is + /// canonical. + TemplateName CanonicalTemplateName; + + friend class ASTContext; + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name) + : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name, + TemplateName Canon) + : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Return the name to which this dependent template name + /// refers. + const IdentifierInfo *getName() const { return Name; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), getName()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + const IdentifierInfo *Name) { + ID.AddPointer(NNS); + ID.AddPointer(Name); + } +}; + +} // end namespace clang. + +namespace llvm { + +/// \brief The clang::TemplateName class is effectively a pointer. +template<> +class PointerLikeTypeTraits<clang::TemplateName> { +public: + static inline void *getAsVoidPointer(clang::TemplateName TN) { + return TN.getAsVoidPointer(); + } + + static inline clang::TemplateName getFromVoidPointer(void *Ptr) { + return clang::TemplateName::getFromVoidPointer(Ptr); + } + + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm. + +#endif diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h new file mode 100644 index 000000000000..1b012385c9f2 --- /dev/null +++ b/include/clang/AST/Type.h @@ -0,0 +1,1977 @@ +//===--- Type.h - C Language Family Type Representation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Type interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPE_H +#define LLVM_CLANG_AST_TYPE_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateName.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" + +using llvm::isa; +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; +namespace clang { class Type; } + +namespace llvm { + template <typename T> + class PointerLikeTypeTraits; + template<> + class PointerLikeTypeTraits< ::clang::Type*> { + public: + static inline void *getAsVoidPointer(::clang::Type *P) { return P; } + static inline ::clang::Type *getFromVoidPointer(void *P) { + return static_cast< ::clang::Type*>(P); + } + enum { NumLowBitsAvailable = 3 }; + }; +} + +namespace clang { + class ASTContext; + class TypedefDecl; + class TemplateDecl; + class TemplateTypeParmDecl; + class NonTypeTemplateParmDecl; + class TemplateTemplateParmDecl; + class TagDecl; + class RecordDecl; + class CXXRecordDecl; + class EnumDecl; + class FieldDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; + class ObjCMethodDecl; + class Expr; + class Stmt; + class SourceLocation; + class StmtIteratorBase; + class TemplateArgument; + class QualifiedNameType; + class PrintingPolicy; + + // Provide forward declarations for all of the *Type classes +#define TYPE(Class, Base) class Class##Type; +#include "clang/AST/TypeNodes.def" + +/// QualType - For efficiency, we don't store CVR-qualified types as nodes on +/// their own: instead each reference to a type stores the qualifiers. This +/// greatly reduces the number of nodes we need to allocate for types (for +/// example we only need one for 'int', 'const int', 'volatile int', +/// 'const volatile int', etc). +/// +/// As an added efficiency bonus, instead of making this a pair, we just store +/// the three bits we care about in the low bits of the pointer. To handle the +/// packing/unpacking, we make QualType be a simple wrapper class that acts like +/// a smart pointer. +class QualType { + llvm::PointerIntPair<Type*, 3> Value; +public: + enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. + Const = 0x1, + Restrict = 0x2, + Volatile = 0x4, + CVRFlags = Const|Restrict|Volatile + }; + + enum GCAttrTypes { + GCNone = 0, + Weak, + Strong + }; + + QualType() {} + + QualType(const Type *Ptr, unsigned Quals) + : Value(const_cast<Type*>(Ptr), Quals) {} + + unsigned getCVRQualifiers() const { return Value.getInt(); } + void setCVRQualifiers(unsigned Quals) { Value.setInt(Quals); } + Type *getTypePtr() const { return Value.getPointer(); } + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + static QualType getFromOpaquePtr(void *Ptr) { + QualType T; + T.Value.setFromOpaqueValue(Ptr); + return T; + } + + Type &operator*() const { + return *getTypePtr(); + } + + Type *operator->() const { + return getTypePtr(); + } + + /// isNull - Return true if this QualType doesn't point to a type yet. + bool isNull() const { + return getTypePtr() == 0; + } + + bool isConstQualified() const { + return (getCVRQualifiers() & Const) ? true : false; + } + bool isVolatileQualified() const { + return (getCVRQualifiers() & Volatile) ? true : false; + } + bool isRestrictQualified() const { + return (getCVRQualifiers() & Restrict) ? true : false; + } + + bool isConstant(ASTContext& Ctx) const; + + /// addConst/addVolatile/addRestrict - add the specified type qual to this + /// QualType. + void addConst() { Value.setInt(Value.getInt() | Const); } + void addVolatile() { Value.setInt(Value.getInt() | Volatile); } + void addRestrict() { Value.setInt(Value.getInt() | Restrict); } + + void removeConst() { Value.setInt(Value.getInt() & ~Const); } + void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); } + void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); } + + QualType getQualifiedType(unsigned TQs) const { + return QualType(getTypePtr(), TQs); + } + QualType getWithAdditionalQualifiers(unsigned TQs) const { + return QualType(getTypePtr(), TQs|getCVRQualifiers()); + } + + QualType withConst() const { return getWithAdditionalQualifiers(Const); } + QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);} + QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);} + + QualType getUnqualifiedType() const; + bool isMoreQualifiedThan(QualType Other) const; + bool isAtLeastAsQualifiedAs(QualType Other) const; + QualType getNonReferenceType() const; + + /// getDesugaredType - Return the specified type with any "sugar" removed from + /// the type. This takes off typedefs, typeof's etc. If the outer level of + /// the type is already concrete, it returns it unmodified. This is similar + /// to getting the canonical type, but it doesn't remove *all* typedefs. For + /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is + /// concrete. + QualType getDesugaredType(bool ForDisplay = false) const; + + /// operator==/!= - Indicate whether the specified types and qualifiers are + /// identical. + bool operator==(const QualType &RHS) const { + return Value == RHS.Value; + } + bool operator!=(const QualType &RHS) const { + return Value != RHS.Value; + } + std::string getAsString() const; + + std::string getAsString(const PrintingPolicy &Policy) const { + std::string S; + getAsStringInternal(S, Policy); + return S; + } + void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; + + void dump(const char *s) const; + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } + +public: + + /// getAddressSpace - Return the address space of this type. + inline unsigned getAddressSpace() const; + + /// GCAttrTypesAttr - Returns gc attribute of this type. + inline QualType::GCAttrTypes getObjCGCAttr() const; + + /// isObjCGCWeak true when Type is objc's weak. + bool isObjCGCWeak() const { + return getObjCGCAttr() == Weak; + } + + /// isObjCGCStrong true when Type is objc's strong. + bool isObjCGCStrong() const { + return getObjCGCAttr() == Strong; + } +}; + +} // end clang. + +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; + static SimpleType getSimplifiedValue(const ::clang::QualType &Val) { + return Val.getTypePtr(); + } +}; +template<> struct simplify_type< ::clang::QualType> + : public simplify_type<const ::clang::QualType> {}; + +// Teach SmallPtrSet that QualType is "basically a pointer". +template<> +class PointerLikeTypeTraits<clang::QualType> { +public: + static inline void *getAsVoidPointer(clang::QualType P) { + return P.getAsOpaquePtr(); + } + static inline clang::QualType getFromVoidPointer(void *P) { + return clang::QualType::getFromOpaquePtr(P); + } + // CVR qualifiers go in low bits. + enum { NumLowBitsAvailable = 0 }; +}; +} // end namespace llvm + +namespace clang { + +/// 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 +/// references. For example, consider: +/// +/// typedef int foo; +/// typedef foo* bar; +/// 'int *' 'foo *' 'bar' +/// +/// There will be a Type object created for 'int'. Since int is canonical, its +/// canonicaltype pointer points to itself. There is also a Type for 'foo' (a +/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next +/// there is a PointerType that represents 'int*', which, like 'int', is +/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical +/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type +/// is also 'int*'. +/// +/// Non-canonical types are useful for emitting diagnostics, without losing +/// information about typedefs being used. Canonical types are useful for type +/// comparisons (they allow by-pointer equality tests) and useful for reasoning +/// about whether something has a particular form (e.g. is a function type), +/// because they implicitly, recursively, strip all typedefs out of a type. +/// +/// Types, once created, are immutable. +/// +class Type { +public: + enum TypeClass { +#define TYPE(Class, Base) Class, +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + TagFirst = Record, TagLast = Enum + }; + +private: + QualType CanonicalType; + + /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). + bool Dependent : 1; + + /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + /// Note that this should stay at the end of the ivars for Type so that + /// subclasses can pack their bitfields into the same word. + unsigned TC : 5; + + Type(const Type&); // DO NOT IMPLEMENT. + void operator=(const Type&); // DO NOT IMPLEMENT. +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), + Dependent(dependent), TC(tc) {} + virtual ~Type() {} + virtual void Destroy(ASTContext& C); + friend class ASTContext; + +public: + TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); } + + bool isCanonical() const { return CanonicalType.getTypePtr() == this; } + + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): + /// object types, function types, and incomplete types. + + /// \brief Determines whether the type describes an object in memory. + /// + /// Note that this definition of object type corresponds to the C++ + /// definition of object type, which includes incomplete types, as + /// opposed to the C definition (which does not include incomplete + /// types). + bool isObjectType() const; + + /// isIncompleteType - Return true if this is an incomplete type. + /// A type that can describe objects, but which lacks information needed to + /// determine its size (e.g. void, or a fwd declared struct). Clients of this + /// routine will need to determine if the size is actually required. + bool isIncompleteType() const; + + /// isIncompleteOrObjectType - Return true if this is an incomplete or object + /// type, in other words, not a function type. + bool isIncompleteOrObjectType() const { + return !isFunctionType(); + } + + /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10). + bool isPODType() 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. + + /// isSpecificBuiltinType - Test for a particular builtin type. + bool isSpecificBuiltinType(unsigned K) const; + + /// isIntegerType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) + bool isEnumeralType() const; + bool isBooleanType() const; + bool isCharType() const; + bool isWideCharType() const; + bool isIntegralType() const; + + /// Floating point categories. + bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) + /// isComplexType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isComplexType() const; // C99 6.2.5p11 (complex) + bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. + bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) + bool isRealType() const; // C99 6.2.5p17 (real floating + integer) + bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) + bool isVoidType() const; // C99 6.2.5p19 + bool isDerivedType() const; // C99 6.2.5p20 + bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) + bool isAggregateType() const; + + // Type Predicates: Check to see if this type is structurally the specified + // type, ignoring typedefs and qualifiers. + bool isFunctionType() const; + bool isFunctionNoProtoType() const { return getAsFunctionNoProtoType() != 0; } + bool isFunctionProtoType() const { return getAsFunctionProtoType() != 0; } + bool isPointerType() const; + bool isBlockPointerType() const; + bool isReferenceType() const; + bool isLValueReferenceType() const; + bool isRValueReferenceType() const; + bool isFunctionPointerType() const; + bool isMemberPointerType() const; + bool isMemberFunctionPointerType() const; + bool isArrayType() const; + bool isConstantArrayType() const; + bool isIncompleteArrayType() const; + bool isVariableArrayType() const; + bool isDependentSizedArrayType() const; + bool isRecordType() const; + bool isClassType() const; + bool isStructureType() const; + bool isUnionType() const; + bool isComplexIntegerType() const; // GCC _Complex integer type. + bool isVectorType() const; // GCC vector type. + bool isExtVectorType() const; // Extended vector type. + bool isObjCInterfaceType() const; // NSString or NSString<foo> + bool isObjCQualifiedInterfaceType() const; // NSString<foo> + bool isObjCQualifiedIdType() const; // id<foo> + bool isTemplateTypeParmType() const; // C++ template type parameter + bool isNullPtrType() const; // C++0x nullptr_t + + /// isDependentType - Whether this type is a dependent type, meaning + /// that its definition somehow depends on a template parameter + /// (C++ [temp.dep.type]). + bool isDependentType() const { return Dependent; } + bool isOverloadableType() const; + + /// hasPointerRepresentation - Whether this type is represented + /// natively as a pointer; this includes pointers, references, block + /// pointers, and Objective-C interface, qualified id, and qualified + /// interface types, as well as nullptr_t. + bool hasPointerRepresentation() const; + + /// hasObjCPointerRepresentation - Whether this type can represent + /// an objective pointer type for the purpose of GC'ability + bool hasObjCPointerRepresentation() const; + + // Type Checking Functions: Check to see if this type is structurally the + // specified type, ignoring typedefs and qualifiers, and return a pointer to + // the best type we can. + const BuiltinType *getAsBuiltinType() const; + const FunctionType *getAsFunctionType() const; + const FunctionNoProtoType *getAsFunctionNoProtoType() const; + const FunctionProtoType *getAsFunctionProtoType() const; + const PointerType *getAsPointerType() const; + const BlockPointerType *getAsBlockPointerType() const; + const ReferenceType *getAsReferenceType() const; + const LValueReferenceType *getAsLValueReferenceType() const; + const RValueReferenceType *getAsRValueReferenceType() const; + const MemberPointerType *getAsMemberPointerType() const; + const TagType *getAsTagType() const; + const RecordType *getAsRecordType() const; + const RecordType *getAsStructureType() const; + /// NOTE: getAs*ArrayType are methods on ASTContext. + const TypedefType *getAsTypedefType() const; + const RecordType *getAsUnionType() const; + const EnumType *getAsEnumType() const; + const VectorType *getAsVectorType() const; // GCC vector type. + const ComplexType *getAsComplexType() const; + const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. + const ExtVectorType *getAsExtVectorType() const; // Extended vector type. + const ObjCInterfaceType *getAsObjCInterfaceType() const; + const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; + const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const; + const TemplateTypeParmType *getAsTemplateTypeParmType() const; + + const TemplateSpecializationType * + getAsTemplateSpecializationType() const; + + /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC + /// interface, return the interface type, otherwise return null. + const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; + + /// 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. + const Type *getArrayElementTypeNoTypeQual() const; + + /// getDesugaredType - Return the specified type with any "sugar" removed from + /// the type. This takes off typedefs, typeof's etc. If the outer level of + /// the type is already concrete, it returns it unmodified. This is similar + /// to getting the canonical type, but it doesn't remove *all* typedefs. For + /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is + /// concrete. + QualType getDesugaredType(bool ForDisplay = false) const; + + /// More type predicates useful for type checking/promotion + bool isPromotableIntegerType() const; // C99 6.3.1.1p2 + + /// isSignedIntegerType - Return true if this is an integer type that is + /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], + /// an enum decl which has a signed representation, or a vector of signed + /// integer element type. + bool isSignedIntegerType() const; + + /// isUnsignedIntegerType - Return true if this is an integer type that is + /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum + /// decl which has an unsigned representation, or a vector of unsigned integer + /// element type. + bool isUnsignedIntegerType() const; + + /// isConstantSizeType - Return true if this is not a variable sized type, + /// according to the rules of C99 6.7.5p3. It is not legal to call this on + /// incomplete types. + bool isConstantSizeType() const; + + /// isSpecifierType - Returns true if this type can be represented by some + /// set of type specifiers. + bool isSpecifierType() const; + + QualType getCanonicalTypeInternal() const { return CanonicalType; } + void dump() const; + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const = 0; + static bool classof(const Type *) { return true; } +}; + +/// ExtQualType - TR18037 (C embedded extensions) 6.2.5p26 +/// This supports all kinds of type attributes; including, +/// address space qualified types, objective-c's __weak and +/// __strong attributes. +/// +class ExtQualType : public Type, public llvm::FoldingSetNode { + /// BaseType - This is the underlying type that this qualifies. All CVR + /// qualifiers are stored on the QualType that references this type, so we + /// can't have any here. + Type *BaseType; + + /// Address Space ID - The address space ID this type is qualified with. + unsigned AddressSpace; + /// GC __weak/__strong attributes + QualType::GCAttrTypes GCAttrType; + + ExtQualType(Type *Base, QualType CanonicalPtr, unsigned AddrSpace, + QualType::GCAttrTypes gcAttr) : + Type(ExtQual, CanonicalPtr, Base->isDependentType()), BaseType(Base), + AddressSpace(AddrSpace), GCAttrType(gcAttr) { + assert(!isa<ExtQualType>(BaseType) && + "Cannot have ExtQualType of ExtQualType"); + } + friend class ASTContext; // ASTContext creates these. +public: + Type *getBaseType() const { return BaseType; } + QualType::GCAttrTypes getObjCGCAttr() const { return GCAttrType; } + unsigned getAddressSpace() const { return AddressSpace; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), AddressSpace, GCAttrType); + } + static void Profile(llvm::FoldingSetNodeID &ID, Type *Base, + unsigned AddrSpace, QualType::GCAttrTypes gcAttr) { + ID.AddPointer(Base); + ID.AddInteger(AddrSpace); + ID.AddInteger(gcAttr); + } + + static bool classof(const Type *T) { return T->getTypeClass() == ExtQual; } + static bool classof(const ExtQualType *) { return true; } +}; + + +/// BuiltinType - This class is used for builtin types like 'int'. Builtin +/// types are always canonical and have a literal name field. +class BuiltinType : public Type { +public: + enum Kind { + Void, + + Bool, // This is bool and/or _Bool. + Char_U, // This is 'char' for targets where char is unsigned. + UChar, // This is explicitly qualified unsigned char. + UShort, + UInt, + ULong, + ULongLong, + UInt128, // __uint128_t + + Char_S, // This is 'char' for targets where char is signed. + SChar, // This is explicitly qualified signed char. + WChar, // This is 'wchar_t' for C++. + Short, + Int, + Long, + LongLong, + Int128, // __int128_t + + Float, Double, LongDouble, + + NullPtr, // This is the type of C++0x 'nullptr'. + + Overload, // This represents the type of an overloaded function declaration. + Dependent // This represents the type of a type-dependent expression. + }; +private: + Kind TypeKind; +public: + BuiltinType(Kind K) + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)), + TypeKind(K) {} + + Kind getKind() const { return TypeKind; } + const char *getName(bool CPlusPlus) const; + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } + static bool classof(const BuiltinType *) { return true; } +}; + +/// FixedWidthIntType - Used for arbitrary width types that we either don't +/// want to or can't map to named integer types. These always have a lower +/// integer rank than builtin types of the same width. +class FixedWidthIntType : public Type { +private: + unsigned Width; + bool Signed; +public: + FixedWidthIntType(unsigned W, bool S) : Type(FixedWidthInt, QualType(), false), + Width(W), Signed(S) {} + + unsigned getWidth() const { return Width; } + bool isSigned() const { return Signed; } + const char *getName() const; + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { return T->getTypeClass() == FixedWidthInt; } + static bool classof(const FixedWidthIntType *) { return true; } +}; + +/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex +/// types (_Complex float etc) as well as the GCC integer complex extensions. +/// +class ComplexType : public Type, public llvm::FoldingSetNode { + QualType ElementType; + ComplexType(QualType Element, QualType CanonicalPtr) : + Type(Complex, CanonicalPtr, Element->isDependentType()), + ElementType(Element) { + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getElementType() const { return ElementType; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { + ID.AddPointer(Element.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } + static bool classof(const ComplexType *) { return true; } +}; + +/// 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) { + } + friend class ASTContext; // ASTContext creates these. +public: + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + QualType getPointeeType() const { return PointeeType; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } + static bool classof(const PointerType *) { return true; } +}; + +/// BlockPointerType - pointer to a block type. +/// This type is to represent types syntactically represented as +/// "void (^)(int)", etc. Pointee is required to always be a function type. +/// +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()), + PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. +public: + + // Get the pointee type. Pointee is required to always be a function type. + QualType getPointeeType() const { return PointeeType; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; + } + static bool classof(const BlockPointerType *) { return true; } +}; + +/// ReferenceType - Base for LValueReferenceType and RValueReferenceType +/// +class ReferenceType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + +protected: + ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef) : + Type(tc, CanonicalRef, Referencee->isDependentType()), + PointeeType(Referencee) { + } +public: + QualType getPointeeType() const { return PointeeType; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee) { + ID.AddPointer(Referencee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference || + T->getTypeClass() == RValueReference; + } + static bool classof(const ReferenceType *) { return true; } +}; + +/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference +/// +class LValueReferenceType : public ReferenceType { + LValueReferenceType(QualType Referencee, QualType CanonicalRef) : + ReferenceType(LValueReference, Referencee, CanonicalRef) { + } + friend class ASTContext; // ASTContext creates these +public: + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference; + } + static bool classof(const LValueReferenceType *) { return true; } +}; + +/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference +/// +class RValueReferenceType : public ReferenceType { + RValueReferenceType(QualType Referencee, QualType CanonicalRef) : + ReferenceType(RValueReference, Referencee, CanonicalRef) { + } + friend class ASTContext; // ASTContext creates these +public: + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == RValueReference; + } + static bool classof(const RValueReferenceType *) { return true; } +}; + +/// MemberPointerType - C++ 8.3.3 - Pointers to members +/// +class MemberPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + /// The class of which the pointee is a member. Must ultimately be a + /// RecordType, but could be a typedef or a template parameter too. + const Type *Class; + + MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : + Type(MemberPointer, CanonicalPtr, + Cls->isDependentType() || Pointee->isDependentType()), + PointeeType(Pointee), Class(Cls) { + } + friend class ASTContext; // ASTContext creates these. +public: + + QualType getPointeeType() const { return PointeeType; } + + const Type *getClass() const { return Class; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType(), getClass()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, + const Type *Class) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + ID.AddPointer(Class); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == MemberPointer; + } + static bool classof(const MemberPointerType *) { return true; } +}; + +/// ArrayType - C99 6.7.5.2 - Array Declarators. +/// +class ArrayType : public Type, public llvm::FoldingSetNode { +public: + /// ArraySizeModifier - Capture whether this is a normal array (e.g. int X[4]) + /// an array with a static size (e.g. int X[static 4]), or an array + /// with a star size (e.g. int X[*]). + /// 'static' is only allowed on function parameters. + enum ArraySizeModifier { + Normal, Static, Star + }; +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... + // - an array type constructed from any dependent type or whose + // 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) {} + + friend class ASTContext; // ASTContext creates these. +public: + QualType getElementType() const { return ElementType; } + ArraySizeModifier getSizeModifier() const { + return ArraySizeModifier(SizeModifier); + } + unsigned getIndexTypeQualifier() const { return IndexTypeQuals; } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == VariableArray || + T->getTypeClass() == IncompleteArray || + T->getTypeClass() == DependentSizedArray; + } + static bool classof(const ArrayType *) { return true; } +}; + +/// ConstantArrayType - This class represents C arrays with a specified constant +/// size. For example 'int A[100]' has ConstantArrayType where the element type +/// is 'int' and the size is 100. +class ConstantArrayType : public ArrayType { + llvm::APInt Size; // Allows us to unique the type. + + ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, + ArraySizeModifier sm, unsigned tq) + : ArrayType(ConstantArray, et, can, sm, tq), Size(size) {} + friend class ASTContext; // ASTContext creates these. +public: + const llvm::APInt &getSize() const { return Size; } + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSize(), + getSizeModifier(), getIndexTypeQualifier()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, + unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(ArraySize.getZExtValue()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray; + } + static bool classof(const ConstantArrayType *) { return true; } +}; + +/// IncompleteArrayType - This class represents C arrays with an unspecified +/// size. For example 'int A[]' has an IncompleteArrayType where the element +/// type is 'int' and the size is unspecified. +class IncompleteArrayType : public ArrayType { + IncompleteArrayType(QualType et, QualType can, + ArraySizeModifier sm, unsigned tq) + : ArrayType(IncompleteArray, et, can, sm, tq) {} + friend class ASTContext; // ASTContext creates these. +public: + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; + } + static bool classof(const IncompleteArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSizeModifier(), getIndexTypeQualifier()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + ArraySizeModifier SizeMod, unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } +}; + +/// VariableArrayType - This class represents C arrays with a specified size +/// which is not an integer-constant-expression. For example, 'int s[x+foo()]'. +/// Since the size expression is an arbitrary expression, we store it as such. +/// +/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and +/// should not be: two lexically equivalent variable array types could mean +/// different things, for example, these variables do not have the same type +/// dynamically: +/// +/// void foo(int x) { +/// int Y[x]; +/// ++x; +/// int Z[x]; +/// } +/// +class VariableArrayType : public ArrayType { + /// SizeExpr - An assignment expression. VLA's are only permitted within + /// a function block. + Stmt *SizeExpr; + + VariableArrayType(QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq) + : ArrayType(VariableArray, et, can, sm, tq), SizeExpr((Stmt*) e) {} + friend class ASTContext; // ASTContext creates these. + virtual void Destroy(ASTContext& C); + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == VariableArray; + } + static bool classof(const VariableArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + assert(0 && "Cannnot unique VariableArrayTypes."); + } +}; + +/// DependentSizedArrayType - This type represents an array type in +/// C++ whose size is a value-dependent expression. For example: +/// @code +/// template<typename T, int Size> +/// class array { +/// T data[Size]; +/// }; +/// @endcode +/// For these types, we won't actually know what the array bound is +/// until template instantiation occurs, at which point this will +/// become either a ConstantArrayType or a VariableArrayType. +class DependentSizedArrayType : public ArrayType { + /// SizeExpr - An assignment expression that will instantiate to the + /// size of the array. + Stmt *SizeExpr; + + DependentSizedArrayType(QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq) + : ArrayType(DependentSizedArray, et, can, sm, tq), SizeExpr((Stmt*) e) {} + friend class ASTContext; // ASTContext creates these. + virtual void Destroy(ASTContext& C); + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedArray; + } + static bool classof(const DependentSizedArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + assert(0 && "Cannnot unique DependentSizedArrayTypes."); + } +}; + +/// VectorType - GCC generic vector type. This type is created using +/// __attribute__((vector_size(n)), where "n" specifies the vector size in +/// bytes. Since the constructor takes the number of vector elements, the +/// client is responsible for converting the size into the number of elements. +class VectorType : public Type, public llvm::FoldingSetNode { +protected: + /// ElementType - The element type of the vector. + QualType ElementType; + + /// NumElements - The number of elements in the vector. + unsigned NumElements; + + VectorType(QualType vecType, unsigned nElements, QualType canonType) : + Type(Vector, canonType, vecType->isDependentType()), + ElementType(vecType), NumElements(nElements) {} + VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType) + : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), + NumElements(nElements) {} + friend class ASTContext; // ASTContext creates these. +public: + + QualType getElementType() const { return ElementType; } + unsigned getNumElements() const { return NumElements; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getNumElements(), getTypeClass()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + unsigned NumElements, TypeClass TypeClass) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(NumElements); + ID.AddInteger(TypeClass); + } + static bool classof(const Type *T) { + return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; + } + static bool classof(const VectorType *) { return true; } +}; + +/// ExtVectorType - Extended vector type. This type is created using +/// __attribute__((ext_vector_type(n)), where "n" is the number of elements. +/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This +/// class enables syntactic extensions, like Vector Components for accessing +/// 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) {} + friend class ASTContext; // ASTContext creates these. +public: + static int getPointAccessorIdx(char c) { + switch (c) { + default: return -1; + case 'x': return 0; + case 'y': return 1; + case 'z': return 2; + case 'w': return 3; + } + } + static int getNumericAccessorIdx(char c) { + switch (c) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + } + } + + static int getAccessorIdx(char c) { + if (int idx = getPointAccessorIdx(c)+1) return idx-1; + return getNumericAccessorIdx(c); + } + + bool isAccessorWithinNumElements(char c) const { + if (int idx = getAccessorIdx(c)+1) + return unsigned(idx-1) < NumElements; + return false; + } + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == ExtVector; + } + static bool classof(const ExtVectorType *) { return true; } +}; + +/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base +/// class of FunctionNoProtoType and FunctionProtoType. +/// +class FunctionType : public Type { + /// 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; + + // The type returned by the function. + QualType ResultType; +protected: + FunctionType(TypeClass tc, QualType res, bool SubclassInfo, + unsigned typeQuals, QualType Canonical, bool Dependent) + : Type(tc, Canonical, Dependent), + SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {} + bool getSubClassData() const { return SubClassData; } + unsigned getTypeQuals() const { return TypeQuals; } +public: + + QualType getResultType() const { return ResultType; } + + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto || + T->getTypeClass() == FunctionProto; + } + static bool classof(const FunctionType *) { return true; } +}; + +/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has +/// no information available about its arguments. +class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { + FunctionNoProtoType(QualType Result, QualType Canonical) + : FunctionType(FunctionNoProto, Result, false, 0, Canonical, + /*Dependent=*/false) {} + friend class ASTContext; // ASTContext creates these. +public: + // No additional state past what FunctionType provides. + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) { + ID.AddPointer(ResultType.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto; + } + static bool classof(const FunctionNoProtoType *) { return true; } +}; + +/// FunctionProtoType - Represents a prototype with argument type info, e.g. +/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no +/// arguments, not as having a single void argument. Such a type can have an +/// 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) { + for (unsigned Idx = 0; Idx < numArgs; ++Idx) + if (ArgArray[Idx]->isDependentType()) + 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) + : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, + (Result->isDependentType() || + hasAnyDependentType(ArgArray, numArgs))), + 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]; + } + + /// NumArgs - The number of arguments this function has, not counting '...'. + unsigned NumArgs : 20; + + /// NumExceptions - The number of types in the exception spec, if any. + unsigned NumExceptions : 10; + + /// HasExceptionSpec - Whether this function has an exception spec at all. + bool HasExceptionSpec : 1; + + /// AnyExceptionSpec - Whether this function has a throw(...) spec. + bool AnyExceptionSpec : 1; + + /// ArgInfo - There is an variable size array after the class in memory that + /// holds the argument types. + + /// Exceptions - There is another variable size array after ArgInfo that + /// holds the exception types. + + friend class ASTContext; // ASTContext creates these. + +public: + unsigned getNumArgs() const { return NumArgs; } + QualType getArgType(unsigned i) const { + assert(i < NumArgs && "Invalid argument number!"); + return arg_type_begin()[i]; + } + + bool hasExceptionSpec() const { return HasExceptionSpec; } + bool hasAnyExceptionSpec() const { return AnyExceptionSpec; } + unsigned getNumExceptions() const { return NumExceptions; } + QualType getExceptionType(unsigned i) const { + assert(i < NumExceptions && "Invalid exception number!"); + return exception_begin()[i]; + } + bool hasEmptyExceptionSpec() const { + return hasExceptionSpec() && !hasAnyExceptionSpec() && + getNumExceptions() == 0; + } + + bool isVariadic() const { return getSubClassData(); } + unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + + typedef const QualType *arg_type_iterator; + arg_type_iterator arg_type_begin() const { + return reinterpret_cast<const QualType *>(this+1); + } + arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; } + + typedef const QualType *exception_iterator; + exception_iterator exception_begin() const { + // exceptions begin where arguments end + return arg_type_end(); + } + exception_iterator exception_end() const { + return exception_begin() + NumExceptions; + } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionProto; + } + static bool classof(const FunctionProtoType *) { return true; } + + 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); +}; + + +class TypedefType : public Type { + TypedefDecl *Decl; +protected: + TypedefType(TypeClass tc, TypedefDecl *D, QualType can) + : Type(tc, can, can->isDependentType()), Decl(D) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + + TypedefDecl *getDecl() const { return Decl; } + + /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to + /// potentially looking through *all* consecutive typedefs. This returns the + /// sum of the type qualifiers, so if you have: + /// typedef const int A; + /// typedef volatile A B; + /// looking through the typedefs for B will give you "const volatile A". + QualType LookThroughTypedefs() const; + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } + static bool classof(const TypedefType *) { return true; } +}; + +/// TypeOfExprType (GCC extension). +class TypeOfExprType : public Type { + Expr *TOExpr; + TypeOfExprType(Expr *E, QualType can); + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return TOExpr; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } + static bool classof(const TypeOfExprType *) { return true; } +}; + +/// TypeOfType (GCC extension). +class TypeOfType : public Type { + QualType TOType; + TypeOfType(QualType T, QualType can) + : Type(TypeOf, can, T->isDependentType()), TOType(T) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getUnderlyingType() const { return TOType; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } + static bool classof(const TypeOfType *) { return true; } +}; + +class TagType : public Type { + /// Stores the TagDecl associated with this type. The decl will + /// point to the TagDecl that actually defines the entity (or is a + /// definition in progress), if there is such a definition. The + /// single-bit value will be non-zero when this tag is in the + /// process of being defined. + mutable llvm::PointerIntPair<TagDecl *, 1> decl; + friend class ASTContext; + friend class TagDecl; + +protected: + TagType(TypeClass TC, TagDecl *D, QualType can); + +public: + TagDecl *getDecl() const { return decl.getPointer(); } + + /// @brief Determines whether this type is in the process of being + /// defined. + bool isBeingDefined() const { return decl.getInt(); } + void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; + } + static bool classof(const TagType *) { return true; } + static bool classof(const RecordType *) { return true; } + static bool classof(const EnumType *) { return true; } +}; + +/// RecordType - This is a helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of structs/unions/classes. +class RecordType : public TagType { +protected: + explicit RecordType(RecordDecl *D) + : TagType(Record, reinterpret_cast<TagDecl*>(D), QualType()) { } + explicit RecordType(TypeClass TC, RecordDecl *D) + : TagType(TC, reinterpret_cast<TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + RecordDecl *getDecl() const { + return reinterpret_cast<RecordDecl*>(TagType::getDecl()); + } + + // FIXME: This predicate is a helper to QualType/Type. It needs to + // recursively check all fields for const-ness. If any field is declared + // 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; } + + static bool classof(const TagType *T); + static bool classof(const Type *T) { + return isa<TagType>(T) && classof(cast<TagType>(T)); + } + static bool classof(const RecordType *) { return true; } +}; + +/// EnumType - This is a helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of enums. +class EnumType : public TagType { + explicit EnumType(EnumDecl *D) + : TagType(Enum, reinterpret_cast<TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + EnumDecl *getDecl() const { + return reinterpret_cast<EnumDecl*>(TagType::getDecl()); + } + + static bool classof(const TagType *T); + static bool classof(const Type *T) { + return isa<TagType>(T) && classof(cast<TagType>(T)); + } + static bool classof(const EnumType *) { return true; } +}; + +class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { + unsigned Depth : 16; + unsigned Index : 16; + IdentifierInfo *Name; + + TemplateTypeParmType(unsigned D, unsigned I, IdentifierInfo *N, + QualType Canon) + : Type(TemplateTypeParm, Canon, /*Dependent=*/true), + Depth(D), Index(I), Name(N) { } + + TemplateTypeParmType(unsigned D, unsigned I) + : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true), + Depth(D), Index(I), Name(0) { } + + friend class ASTContext; // ASTContext creates these + +public: + unsigned getDepth() const { return Depth; } + unsigned getIndex() const { return Index; } + IdentifierInfo *getName() const { return Name; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Depth, Index, Name); + } + + static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, + unsigned Index, IdentifierInfo *Name) { + ID.AddInteger(Depth); + ID.AddInteger(Index); + ID.AddPointer(Name); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; + } + static bool classof(const TemplateTypeParmType *T) { return true; } +}; + +/// \brief Represents the type of a template specialization as written +/// in the source code. +/// +/// Template specialization types represent the syntactic form of a +/// template-id that refers to a type, e.g., @c vector<int>. Some +/// template specialization types are syntactic sugar, whose canonical +/// type will point to some other type node that represents the +/// instantiation or class template specialization. For example, a +/// class template specialization type of @c vector<int> will refer to +/// a tag type for the instantiation +/// @c std::vector<int, std::allocator<int>>. +/// +/// Other template specialization types, for which the template name +/// is dependent, may be canonical types. These types are always +/// dependent. +class TemplateSpecializationType + : public Type, public llvm::FoldingSetNode { + + /// \brief The name of the template being specialized. + TemplateName Template; + + /// \brief - The number of template arguments named in this class + /// template specialization. + unsigned NumArgs; + + TemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, QualType Canon); + + virtual void Destroy(ASTContext& C); + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Determine whether any of the given template arguments are + /// dependent. + static bool anyDependentTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Print a template argument list, including the '<' and '>' + /// enclosing the template arguments. + static std::string PrintTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy); + + typedef const TemplateArgument * iterator; + + iterator begin() const { return getArgs(); } + iterator end() const; + + /// \brief Retrieve the name of the template that we are specializing. + TemplateName getTemplateName() const { return Template; } + + /// \brief Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return reinterpret_cast<const TemplateArgument *>(this + 1); + } + + /// \brief Retrieve the number of template arguments. + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve a specific template argument as a type. + /// \precondition @c isArgType(Arg) + const TemplateArgument &getArg(unsigned Idx) const; + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Template, getArgs(), NumArgs); + } + + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + const TemplateArgument *Args, unsigned NumArgs); + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateSpecialization; + } + static bool classof(const TemplateSpecializationType *T) { return true; } +}; + +/// \brief Represents a type that was referred to via a qualified +/// name, e.g., N::M::type. +/// +/// This type is used to keep track of a type name as written in the +/// source code, including any nested-name-specifiers. The type itself +/// is always "sugar", used to express what was written in the source +/// code but containing no additional semantic information. +class QualifiedNameType : public Type, public llvm::FoldingSetNode { + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// \brief The type that this qualified name refers to. + QualType NamedType; + + QualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType, + QualType CanonType) + : Type(QualifiedName, CanonType, NamedType->isDependentType()), + NNS(NNS), NamedType(NamedType) { } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// \brief Retrieve the type named by the qualified-id. + QualType getNamedType() const { return NamedType; } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, NNS, NamedType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + QualType NamedType) { + ID.AddPointer(NNS); + NamedType.Profile(ID); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == QualifiedName; + } + static bool classof(const QualifiedNameType *T) { return true; } +}; + +/// \brief Represents a 'typename' specifier that names a type within +/// a dependent type, e.g., "typename T::type". +/// +/// TypenameType has a very similar structure to QualifiedNameType, +/// which also involves a nested-name-specifier following by a type, +/// and (FIXME!) both can even be prefixed by the 'typename' +/// keyword. However, the two types serve very different roles: +/// QualifiedNameType is a non-semantic type that serves only as sugar +/// to show how a particular type was written in the source +/// code. TypenameType, on the other hand, only occurs when the +/// nested-name-specifier is dependent, such that we cannot resolve +/// the actual type until after instantiation. +class TypenameType : public Type, public llvm::FoldingSetNode { + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + typedef llvm::PointerUnion<const IdentifierInfo *, + const TemplateSpecializationType *> NameType; + + /// \brief The type that this typename specifier refers to. + NameType Name; + + TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name, + QualType CanonType) + : Type(Typename, CanonType, true), NNS(NNS), Name(Name) { + assert(NNS->isDependent() && + "TypenameType requires a dependent nested-name-specifier"); + } + + TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty, + QualType CanonType) + : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) { + assert(NNS->isDependent() && + "TypenameType requires a dependent nested-name-specifier"); + } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// \brief Retrieve the type named by the typename specifier as an + /// identifier. + /// + /// This routine will return a non-NULL identifier pointer when the + /// form of the original typename was terminated by an identifier, + /// e.g., "typename T::type". + const IdentifierInfo *getIdentifier() const { + return Name.dyn_cast<const IdentifierInfo *>(); + } + + /// \brief Retrieve the type named by the typename specifier as a + /// type specialization. + const TemplateSpecializationType *getTemplateId() const { + return Name.dyn_cast<const TemplateSpecializationType *>(); + } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, NNS, Name); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + NameType Name) { + ID.AddPointer(NNS); + ID.AddPointer(Name.getOpaqueValue()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Typename; + } + static bool classof(const TypenameType *T) { return true; } +}; + +/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for +/// object oriented design. They basically correspond to C++ classes. There +/// are two kinds of interface types, normal interfaces like "NSString" and +/// qualified interfaces, which are qualified with a protocol list like +/// "NSString<NSCopyable, NSAmazing>". Qualified interface types are instances +/// of ObjCQualifiedInterfaceType, which is a subclass of ObjCInterfaceType. +class ObjCInterfaceType : public Type { + ObjCInterfaceDecl *Decl; +protected: + ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) : + Type(tc, QualType(), /*Dependent=*/false), Decl(D) { } + friend class ASTContext; // ASTContext creates these. +public: + + ObjCInterfaceDecl *getDecl() const { return Decl; } + + /// qual_iterator and friends: this provides access to the (potentially empty) + /// list of protocols qualifying this interface. If this is an instance of + /// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an + /// empty list if there are no qualifying protocols. + typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; + inline qual_iterator qual_begin() const; + inline qual_iterator qual_end() const; + bool qual_empty() const { return getTypeClass() != ObjCQualifiedInterface; } + + /// getNumProtocols - Return the number of qualifying protocols in this + /// interface type, or 0 if there are none. + inline unsigned getNumProtocols() const; + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCInterface || + T->getTypeClass() == ObjCQualifiedInterface; + } + static bool classof(const ObjCInterfaceType *) { return true; } +}; + +/// ObjCQualifiedInterfaceType - This class represents interface types +/// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>. +/// +/// Duplicate protocols are removed and protocol list is canonicalized to be in +/// alphabetical order. +class ObjCQualifiedInterfaceType : public ObjCInterfaceType, + public llvm::FoldingSetNode { + + // List of protocols for this protocol conforming object type + // List is sorted on protocol name. No protocol is enterred more than once. + llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; + + ObjCQualifiedInterfaceType(ObjCInterfaceDecl *D, + ObjCProtocolDecl **Protos, unsigned NumP) : + ObjCInterfaceType(ObjCQualifiedInterface, D), + Protocols(Protos, Protos+NumP) { } + friend class ASTContext; // ASTContext creates these. +public: + + unsigned getNumProtocols() const { + return Protocols.size(); + } + + qual_iterator qual_begin() const { return Protocols.begin(); } + qual_iterator qual_end() const { return Protocols.end(); } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **protocols, unsigned NumProtocols); + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCQualifiedInterface; + } + static bool classof(const ObjCQualifiedInterfaceType *) { return true; } +}; + +inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_begin() const { + if (const ObjCQualifiedInterfaceType *QIT = + dyn_cast<ObjCQualifiedInterfaceType>(this)) + return QIT->qual_begin(); + return 0; +} +inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_end() const { + if (const ObjCQualifiedInterfaceType *QIT = + dyn_cast<ObjCQualifiedInterfaceType>(this)) + return QIT->qual_end(); + return 0; +} + +/// getNumProtocols - Return the number of qualifying protocols in this +/// interface type, or 0 if there are none. +inline unsigned ObjCInterfaceType::getNumProtocols() const { + if (const ObjCQualifiedInterfaceType *QIT = + dyn_cast<ObjCQualifiedInterfaceType>(this)) + return QIT->getNumProtocols(); + return 0; +} + +/// ObjCQualifiedIdType - to represent id<protocol-list>. +/// +/// Duplicate protocols are removed and protocol list is canonicalized to be in +/// alphabetical order. +class ObjCQualifiedIdType : public Type, + public llvm::FoldingSetNode { + // List of protocols for this protocol conforming 'id' type + // List is sorted on protocol name. No protocol is enterred more than once. + llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; + + ObjCQualifiedIdType(ObjCProtocolDecl **Protos, unsigned NumP) + : Type(ObjCQualifiedId, QualType()/*these are always canonical*/, + /*Dependent=*/false), + Protocols(Protos, Protos+NumP) { } + friend class ASTContext; // ASTContext creates these. +public: + + unsigned getNumProtocols() const { + return Protocols.size(); + } + + typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; + qual_iterator qual_begin() const { return Protocols.begin(); } + qual_iterator qual_end() const { return Protocols.end(); } + + virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + ObjCProtocolDecl **protocols, unsigned NumProtocols); + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCQualifiedId; + } + static bool classof(const ObjCQualifiedIdType *) { return true; } + +}; + +// Inline function definitions. + +/// getUnqualifiedType - Return the type without any qualifiers. +inline QualType QualType::getUnqualifiedType() const { + Type *TP = getTypePtr(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(TP)) + TP = EXTQT->getBaseType(); + return QualType(TP, 0); +} + +/// getAddressSpace - Return the address space of this type. +inline unsigned QualType::getAddressSpace() const { + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) + return AT->getElementType().getAddressSpace(); + if (const RecordType *RT = dyn_cast<RecordType>(CT)) + return RT->getAddressSpace(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT)) + return EXTQT->getAddressSpace(); + return 0; +} + +/// getObjCGCAttr - Return the gc attribute of this type. +inline QualType::GCAttrTypes QualType::getObjCGCAttr() const { + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) + return AT->getElementType().getObjCGCAttr(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT)) + return EXTQT->getObjCGCAttr(); + if (const PointerType *PT = CT->getAsPointerType()) + return PT->getPointeeType().getObjCGCAttr(); + return GCNone; +} + +/// isMoreQualifiedThan - Determine whether this type is more +/// qualified than the Other type. For example, "const volatile int" +/// is more qualified than "const int", "volatile int", and +/// "int". However, it is not more qualified than "const volatile +/// int". +inline bool QualType::isMoreQualifiedThan(QualType Other) const { + unsigned MyQuals = this->getCVRQualifiers(); + unsigned OtherQuals = Other.getCVRQualifiers(); + if (getAddressSpace() != Other.getAddressSpace()) + return false; + return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals; +} + +/// 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 { + unsigned MyQuals = this->getCVRQualifiers(); + unsigned OtherQuals = Other.getCVRQualifiers(); + if (getAddressSpace() != Other.getAddressSpace()) + return false; + return (MyQuals | OtherQuals) == MyQuals; +} + +/// getNonReferenceType - If Type is a reference type (e.g., const +/// int&), returns the type that the reference refers to ("const +/// int"). Otherwise, returns the type itself. This routine is used +/// throughout Sema to implement C++ 5p6: +/// +/// If an expression initially has the type "reference to T" (8.3.2, +/// 8.5.3), the type is adjusted to "T" prior to any further +/// analysis, the expression designates the object or function +/// denoted by the reference, and the expression is an lvalue. +inline QualType QualType::getNonReferenceType() const { + if (const ReferenceType *RefType = (*this)->getAsReferenceType()) + return RefType->getPointeeType(); + else + return *this; +} + +inline const TypedefType* Type::getAsTypedefType() const { + return dyn_cast<TypedefType>(this); +} +inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { + if (const PointerType *PT = getAsPointerType()) + return PT->getPointeeType()->getAsObjCInterfaceType(); + return 0; +} + +// NOTE: All of these methods use "getUnqualifiedType" to strip off address +// space qualifiers if present. +inline bool Type::isFunctionType() const { + return isa<FunctionType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isPointerType() const { + return isa<PointerType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isBlockPointerType() const { + return isa<BlockPointerType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isReferenceType() const { + return isa<ReferenceType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isLValueReferenceType() const { + return isa<LValueReferenceType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isRValueReferenceType() const { + return isa<RValueReferenceType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isFunctionPointerType() const { + if (const PointerType* T = getAsPointerType()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} +inline bool Type::isMemberPointerType() const { + return isa<MemberPointerType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isMemberFunctionPointerType() const { + if (const MemberPointerType* T = getAsMemberPointerType()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} +inline bool Type::isArrayType() const { + return isa<ArrayType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isConstantArrayType() const { + return isa<ConstantArrayType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isIncompleteArrayType() const { + return isa<IncompleteArrayType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isVariableArrayType() const { + return isa<VariableArrayType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isDependentSizedArrayType() const { + return isa<DependentSizedArrayType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isRecordType() const { + return isa<RecordType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isAnyComplexType() const { + return isa<ComplexType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isVectorType() const { + return isa<VectorType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isExtVectorType() const { + return isa<ExtVectorType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isObjCInterfaceType() const { + return isa<ObjCInterfaceType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isObjCQualifiedInterfaceType() const { + return isa<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isObjCQualifiedIdType() const { + return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isTemplateTypeParmType() const { + return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType()); +} + +inline bool Type::isSpecificBuiltinType(unsigned K) const { + if (const BuiltinType *BT = getAsBuiltinType()) + if (BT->getKind() == (BuiltinType::Kind) K) + return true; + return false; +} + +/// \brief Determines whether this is a type for which one can define +/// an overloaded operator. +inline bool Type::isOverloadableType() const { + return isDependentType() || isRecordType() || isEnumeralType(); +} + +inline bool Type::hasPointerRepresentation() const { + return (isPointerType() || isReferenceType() || isBlockPointerType() || + isObjCInterfaceType() || isObjCQualifiedIdType() || + isObjCQualifiedInterfaceType() || isNullPtrType()); +} + +inline bool Type::hasObjCPointerRepresentation() const { + return (isObjCInterfaceType() || isObjCQualifiedIdType() || + isObjCQualifiedInterfaceType()); +} + +/// Insertion operator for diagnostics. This allows sending QualType's into a +/// diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + QualType T) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + Diagnostic::ak_qualtype); + return DB; +} + +} // end namespace clang + +#endif diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def new file mode 100644 index 000000000000..76cbed311d79 --- /dev/null +++ b/include/clang/AST/TypeNodes.def @@ -0,0 +1,85 @@ +//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- 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 AST type info database. Each type node is +// enumerated by providing its name (e.g., "Builtin" or "Enum") and +// base class (e.g., "Type" or "TagType"). Depending on where in the +// abstract syntax tree the type will show up, the enumeration uses +// one of four different macros: +// +// TYPE(Class, Base) - A type that can show up anywhere in the AST, +// and might be dependent, canonical, or non-canonical. All clients +// will need to understand these types. +// +// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in +// the type hierarchy but has no concrete instances. +// +// NON_CANONICAL_TYPE(Class, Base) - A type that can show up +// anywhere in the AST but will never be a part of a canonical +// type. Clients that only need to deal with canonical types +// (ignoring, e.g., typedefs and other type alises used for +// pretty-printing) can ignore these types. +// +// DEPENDENT_TYPE(Class, Base) - A type that will only show up +// within a C++ template that has not been instantiated, e.g., a +// type that is always dependent. Clients that do not need to deal +// with uninstantiated C++ templates can ignore these types. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPE +# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef NON_CANONICAL_TYPE +# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef DEPENDENT_TYPE +# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +TYPE(ExtQual, Type) +TYPE(Builtin, Type) +TYPE(FixedWidthInt, Type) +TYPE(Complex, Type) +TYPE(Pointer, Type) +TYPE(BlockPointer, Type) +ABSTRACT_TYPE(Reference, Type) +TYPE(LValueReference, ReferenceType) +TYPE(RValueReference, ReferenceType) +TYPE(MemberPointer, Type) +ABSTRACT_TYPE(Array, Type) +TYPE(ConstantArray, ArrayType) +TYPE(IncompleteArray, ArrayType) +TYPE(VariableArray, ArrayType) +DEPENDENT_TYPE(DependentSizedArray, ArrayType) +TYPE(Vector, Type) +TYPE(ExtVector, VectorType) +ABSTRACT_TYPE(Function, Type) +TYPE(FunctionProto, FunctionType) +TYPE(FunctionNoProto, FunctionType) +NON_CANONICAL_TYPE(Typedef, Type) +NON_CANONICAL_TYPE(TypeOfExpr, Type) +NON_CANONICAL_TYPE(TypeOf, Type) +ABSTRACT_TYPE(Tag, Type) +TYPE(Record, TagType) +TYPE(Enum, TagType) +DEPENDENT_TYPE(TemplateTypeParm, Type) +TYPE(TemplateSpecialization, Type) +NON_CANONICAL_TYPE(QualifiedName, Type) +DEPENDENT_TYPE(Typename, Type) +TYPE(ObjCInterface, Type) +TYPE(ObjCQualifiedInterface, ObjCInterfaceType) +TYPE(ObjCQualifiedId, Type) + +#undef DEPENDENT_TYPE +#undef NON_CANONICAL_TYPE +#undef ABSTRACT_TYPE +#undef TYPE diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h new file mode 100644 index 000000000000..4f60273d6809 --- /dev/null +++ b/include/clang/AST/TypeOrdering.h @@ -0,0 +1,63 @@ +//===-------------- TypeOrdering.h - Total ordering for types -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a function objects and specializations that +// allow QualType values to be sorted, used in std::maps, std::sets, +// llvm::DenseMaps, and llvm::DenseSets. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TYPE_ORDERING_H +#define LLVM_CLANG_TYPE_ORDERING_H + +#include "clang/AST/Type.h" +#include <functional> + +namespace clang { + +/// QualTypeOrdering - Function object that provides a total ordering +/// on QualType values. +struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> { + bool operator()(QualType T1, QualType T2) const { + return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr()); + } +}; + +} + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::QualType> { + static inline clang::QualType getEmptyKey() { return clang::QualType(); } + + static inline clang::QualType getTombstoneKey() { + using clang::QualType; + return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::QualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::QualType LHS, clang::QualType RHS) { + return LHS == RHS; + } + + static bool isPod() { + // QualType isn't *technically* a POD type. However, we can get + // away with calling it a POD type since its copy constructor, + // copy assignment operator, and destructor are all trivial. + return true; + } + }; +} + +#endif diff --git a/include/clang/AST/X86Builtins.def b/include/clang/AST/X86Builtins.def new file mode 100644 index 000000000000..710efa8cee4b --- /dev/null +++ b/include/clang/AST/X86Builtins.def @@ -0,0 +1,427 @@ +//===--- X86Builtins.def - X86 Builtin function database --------*- 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 X86-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: this needs to be the full list supported by GCC. Right now, I'm just +// adding stuff on demand. + +// The format of this database matches clang/AST/Builtins.def. + +// FIXME: In GCC, these builtins are defined depending on whether support for +// MMX/SSE/etc is turned on. We should do this too. + +// FIXME: Ideally we would be able to pull this information from what +// LLVM already knows about X86 builtins. We need to match the LLVM +// definition anyway, since code generation will lower to the +// intrinsic if one exists. + +BUILTIN(__builtin_ia32_emms , "v", "") + +// FIXME: Are these nothrow/const? + +// SSE intrinsics. +BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comile, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comige, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_addps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_subps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_mulps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_divps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_addss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_subss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_mulss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_divss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fc", "") +BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fc", "") +BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_andps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_andnps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_orps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_xorps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_movss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_movhlps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_movlhps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_unpckhps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_unpcklps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_addpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_subpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_mulpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_divpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_addsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_subsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_mulsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_divsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dc", "") +BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dc", "") +BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_andpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_andnpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_orpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_xorpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_movsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_unpckhpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_unpcklpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_paddb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_paddw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_paddd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_paddq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psubb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psubw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psubd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psubq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pand128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_pandn128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_por128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_pxor128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_punpckhbw128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_punpckhwd128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_punpckhdq128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_punpckhqdq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_punpcklbw128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_punpcklwd128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_punpckldq128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_punpcklqdq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "") +BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "") +BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "") +BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "") +BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "") +BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "") +BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_pshufw, "V4sV4si", "") +BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "") +BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "") +BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "") +BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "") +BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "") +BUILTIN(__builtin_ia32_stmxcsr, "Ui", "") +BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "") +BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_cvtsi2ss, "V4fV4fi", "") +BUILTIN(__builtin_ia32_cvtsi642ss, "V4fV4fLLi", "") +BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "") +BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "") +BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_cvttss2si, "iV4f", "") +BUILTIN(__builtin_ia32_cvttss2si64, "LLiV4f", "") +BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "") +BUILTIN(__builtin_ia32_loadups, "V4ffC*", "") +BUILTIN(__builtin_ia32_storeups, "vf*V4f", "") +BUILTIN(__builtin_ia32_loadhps, "V4fV4fV2i*", "") +BUILTIN(__builtin_ia32_loadlps, "V4fV4fV2i*", "") +BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "") +BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "") +BUILTIN(__builtin_ia32_movmskps, "iV4f", "") +BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "") +BUILTIN(__builtin_ia32_movntps, "vf*V4f", "") +BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "") +BUILTIN(__builtin_ia32_sfence, "v", "") +BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "") +BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "") +BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "") +BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "") +BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "") +BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "") +BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "") +BUILTIN(__builtin_ia32_shufps, "V4fV4fV4fi", "") +BUILTIN(__builtin_ia32_femms, "v", "") +BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "") +BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "") +BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "") +BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "") +BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "") +BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "") +BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "") +BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "") +BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "") +BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "") +BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "") +BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "") +BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "") +BUILTIN(__builtin_ia32_loadupd, "V2ddC*", "") +BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "") +BUILTIN(__builtin_ia32_loadhpd, "V2dV2ddC*", "") +BUILTIN(__builtin_ia32_loadlpd, "V2dV2ddC*", "") +BUILTIN(__builtin_ia32_movmskpd, "iV2d", "") +BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "") +BUILTIN(__builtin_ia32_movnti, "vi*i", "") +BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "") +BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "") +BUILTIN(__builtin_ia32_pshufd, "V4iV4ii", "") +BUILTIN(__builtin_ia32_pshuflw, "V8sV8si", "") +BUILTIN(__builtin_ia32_pshufhw, "V8sV8si", "") +BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "") +BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "") +BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "") +BUILTIN(__builtin_ia32_shufpd, "V2dV2dV2di", "") +BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "") +BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "") +BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "") +BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "") +BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "") +BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "") +BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "") +BUILTIN(__builtin_ia32_cvttsd2si, "iV2d", "") +BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "") +BUILTIN(__builtin_ia32_cvttsd2si64, "LLiV2d", "") +BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "") +BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "") +BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "") +BUILTIN(__builtin_ia32_cvtsi2sd, "V2dV2di", "") +BUILTIN(__builtin_ia32_cvtsi642sd, "V2dV2dLLi", "") +BUILTIN(__builtin_ia32_cvtsd2ss, "V4fV4fV2d", "") +BUILTIN(__builtin_ia32_cvtss2sd, "V2dV2dV4f", "") +BUILTIN(__builtin_ia32_clflush, "vvC*", "") +BUILTIN(__builtin_ia32_lfence, "v", "") +BUILTIN(__builtin_ia32_mfence, "v", "") +BUILTIN(__builtin_ia32_loaddqu, "V16ccC*", "") +BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "") +BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "") +BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "") +BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "") +BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "") +BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "") +BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "") +BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "") +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_psrlq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "") +BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "") +BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") +BUILTIN(__builtin_ia32_mwait, "vUiUi", "") +BUILTIN(__builtin_ia32_movshdup, "V4fV4f", "") +BUILTIN(__builtin_ia32_movsldup, "V4fV4f", "") +BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") +BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "") +BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "") +BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "") +BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "") +BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "") +BUILTIN(__builtin_ia32_vec_ext_v2df, "dV2di", "") +BUILTIN(__builtin_ia32_vec_ext_v2di, "LLiV2LLii", "") +BUILTIN(__builtin_ia32_vec_ext_v4sf, "fV4fi", "") +BUILTIN(__builtin_ia32_vec_ext_v4si, "iV4ii", "") +BUILTIN(__builtin_ia32_vec_ext_v8hi, "UsV8si", "") +BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4si", "") +BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "") +BUILTIN(__builtin_ia32_vec_set_v8hi, "V8sV8ssi", "") +BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssi", "") +BUILTIN(__builtin_ia32_vec_set_v16qi, "V16cV16cii", "") +BUILTIN(__builtin_ia32_vec_set_v4si, "V4iV4iii", "") +BUILTIN(__builtin_ia32_vec_set_v2di, "V2LLiV2LLiLLii", "") +BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") + +BUILTIN(__builtin_ia32_loadlv4si, "V4iV2i*", "") +BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") + +BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "") +BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8si", "") +BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2di", "") +BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fi", "") +BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmovsxbd128, "V4iV16c", "") +BUILTIN(__builtin_ia32_pmovsxbq128, "V2LLiV16c", "") +BUILTIN(__builtin_ia32_pmovsxbw128, "V8sV16c", "") +BUILTIN(__builtin_ia32_pmovsxdq128, "V2LLiV4i", "") +BUILTIN(__builtin_ia32_pmovsxwd128, "V4iV8s", "") +BUILTIN(__builtin_ia32_pmovsxwq128, "V2LLiV8s", "") +BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "") +BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "") +BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "") +BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "") +BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "") +BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "") +BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "") +BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "") +BUILTIN(__builtin_ia32_roundss, "V4fV4fi", "") +BUILTIN(__builtin_ia32_roundsd, "V2dV2di", "") +BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "") + + +#undef BUILTIN diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h new file mode 100644 index 000000000000..b41cd684e951 --- /dev/null +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -0,0 +1,119 @@ +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIVEVARIABLES_H +#define LLVM_CLANG_LIVEVARIABLES_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/Support/BlkExprDeclBitVector.h" +#include "clang/Analysis/FlowSensitive/DataflowValues.h" + +namespace clang { + +class Stmt; +class DeclRefExpr; +class SourceManager; + +struct LiveVariables_ValueTypes { + + struct ObserverTy; + + // We keep dataflow state for declarations and block-level expressions; + typedef StmtDeclBitVector_Types::ValTy ValTy; + + // We need to keep track of both declarations and CFGBlock-level expressions, + // (so that we don't explore such expressions twice). We also want + // to compute liveness information for block-level expressions, since these + // act as "temporary" values. + + struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { + ObserverTy* Observer; + ValTy AlwaysLive; + + AnalysisDataTy() : Observer(NULL) {} + }; + + //===-----------------------------------------------------===// + // ObserverTy - Observer for uninitialized values queries. + //===-----------------------------------------------------===// + + struct ObserverTy { + virtual ~ObserverTy() {} + + /// ObserveStmt - A callback invoked right before invoking the + /// liveness transfer function on the given statement. + virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD, + const ValTy& V) {} + + virtual void ObserverKill(DeclRefExpr* DR) {} + }; +}; + +class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, + dataflow::backward_analysis_tag> { + + +public: + typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; + + LiveVariables(ASTContext& Ctx, CFG& cfg); + + /// IsLive - Return true if a variable is live at beginning of a + /// specified block. + bool isLive(const CFGBlock* B, const VarDecl* D) const; + + /// IsLive - Returns true if a variable is live at the beginning of the + /// the statement. This query only works if liveness information + /// has been recorded at the statement level (see runOnAllBlocks), and + /// only returns liveness information for block-level expressions. + bool isLive(const Stmt* S, const VarDecl* D) const; + + /// IsLive - Returns true the block-level expression "value" is live + /// before the given block-level expression (see runOnAllBlocks). + bool isLive(const Stmt* Loc, const Stmt* StmtVal) const; + + /// IsLive - Return true if a variable is live according to the + /// provided livness bitvector. + bool isLive(const ValTy& V, const VarDecl* D) const; + + /// dumpLiveness - Print to stderr the liveness information encoded + /// by a specified bitvector. + void dumpLiveness(const ValTy& V, SourceManager& M) const; + + /// dumpBlockLiveness - Print to stderr the liveness information + /// associated with each basic block. + void dumpBlockLiveness(SourceManager& M) const; + + /// getNumDecls - Return the number of variables (declarations) that + /// whose liveness status is being tracked by the dataflow + /// analysis. + unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); } + + /// IntializeValues - This routine can perform extra initialization, but + /// for LiveVariables this does nothing since all that logic is in + /// the constructor. + void InitializeValues(const CFG& cfg) {} + + void runOnCFG(CFG& cfg); + + /// runOnAllBlocks - Propagate the dataflow values once for each block, + /// starting from the current dataflow values. 'recordStmtValues' indicates + /// whether the method should store dataflow values per each individual + /// block-level expression. + void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs, + bool recordStmtValues=false); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h new file mode 100644 index 000000000000..7a9da03e4bd2 --- /dev/null +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -0,0 +1,74 @@ +//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Unintialized Values analysis, +// a flow-sensitive analysis that detects when variable values are unintialized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_UNITVALS_H +#define LLVM_CLANG_UNITVALS_H + +#include "clang/Analysis/Support/BlkExprDeclBitVector.h" +#include "clang/Analysis/FlowSensitive/DataflowValues.h" + +namespace clang { + + class BlockVarDecl; + class Expr; + class DeclRefExpr; + class VarDecl; + +/// UninitializedValues_ValueTypes - Utility class to wrap type declarations +/// for dataflow values and dataflow analysis state for the +/// Unitialized Values analysis. +class UninitializedValues_ValueTypes { +public: + + struct ObserverTy; + + struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { + AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {} + virtual ~AnalysisDataTy() {}; + + ObserverTy* Observer; + bool FullUninitTaint; + }; + + typedef StmtDeclBitVector_Types::ValTy ValTy; + + //===--------------------------------------------------------------------===// + // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized + // value. + //===--------------------------------------------------------------------===// + + struct ObserverTy { + virtual ~ObserverTy(); + virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD, + DeclRefExpr* DR, VarDecl* VD) = 0; + }; +}; + +/// UninitializedValues - Objects of this class encapsulate dataflow analysis +/// information regarding what variable declarations in a function are +/// potentially unintialized. +class UninitializedValues : + public DataflowValues<UninitializedValues_ValueTypes> { +public: + typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy; + + UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); } + + /// IntializeValues - Create initial dataflow values and meta data for + /// a given CFG. This is intended to be called by the dataflow solver. + void InitializeValues(const CFG& cfg); +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h new file mode 100644 index 000000000000..e82dc9ed9f3f --- /dev/null +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- 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_DIAGNOSTICANALYSIS_H +#define LLVM_CLANG_DIAGNOSTICANALYSIS_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define ANALYSISSTART +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#undef DIAG + NUM_BUILTIN_ANALYSIS_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h new file mode 100644 index 000000000000..38612593368b --- /dev/null +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -0,0 +1,291 @@ +//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- 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 skeleton code for implementing dataflow analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER +#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER + +#include "clang/AST/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "functional" // STL + +namespace clang { + +//===----------------------------------------------------------------------===// +/// DataflowWorkListTy - Data structure representing the worklist used for +/// dataflow algorithms. +//===----------------------------------------------------------------------===// + +class DataflowWorkListTy { + typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; + BlockSet wlist; +public: + /// enqueue - Add a block to the worklist. Blocks already on the + /// worklist are not added a second time. + void enqueue(const CFGBlock* B) { wlist.insert(B); } + + /// dequeue - Remove a block from the worklist. + const CFGBlock* dequeue() { + assert (!wlist.empty()); + const CFGBlock* B = *wlist.begin(); + wlist.erase(B); + return B; + } + + /// isEmpty - Return true if the worklist is empty. + bool isEmpty() const { return wlist.empty(); } +}; + +//===----------------------------------------------------------------------===// +// BlockItrTraits - Traits classes that allow transparent iteration +// over successors/predecessors of a block depending on the direction +// of our dataflow analysis. +//===----------------------------------------------------------------------===// + +namespace dataflow { +template<typename Tag> struct ItrTraits {}; + +template <> struct ItrTraits<forward_analysis_tag> { + typedef CFGBlock::const_pred_iterator PrevBItr; + typedef CFGBlock::const_succ_iterator NextBItr; + typedef CFGBlock::const_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); } + static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); } + static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); } + + static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); } + static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); } + + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + return BlockEdge(Prev, B); + } + + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + return BlockEdge(B, Next); + } +}; + +template <> struct ItrTraits<backward_analysis_tag> { + typedef CFGBlock::const_succ_iterator PrevBItr; + typedef CFGBlock::const_pred_iterator NextBItr; + typedef CFGBlock::const_reverse_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); } + static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); } + + static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); } + static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); } + + static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); } + static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } + + static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + return BlockEdge(B, Prev); + } + + static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + return BlockEdge(Next, B); + } +}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowSolverTy - Generic dataflow solver. +//===----------------------------------------------------------------------===// + +template <typename _DFValuesTy, // Usually a subclass of DataflowValues + typename _TransferFuncsTy, + typename _MergeOperatorTy, + typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> > +class DataflowSolver { + + //===----------------------------------------------------===// + // Type declarations. + //===----------------------------------------------------===// + +public: + typedef _DFValuesTy DFValuesTy; + typedef _TransferFuncsTy TransferFuncsTy; + typedef _MergeOperatorTy MergeOperatorTy; + + typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; + typedef typename _DFValuesTy::ValTy ValTy; + typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy; + typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; + + typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits; + typedef typename ItrTraits::NextBItr NextBItr; + typedef typename ItrTraits::PrevBItr PrevBItr; + typedef typename ItrTraits::StmtItr StmtItr; + + //===----------------------------------------------------===// + // External interface: constructing and running the solver. + //===----------------------------------------------------===// + +public: + DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {} + ~DataflowSolver() {} + + /// runOnCFG - Computes dataflow values for all blocks in a CFG. + void runOnCFG(CFG& cfg, bool recordStmtValues = false) { + // Set initial dataflow values and boundary conditions. + D.InitializeValues(cfg); + // Solve the dataflow equations. This will populate D.EdgeDataMap + // with dataflow values. + SolveDataflowEquations(cfg, recordStmtValues); + } + + /// runOnBlock - Computes dataflow values for a given block. This + /// should usually be invoked only after previously computing + /// dataflow values using runOnCFG, as runOnBlock is intended to + /// only be used for querying the dataflow values within a block + /// with and Observer object. + void runOnBlock(const CFGBlock* B, bool recordStmtValues) { + BlockDataMapTy& M = D.getBlockDataMap(); + typename BlockDataMapTy::iterator I = M.find(B); + + if (I != M.end()) { + TF.getVal().copyValues(I->second); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + } + } + + void runOnBlock(const CFGBlock& B, bool recordStmtValues) { + runOnBlock(&B, recordStmtValues); + } + void runOnBlock(CFG::iterator& I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + + void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) { + for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + runOnBlock(I, recordStmtValues); + } + + //===----------------------------------------------------===// + // Internal solver logic. + //===----------------------------------------------------===// + +private: + + /// SolveDataflowEquations - Perform the actual worklist algorithm + /// to compute dataflow values. + void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) { + // Enqueue all blocks to ensure the dataflow values are computed + // for every block. Not all blocks are guaranteed to reach the exit block. + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + WorkList.enqueue(&*I); + + while (!WorkList.isEmpty()) { + const CFGBlock* B = WorkList.dequeue(); + ProcessMerge(cfg,B); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + UpdateEdges(cfg,B,TF.getVal()); + } + } + + void ProcessMerge(CFG& cfg, const CFGBlock* B) { + ValTy& V = TF.getVal(); + TF.SetTopValue(V); + + // Merge dataflow values from all predecessors of this block. + MergeOperatorTy Merge; + + EdgeDataMapTy& M = D.getEdgeDataMap(); + bool firstMerge = true; + + for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){ + + typename EdgeDataMapTy::iterator EI = + M.find(ItrTraits::PrevEdge(B, *I)); + + if (EI != M.end()) { + if (firstMerge) { + firstMerge = false; + V.copyValues(EI->second); + } + else Merge(V,EI->second); + } + } + + // Set the data for the block. + D.getBlockDataMap()[B].copyValues(V); + } + + /// ProcessBlock - Process the transfer functions for a given block. + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + dataflow::forward_analysis_tag) { + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) + ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + } + + void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + dataflow::backward_analysis_tag) { + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) + ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + } + + void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { + if (record) D.getStmtDataMap()[S] = TF.getVal(); + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + } + + void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){ + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + if (record) D.getStmtDataMap()[S] = TF.getVal(); + } + + /// UpdateEdges - After processing the transfer functions for a + /// block, update the dataflow value associated with the block's + /// outgoing/incoming edges (depending on whether we do a + // forward/backward analysis respectively) + void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) { + for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) + UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I); + } + + /// UpdateEdgeValue - Update the value associated with a given edge. + void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) { + EdgeDataMapTy& M = D.getEdgeDataMap(); + typename EdgeDataMapTy::iterator I = M.find(E); + + if (I == M.end()) { // First computed value for this edge? + M[E].copyValues(V); + WorkList.enqueue(TargetBlock); + } + else if (!_Equal()(V,I->second)) { + I->second.copyValues(V); + WorkList.enqueue(TargetBlock); + } + } + +private: + DFValuesTy& D; + DataflowWorkListTy WorkList; + TransferFuncsTy TF; +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h new file mode 100644 index 000000000000..d6427a5cab47 --- /dev/null +++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -0,0 +1,172 @@ +//===--- DataflowValues.h - Data structure for dataflow 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 a skeleton data structure for encapsulating the dataflow +// values for a CFG. Typically this is subclassed to provide methods for +// computing these values from a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES +#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES + +#include "clang/AST/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/DenseMap.h" + +//===----------------------------------------------------------------------===// +/// Dataflow Directional Tag Classes. These are used for tag dispatching +/// within the dataflow solver/transfer functions to determine what direction +/// a dataflow analysis flows. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace dataflow { + struct forward_analysis_tag {}; + struct backward_analysis_tag {}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowValues. Container class to store dataflow values for a CFG. +//===----------------------------------------------------------------------===// + +template <typename ValueTypes, + typename _AnalysisDirTag = dataflow::forward_analysis_tag > +class DataflowValues { + + //===--------------------------------------------------------------------===// + // Type declarations. + //===--------------------------------------------------------------------===// + +public: + typedef typename ValueTypes::ValTy ValTy; + typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; + typedef _AnalysisDirTag AnalysisDirTag; + typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; + typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; + typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy; + + //===--------------------------------------------------------------------===// + // Predicates. + //===--------------------------------------------------------------------===// + +public: + /// isForwardAnalysis - Returns true if the dataflow values are computed + /// from a forward analysis. + bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } + + /// isBackwardAnalysis - Returns true if the dataflow values are computed + /// from a backward analysis. + bool isBackwardAnalysis() { return !isForwardAnalysis(); } + +private: + bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + + //===--------------------------------------------------------------------===// + // Initialization and accessors methods. + //===--------------------------------------------------------------------===// + +public: + DataflowValues() : StmtDataMap(NULL) {} + ~DataflowValues() { delete StmtDataMap; } + + /// InitializeValues - Invoked by the solver to initialize state needed for + /// dataflow analysis. This method is usually specialized by subclasses. + void InitializeValues(const CFG& cfg) {}; + + + /// getEdgeData - Retrieves the dataflow values associated with a + /// CFG edge. + ValTy& getEdgeData(const BlockEdge& E) { + typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E); + assert (I != EdgeDataMap.end() && "No data associated with Edge."); + return I->second; + } + + const ValTy& getEdgeData(const BlockEdge& E) const { + return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); + } + + /// getBlockData - Retrieves the dataflow values associated with a + /// specified CFGBlock. If the dataflow analysis is a forward analysis, + /// this data is associated with the END of the block. If the analysis + /// is a backwards analysis, it is associated with the ENTRY of the block. + ValTy& getBlockData(const CFGBlock* B) { + typename BlockDataMapTy::iterator I = BlockDataMap.find(B); + assert (I != BlockDataMap.end() && "No data associated with block."); + return I->second; + } + + const ValTy& getBlockData(const CFGBlock* B) const { + return const_cast<DataflowValues*>(this)->getBlockData(B); + } + + /// getStmtData - Retrieves the dataflow values associated with a + /// specified Stmt. If the dataflow analysis is a forward analysis, + /// this data corresponds to the point immediately before a Stmt. + /// If the analysis is a backwards analysis, it is associated with + /// the point after a Stmt. This data is only computed for block-level + /// expressions, and only when requested when the analysis is executed. + ValTy& getStmtData(const Stmt* S) { + assert (StmtDataMap && "Dataflow values were not computed for statements."); + typename StmtDataMapTy::iterator I = StmtDataMap->find(S); + assert (I != StmtDataMap->end() && "No data associated with statement."); + return I->second; + } + + const ValTy& getStmtData(const Stmt* S) const { + return const_cast<DataflowValues*>(this)->getStmtData(S); + } + + /// getEdgeDataMap - Retrieves the internal map between CFG edges and + /// dataflow values. Usually used by a dataflow solver to compute + /// values for blocks. + EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; } + const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; } + + /// getBlockDataMap - Retrieves the internal map between CFGBlocks and + /// dataflow values. If the dataflow analysis operates in the forward + /// direction, the values correspond to the dataflow values at the start + /// of the block. Otherwise, for a backward analysis, the values correpsond + /// to the dataflow values at the end of the block. + BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } + const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } + + /// getStmtDataMap - Retrieves the internal map between Stmts and + /// dataflow values. + StmtDataMapTy& getStmtDataMap() { + if (!StmtDataMap) StmtDataMap = new StmtDataMapTy(); + return *StmtDataMap; + } + + const StmtDataMapTy& getStmtDataMap() const { + return const_cast<DataflowValues*>(this)->getStmtDataMap(); + } + + /// getAnalysisData - Retrieves the meta data associated with a + /// dataflow analysis for analyzing a particular CFG. + /// This is typically consumed by transfer function code (via the solver). + /// This can also be used by subclasses to interpret the dataflow values. + AnalysisDataTy& getAnalysisData() { return AnalysisData; } + const AnalysisDataTy& getAnalysisData() const { return AnalysisData; } + + //===--------------------------------------------------------------------===// + // Internal data. + //===--------------------------------------------------------------------===// + +protected: + EdgeDataMapTy EdgeDataMap; + BlockDataMapTy BlockDataMap; + StmtDataMapTy* StmtDataMap; + AnalysisDataTy AnalysisData; +}; + +} // end namespace clang +#endif diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h new file mode 100644 index 000000000000..23610f9a2d97 --- /dev/null +++ b/include/clang/Analysis/LocalCheckers.h @@ -0,0 +1,54 @@ +//==- 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; + +void CheckDeadStores(LiveVariables& L, BugReporter& BR); + +void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, + bool FullUninitTaint=false); + +GRTransferFuncs* MakeGRSimpleValsTF(); +GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); + +void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, + BugReporter& BR); + +void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); +void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR); + +void RegisterAppleChecks(GRExprEngine& Eng); + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h new file mode 100644 index 000000000000..994b35e5efda --- /dev/null +++ b/include/clang/Analysis/PathDiagnostic.h @@ -0,0 +1,487 @@ +//===--- PathDiagnostic.h - Path-Specific Diagnostic 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 PathDiagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H +#define LLVM_CLANG_PATH_DIAGNOSTIC_H + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/OwningPtr.h" + +#include <vector> +#include <deque> +#include <string> +#include <algorithm> + +namespace clang { + +//===----------------------------------------------------------------------===// +// High-level interface for handlers of path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnostic; +class Stmt; +class Decl; +class Preprocessor; + +class PathDiagnosticClient : public DiagnosticClient { +public: + PathDiagnosticClient() {} + virtual ~PathDiagnosticClient() {} + + virtual void SetPreprocessor(Preprocessor *PP) {} + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + + virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0; + + enum PathGenerationScheme { Minimal, Extensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + virtual bool supportsLogicalOpControlFlow() const { return false; } + virtual bool supportsAllBlockEdges() const { return false; } + virtual bool useVerboseDescription() const { return true; } +}; + +//===----------------------------------------------------------------------===// +// Path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticRange : public SourceRange { +public: + const bool isPoint; + + PathDiagnosticRange(const SourceRange &R, bool isP = false) + : SourceRange(R), isPoint(isP) {} +}; + +class PathDiagnosticLocation { +private: + enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; + SourceRange R; + const Stmt *S; + const Decl *D; + const SourceManager *SM; +public: + PathDiagnosticLocation() + : K(SingleLocK), S(0), D(0), SM(0) {} + + PathDiagnosticLocation(FullSourceLoc L) + : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} + + PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) + : K(StmtK), S(s), D(0), SM(&sm) {} + + PathDiagnosticLocation(SourceRange r, const SourceManager &sm) + : K(RangeK), R(r), S(0), D(0), SM(&sm) {} + + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) + : K(DeclK), S(0), D(d), SM(&sm) {} + + bool operator==(const PathDiagnosticLocation &X) const { + return K == X.K && R == X.R && S == X.S && D == X.D; + } + + bool operator!=(const PathDiagnosticLocation &X) const { + return K != X.K || R != X.R || S != X.S || D != X.D;; + } + + PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { + K = X.K; + R = X.R; + S = X.S; + D = X.D; + SM = X.SM; + return *this; + } + + bool isValid() const { + return SM != 0; + } + + const SourceManager& getSourceManager() const { assert(isValid());return *SM;} + + FullSourceLoc asLocation() const; + PathDiagnosticRange asRange() const; + const Stmt *asStmt() const { assert(isValid()); return S; } + const Decl *asDecl() const { assert(isValid()); return D; } + + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } + + void invalidate() { + *this = PathDiagnosticLocation(); + } + + void flatten(); + + const SourceManager& getManager() const { assert(isValid()); return *SM; } +}; + +class PathDiagnosticLocationPair { +private: + PathDiagnosticLocation Start, End; +public: + PathDiagnosticLocationPair(const PathDiagnosticLocation &start, + const PathDiagnosticLocation &end) + : Start(start), End(end) {} + + const PathDiagnosticLocation &getStart() const { return Start; } + const PathDiagnosticLocation &getEnd() const { return End; } + + void flatten() { + Start.flatten(); + End.flatten(); + } +}; + +//===----------------------------------------------------------------------===// +// Path "pieces" for path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticPiece { +public: + enum Kind { ControlFlow, Event, Macro }; + enum DisplayHint { Above, Below }; + +private: + const std::string str; + std::vector<CodeModificationHint> CodeModificationHints; + const Kind kind; + const DisplayHint Hint; + std::vector<SourceRange> ranges; + + // Do not implement: + PathDiagnosticPiece(); + PathDiagnosticPiece(const PathDiagnosticPiece &P); + PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); + +protected: + PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(Kind k, DisplayHint hint = Below); + +public: + virtual ~PathDiagnosticPiece(); + + const std::string& getString() const { return str; } + + /// getDisplayHint - Return a hint indicating where the diagnostic should + /// be displayed by the PathDiagnosticClient. + DisplayHint getDisplayHint() const { return Hint; } + + virtual PathDiagnosticLocation getLocation() const = 0; + virtual void flattenLocations() = 0; + + Kind getKind() const { return kind; } + + void addRange(SourceRange R) { ranges.push_back(R); } + + void addRange(SourceLocation B, SourceLocation E) { + ranges.push_back(SourceRange(B,E)); + } + + void addCodeModificationHint(const CodeModificationHint& Hint) { + CodeModificationHints.push_back(Hint); + } + + typedef const SourceRange* range_iterator; + + range_iterator ranges_begin() const { + return ranges.empty() ? NULL : &ranges[0]; + } + + range_iterator ranges_end() const { + return ranges_begin() + ranges.size(); + } + + typedef const CodeModificationHint *code_modifications_iterator; + + code_modifications_iterator code_modifications_begin() const { + return CodeModificationHints.empty()? 0 : &CodeModificationHints[0]; + } + + code_modifications_iterator code_modifications_end() const { + return CodeModificationHints.empty()? 0 + : &CodeModificationHints[0] + CodeModificationHints.size(); + } + + static inline bool classof(const PathDiagnosticPiece* P) { + return true; + } +}; + +class PathDiagnosticSpotPiece : public PathDiagnosticPiece { +private: + PathDiagnosticLocation Pos; +public: + PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, + const std::string& s, + PathDiagnosticPiece::Kind k, + bool addPosRange = true) + : PathDiagnosticPiece(s, k), Pos(pos) { + assert(Pos.asLocation().isValid() && + "PathDiagnosticSpotPiece's must have a valid location."); + if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); + } + + PathDiagnosticLocation getLocation() const { return Pos; } + virtual void flattenLocations() { Pos.flatten(); } +}; + +class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { + +public: + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, + const std::string& s, bool addPosRange = true) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s, + bool addPosRange = true) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + + ~PathDiagnosticEventPiece(); + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Event; + } +}; + +class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { + std::vector<PathDiagnosticLocationPair> LPairs; +public: + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + const std::string& s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + const char* s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos) + : PathDiagnosticPiece(ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + ~PathDiagnosticControlFlowPiece(); + + PathDiagnosticLocation getStartLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getStart(); + } + + PathDiagnosticLocation getEndLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getEnd(); + } + + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } + + virtual PathDiagnosticLocation getLocation() const { + return getStartLocation(); + } + + typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; + iterator begin() { return LPairs.begin(); } + iterator end() { return LPairs.end(); } + + virtual void flattenLocations() { + for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); + } + + typedef std::vector<PathDiagnosticLocationPair>::const_iterator + const_iterator; + const_iterator begin() const { return LPairs.begin(); } + const_iterator end() const { return LPairs.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == ControlFlow; + } +}; + +class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { + std::vector<PathDiagnosticPiece*> SubPieces; +public: + PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) + : PathDiagnosticSpotPiece(pos, "", Macro) {} + + ~PathDiagnosticMacroPiece(); + + bool containsEvent() const; + + void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } + + typedef std::vector<PathDiagnosticPiece*>::iterator iterator; + iterator begin() { return SubPieces.begin(); } + iterator end() { return SubPieces.end(); } + + virtual void flattenLocations() { + PathDiagnosticSpotPiece::flattenLocations(); + for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); + } + + typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator; + const_iterator begin() const { return SubPieces.begin(); } + const_iterator end() const { return SubPieces.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Macro; + } +}; + +/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive +/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, +/// each which represent the pieces of the path. +class PathDiagnostic { + std::deque<PathDiagnosticPiece*> path; + unsigned Size; + std::string BugType; + std::string Desc; + std::string Category; + std::deque<std::string> OtherDesc; + +public: + PathDiagnostic(); + + PathDiagnostic(const char* bugtype, const char* desc, const char* category); + + PathDiagnostic(const std::string& bugtype, const std::string& desc, + const std::string& category); + + ~PathDiagnostic(); + + const std::string& getDescription() const { return Desc; } + const std::string& getBugType() const { return BugType; } + const std::string& getCategory() const { return Category; } + + typedef std::deque<std::string>::const_iterator meta_iterator; + meta_iterator meta_begin() const { return OtherDesc.begin(); } + meta_iterator meta_end() const { return OtherDesc.end(); } + void addMeta(const std::string& s) { OtherDesc.push_back(s); } + void addMeta(const char* s) { OtherDesc.push_back(s); } + + PathDiagnosticLocation getLocation() const { + assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); + return rbegin()->getLocation(); + } + + void push_front(PathDiagnosticPiece* piece) { + path.push_front(piece); + ++Size; + } + + void push_back(PathDiagnosticPiece* piece) { + path.push_back(piece); + ++Size; + } + + PathDiagnosticPiece* back() { + return path.back(); + } + + const PathDiagnosticPiece* back() const { + return path.back(); + } + + unsigned size() const { return Size; } + bool empty() const { return Size == 0; } + + void resetPath(bool deletePieces = true); + + class iterator { + public: + typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy; + + typedef PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + iterator(const ImplTy& i) : I(i) {} + + bool operator==(const iterator& X) const { return I == X.I; } + bool operator!=(const iterator& X) const { return I != X.I; } + + PathDiagnosticPiece& operator*() const { return **I; } + PathDiagnosticPiece* operator->() const { return *I; } + + iterator& operator++() { ++I; return *this; } + iterator& operator--() { --I; return *this; } + }; + + class const_iterator { + public: + typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy; + + typedef const PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + const_iterator(const ImplTy& i) : I(i) {} + + bool operator==(const const_iterator& X) const { return I == X.I; } + bool operator!=(const const_iterator& X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + + const_iterator& operator++() { ++I; return *this; } + const_iterator& operator--() { --I; return *this; } + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + // forward iterator creation methods. + + iterator begin() { return path.begin(); } + iterator end() { return path.end(); } + + const_iterator begin() const { return path.begin(); } + const_iterator end() const { return path.end(); } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + void flattenLocations() { + for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); + } +}; + + +} //end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h new file mode 100644 index 000000000000..b694e9b29940 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -0,0 +1,163 @@ +//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by GRExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H +#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H + +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ImmutableList.h" + +namespace clang { + +class CompoundValData : public llvm::FoldingSetNode { + QualType T; + llvm::ImmutableList<SVal> L; + +public: + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + : T(t), L(l) {} + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const { return L.begin(); } + iterator end() const { return L.end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, + llvm::ImmutableList<SVal> L); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } +}; + +class BasicValueFactory { + typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > + APSIntSetTy; + + ASTContext& Ctx; + llvm::BumpPtrAllocator& BPAlloc; + + APSIntSetTy APSIntSet; + void* PersistentSVals; + void* PersistentSValPairs; + + llvm::ImmutableList<SVal>::Factory SValListFactory; + llvm::FoldingSet<CompoundValData> CompoundValDataSet; + +public: + BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) + : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), + SValListFactory(Alloc) {} + + ~BasicValueFactory(); + + ASTContext& getContext() const { return Ctx; } + + const llvm::APSInt& getValue(const llvm::APSInt& X); + const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, QualType T); + + /// Convert - Create a new persistent APSInt with the same value as 'From' + /// but with the bitwidth and signedness of 'To'. + const llvm::APSInt& Convert(const llvm::APSInt& To, + const llvm::APSInt& From) { + + if (To.isUnsigned() == From.isUnsigned() && + To.getBitWidth() == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), + To.getBitWidth(), + To.isUnsigned()); + } + + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMaxValue(QualType 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); + return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + llvm::APSInt X = V; + ++X; + return getValue(X); + } + + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + llvm::APSInt X = V; + --X; + return getValue(X); + } + + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); + } + + inline const llvm::APSInt& getTruthValue(bool b) { + return getTruthValue(b, Ctx.IntTy); + } + + const CompoundValData* getCompoundValData(QualType T, + llvm::ImmutableList<SVal> Vals); + + llvm::ImmutableList<SVal> getEmptySValList() { + return SValListFactory.GetEmptyList(); + } + + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { + return SValListFactory.Add(X, L); + } + + const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, + const llvm::APSInt& V2); + + const std::pair<SVal, uintptr_t>& + getPersistentSValWithData(const SVal& V, uintptr_t Data); + + const std::pair<SVal, SVal>& + getPersistentSValPair(const SVal& V1, const SVal& V2); + + const SVal* getPersistentSVal(SVal X); +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h new file mode 100644 index 000000000000..90fd9d8ebf45 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -0,0 +1,466 @@ +//===--- BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating +// PathDiagnostics for analyses based on GRState. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER +#define LLVM_CLANG_ANALYSIS_BUGREPORTER + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/ImmutableSet.h" +#include <list> + +namespace clang { + +class PathDiagnostic; +class PathDiagnosticPiece; +class PathDiagnosticClient; +class ASTContext; +class Diagnostic; +class BugReporter; +class BugReporterContext; +class GRExprEngine; +class GRState; +class Stmt; +class BugType; +class ParentMap; + +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// + +class BugReporterVisitor { +public: + virtual ~BugReporterVisitor(); + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, + const ExplodedNode<GRState>* PrevN, + BugReporterContext& BRC) = 0; + + virtual bool isOwnedByReporterContext() { return true; } +}; + +// FIXME: Combine this with RangedBugReport and remove RangedBugReport. +class BugReport : public BugReporterVisitor { +protected: + BugType& BT; + std::string ShortDescription; + std::string Description; + const ExplodedNode<GRState> *EndNode; + SourceRange R; + +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + virtual void Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddInteger(getLocation().getRawEncoding()); + } + +public: + class NodeResolver { + public: + virtual ~NodeResolver() {} + virtual const ExplodedNode<GRState>* + getOriginalNode(const ExplodedNode<GRState>* N) = 0; + }; + + BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n) + : BT(bt), Description(desc), EndNode(n) {} + + BugReport(BugType& bt, const char* shortDesc, const char* desc, + const ExplodedNode<GRState> *n) + : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} + + virtual ~BugReport(); + + virtual bool isOwnedByReporterContext() { return false; } + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } + + // FIXME: Perhaps this should be moved into a subclass? + const ExplodedNode<GRState>* getEndNode() const { return EndNode; } + + // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint + // object. + // FIXME: If we do need it, we can probably just make it private to + // BugReporter. + Stmt* getStmt(BugReporter& BR) const; + + const std::string& getDescription() const { return Description; } + + const std::string& getShortDescription() const { + return ShortDescription.empty() ? Description : ShortDescription; + } + + // FIXME: Is this needed? + virtual std::pair<const char**,const char**> getExtraDescriptiveText() { + return std::make_pair((const char**)0,(const char**)0); + } + + // FIXME: Perhaps move this into a subclass. + virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, + const ExplodedNode<GRState>* N); + + /// getLocation - Return the "definitive" location of the reported bug. + /// While a bug can span an entire path, usually there is a specific + /// location that can be used to identify where the key issue occured. + /// This location is used by clients rendering diagnostics. + virtual SourceLocation getLocation() const; + + /// getRanges - Returns the source ranges associated with this bug. + virtual void getRanges(BugReporter& BR,const SourceRange*& beg, + const SourceRange*& end); + + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, + const ExplodedNode<GRState>* PrevN, + BugReporterContext& BR); + + virtual void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N) {} +}; + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + // List of *owned* BugReport objects. + std::list<BugReport*> Reports; + + friend class BugReporter; + void AddReport(BugReport* R) { Reports.push_back(R); } +public: + BugReportEquivClass(BugReport* R) { Reports.push_back(R); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + (*Reports.begin())->Profile(ID); + } + + class iterator { + std::list<BugReport*>::iterator impl; + public: + iterator(std::list<BugReport*>::iterator i) : impl(i) {} + iterator& operator++() { ++impl; return *this; } + bool operator==(const iterator& I) const { return I.impl == impl; } + bool operator!=(const iterator& I) const { return I.impl != impl; } + BugReport* operator*() const { return *impl; } + BugReport* operator->() const { return *impl; } + }; + + class const_iterator { + std::list<BugReport*>::const_iterator impl; + public: + const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {} + const_iterator& operator++() { ++impl; return *this; } + bool operator==(const const_iterator& I) const { return I.impl == impl; } + bool operator!=(const const_iterator& I) const { return I.impl != impl; } + const BugReport* operator*() const { return *impl; } + const BugReport* operator->() const { return *impl; } + }; + + iterator begin() { return iterator(Reports.begin()); } + iterator end() { return iterator(Reports.end()); } + + const_iterator begin() const { return const_iterator(Reports.begin()); } + const_iterator end() const { return const_iterator(Reports.end()); } +}; + +class BugType { +private: + const std::string Name; + const std::string Category; + llvm::FoldingSet<BugReportEquivClass> EQClasses; + friend class BugReporter; +public: + BugType(const char *name, const char* cat) : Name(name), Category(cat) {} + virtual ~BugType(); + + // FIXME: Should these be made strings as well? + const std::string& getName() const { return Name; } + const std::string& getCategory() const { return Category; } + + virtual void FlushReports(BugReporter& BR); + void AddReport(BugReport* BR); + + typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator; + iterator begin() { return EQClasses.begin(); } + iterator end() { return EQClasses.end(); } + + typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator; + const_iterator begin() const { return EQClasses.begin(); } + const_iterator end() const { return EQClasses.end(); } +}; + +//===----------------------------------------------------------------------===// +// Specialized subclasses of BugReport. +//===----------------------------------------------------------------------===// + +// FIXME: Collapse this with the default BugReport class. +class RangedBugReport : public BugReport { + std::vector<SourceRange> Ranges; +public: + RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n) + : BugReport(D, description, n) {} + + RangedBugReport(BugType& D, const char *shortDescription, + const char *description, ExplodedNode<GRState> *n) + : BugReport(D, shortDescription, description, n) {} + + ~RangedBugReport(); + + // FIXME: Move this out of line. + void addRange(SourceRange R) { Ranges.push_back(R); } + + // FIXME: Move this out of line. + void getRanges(BugReporter& BR,const SourceRange*& beg, + const SourceRange*& end) { + + if (Ranges.empty()) { + beg = NULL; + end = NULL; + } + else { + beg = &Ranges[0]; + end = beg + Ranges.size(); + } + } +}; + +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + +class BugReporterData { +public: + virtual ~BugReporterData(); + virtual Diagnostic& getDiagnostic() = 0; + virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; + virtual ASTContext& getContext() = 0; + virtual SourceManager& getSourceManager() = 0; + virtual CFG* getCFG() = 0; + virtual ParentMap& getParentMap() = 0; + virtual LiveVariables* getLiveVariables() = 0; +}; + +class BugReporter { +public: + enum Kind { BaseBRKind, GRBugReporterKind }; + +private: + typedef llvm::ImmutableSet<BugType*> BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; + BugReporterData& D; + + void FlushReport(BugReportEquivClass& EQ); + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} + +public: + BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} + virtual ~BugReporter(); + + void FlushReports(); + + Kind getKind() const { return kind; } + + Diagnostic& getDiagnostic() { + return D.getDiagnostic(); + } + + PathDiagnosticClient* getPathDiagnosticClient() { + return D.getPathDiagnosticClient(); + } + + typedef BugTypesTy::iterator iterator; + iterator begin() { return BugTypes.begin(); } + iterator end() { return BugTypes.end(); } + + ASTContext& getContext() { return D.getContext(); } + + SourceManager& getSourceManager() { return D.getSourceManager(); } + + CFG* getCFG() { return D.getCFG(); } + + ParentMap& getParentMap() { return D.getParentMap(); } + + LiveVariables* getLiveVariables() { return D.getLiveVariables(); } + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& EQ) {} + + void Register(BugType *BT); + + void EmitReport(BugReport *R); + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + void EmitBasicReport(const char* BugName, const char* BugCategory, + const char* BugStr, SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc) { + EmitBasicReport(BugName, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(const char* BugName, const char* BugCategory, + const char* BugStr, SourceLocation Loc) { + EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(const char* BugName, const char* BugStr, + SourceLocation Loc, SourceRange R) { + EmitBasicReport(BugName, BugStr, Loc, &R, 1); + } + + void EmitBasicReport(const char* BugName, const char* Category, + const char* BugStr, SourceLocation Loc, SourceRange R) { + EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); + } + + static bool classof(const BugReporter* R) { return true; } +}; + +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. +class GRBugReporter : public BugReporter { + GRExprEngine& Eng; + llvm::SmallSet<SymbolRef, 10> NotableSymbols; +public: + GRBugReporter(BugReporterData& d, GRExprEngine& eng) + : BugReporter(d, GRBugReporterKind), Eng(eng) {} + + virtual ~GRBugReporter(); + + /// getEngine - Return the analysis engine used to analyze a given + /// function or method. + GRExprEngine& getEngine() { return Eng; } + + /// getGraph - Get the exploded graph created by the analysis engine + /// for the analyzed method or function. + ExplodedGraph<GRState>& getGraph(); + + /// getStateManager - Return the state manager used by the analysis + /// engine. + GRStateManager& getStateManager(); + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& R); + + void addNotableSymbol(SymbolRef Sym) { + NotableSymbols.insert(Sym); + } + + bool isNotable(SymbolRef Sym) const { + return (bool) NotableSymbols.count(Sym); + } + + /// classof - Used by isa<>, cast<>, and dyn_cast<>. + static bool classof(const BugReporter* R) { + return R->getKind() == GRBugReporterKind; + } +}; + +class BugReporterContext { + GRBugReporter &BR; + std::vector<BugReporterVisitor*> Callbacks; +public: + BugReporterContext(GRBugReporter& br) : BR(br) {} + virtual ~BugReporterContext(); + + void addVisitor(BugReporterVisitor* visitor) { + if (visitor) Callbacks.push_back(visitor); + } + + typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator; + visitor_iterator visitor_begin() { return Callbacks.begin(); } + visitor_iterator visitor_end() { return Callbacks.end(); } + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); } + + void addNotableSymbol(SymbolRef Sym) { + // FIXME: For now forward to GRBugReporter. + BR.addNotableSymbol(Sym); + } + + bool isNotable(SymbolRef Sym) const { + // FIXME: For now forward to GRBugReporter. + return BR.isNotable(Sym); + } + + GRStateManager& getStateManager() { + return BR.getStateManager(); + } + + ValueManager& getValueManager() { + return getStateManager().getValueManager(); + } + + ASTContext& getASTContext() { + return BR.getContext(); + } + + SourceManager& getSourceManager() { + return BR.getSourceManager(); + } + + const Decl& getCodeDecl() { + return getStateManager().getCodeDecl(); + } + + const CFG& getCFG() { + return *BR.getCFG(); + } + + virtual BugReport::NodeResolver& getNodeResolver() = 0; +}; + +class DiagBugReport : public RangedBugReport { + std::list<std::string> Strs; + FullSourceLoc L; +public: + DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + RangedBugReport(D, desc, 0), L(l) {} + + virtual ~DiagBugReport() {} + + // FIXME: Move out-of-line (virtual function). + SourceLocation getLocation() const { return L; } + + void addString(const std::string& s) { Strs.push_back(s); } + + typedef std::list<std::string>::const_iterator str_iterator; + str_iterator str_begin() const { return Strs.begin(); } + str_iterator str_end() const { return Strs.end(); } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h new file mode 100644 index 000000000000..c8e5e85c8a1a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h @@ -0,0 +1,67 @@ +//== ConstraintManager.h - Constraints on symbolic 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 defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H +#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H + +// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place. +#include "clang/Analysis/PathSensitive/Store.h" + +namespace llvm { +class APSInt; +} + +namespace clang { + +class GRState; +class GRStateManager; +class SVal; + +class ConstraintManager { +public: + virtual ~ConstraintManager(); + virtual const GRState* Assume(const GRState* St, SVal Cond, + bool Assumption, bool& isFeasible) = 0; + + virtual const GRState* AssumeInBound(const GRState* St, SVal Idx, + SVal UpperBound, bool Assumption, + bool& isFeasible) = 0; + + virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) + const = 0; + + virtual bool isEqual(const GRState* St, SymbolRef sym, + const llvm::APSInt& V) const = 0; + + virtual const GRState* RemoveDeadBindings(const GRState* St, + SymbolReaper& SymReaper) = 0; + + virtual void print(const GRState* St, std::ostream& Out, + const char* nl, const char *sep) = 0; + + virtual void EndPath(const GRState* St) {} + + /// 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 + /// conjured symbolic value in order to recover some precision. + virtual bool canReasonAbout(SVal X) const = 0; +}; + +ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr); +ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr); + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h new file mode 100644 index 000000000000..fde8b167f3c7 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Environment.h @@ -0,0 +1,151 @@ +//== Environment.h - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H + +// For using typedefs in StoreManager. Should find a better place for these +// typedefs. +#include "clang/Analysis/PathSensitive/Store.h" + +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +class EnvironmentManager; +class BasicValueFactory; +class LiveVariables; + +class Environment : public llvm::FoldingSetNode { +private: + + friend class EnvironmentManager; + + // Type definitions. + typedef llvm::ImmutableMap<Stmt*,SVal> BindingsTy; + + // Data. + BindingsTy SubExprBindings; + BindingsTy BlkExprBindings; + + Environment(BindingsTy seb, BindingsTy beb) + : SubExprBindings(seb), BlkExprBindings(beb) {} + +public: + + typedef BindingsTy::iterator seb_iterator; + seb_iterator seb_begin() const { return SubExprBindings.begin(); } + seb_iterator seb_end() const { return SubExprBindings.end(); } + + typedef BindingsTy::iterator beb_iterator; + beb_iterator beb_begin() const { return BlkExprBindings.begin(); } + beb_iterator beb_end() const { return BlkExprBindings.end(); } + + SVal LookupSubExpr(Stmt* E) const { + const SVal* X = SubExprBindings.lookup(cast<Expr>(E)); + return X ? *X : UnknownVal(); + } + + SVal LookupBlkExpr(Stmt* E) const { + const SVal* X = BlkExprBindings.lookup(E); + return X ? *X : UnknownVal(); + } + + SVal LookupExpr(Stmt* E) const { + const SVal* X = SubExprBindings.lookup(E); + if (X) return *X; + X = BlkExprBindings.lookup(E); + return X ? *X : UnknownVal(); + } + + SVal GetSVal(Stmt* Ex, BasicValueFactory& BasicVals) const; + SVal GetBlkExprSVal(Stmt* Ex, BasicValueFactory& BasicVals) const; + + /// Profile - Profile the contents of an Environment object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { + E->SubExprBindings.Profile(ID); + E->BlkExprBindings.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + bool operator==(const Environment& RHS) const { + return SubExprBindings == RHS.SubExprBindings && + BlkExprBindings == RHS.BlkExprBindings; + } +}; + +class EnvironmentManager { +private: + typedef Environment::BindingsTy::Factory FactoryTy; + FactoryTy F; + +public: + + EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} + ~EnvironmentManager() {} + + /// RemoveBlkExpr - Return a new environment object with the same bindings as + /// the provided environment except with any bindings for the provided Stmt* + /// removed. This method only removes bindings for block-level expressions. + /// Using this method on a non-block level expression will return the + /// same environment object. + Environment RemoveBlkExpr(const Environment& Env, Stmt* E) { + return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E)); + } + + Environment RemoveSubExpr(const Environment& Env, Stmt* E) { + return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings); + } + + Environment AddBlkExpr(const Environment& Env, Stmt* E, SVal V) { + return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V)); + } + + Environment AddSubExpr(const Environment& Env, Stmt* E, SVal V) { + return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings); + } + + /// RemoveSubExprBindings - Return a new environment object with + /// the same bindings as the provided environment except with all the + /// subexpression bindings removed. + Environment RemoveSubExprBindings(const Environment& Env) { + return Environment(F.GetEmptyMap(), Env.BlkExprBindings); + } + + Environment getInitialEnvironment() { + return Environment(F.GetEmptyMap(), F.GetEmptyMap()); + } + + Environment BindExpr(const Environment& Env, Stmt* E, SVal V, + bool isBlkExpr, bool Invalidate); + + Environment + RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper, + GRStateManager& StateMgr, const GRState *state, + llvm::SmallVectorImpl<const MemRegion*>& DRoots); + +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h new file mode 100644 index 000000000000..8494d935650d --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -0,0 +1,582 @@ +//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH +#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Casting.h" + +namespace clang { + +class GRCoreEngineImpl; +class ExplodedNodeImpl; +class CFG; +class ASTContext; + +class GRStmtNodeBuilderImpl; +class GRBranchNodeBuilderImpl; +class GRIndirectGotoNodeBuilderImpl; +class GRSwitchNodeBuilderImpl; +class GREndPathNodebuilderImpl; + +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + +class ExplodedNodeImpl : public llvm::FoldingSetNode { +protected: + friend class ExplodedGraphImpl; + friend class GRCoreEngineImpl; + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + class NodeGroup { + enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; + uintptr_t P; + + unsigned getKind() const { + return P & 0x1; + } + + void* getPtr() const { + assert (!getFlag()); + return reinterpret_cast<void*>(P & ~Mask); + } + + ExplodedNodeImpl* getNode() const { + return reinterpret_cast<ExplodedNodeImpl*>(getPtr()); + } + + public: + NodeGroup() : P(0) {} + + ~NodeGroup(); + + ExplodedNodeImpl** begin() const; + + ExplodedNodeImpl** end() const; + + unsigned size() const; + + bool empty() const { return size() == 0; } + + void addNode(ExplodedNodeImpl* N); + + void setFlag() { + assert (P == 0); + P = AuxFlag; + } + + bool getFlag() const { + return P & AuxFlag ? true : false; + } + }; + + /// Location - The program location (within a function body) associated + /// with this node. + const ProgramPoint Location; + + /// State - The state associated with this node. + const void* State; + + /// Preds - The predecessors of this node. + NodeGroup Preds; + + /// Succs - The successors of this node. + NodeGroup Succs; + + /// Construct a ExplodedNodeImpl with the provided location and state. + explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state) + : Location(loc), State(state) {} + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNodeImpl* V); + +public: + + /// getLocation - Returns the edge associated with the given node. + ProgramPoint getLocation() const { return Location; } + + template <typename T> + const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + void markAsSink() { Succs.setFlag(); } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0; + }; + + static void SetAuditor(Auditor* A); +}; + + +template <typename StateTy> +struct GRTrait { + static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) { + St->Profile(ID); + } +}; + + +template <typename StateTy> +class ExplodedNode : public ExplodedNodeImpl { +public: + /// Construct a ExplodedNodeImpl with the given node ID, program edge, + /// and state. + explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St) + : ExplodedNodeImpl(loc, St) {} + + /// getState - Returns the state associated with the node. + inline const StateTy* getState() const { + return static_cast<const StateTy*>(State); + } + + // Profiling (for FoldingSet). + + static inline void Profile(llvm::FoldingSetNodeID& ID, + const ProgramPoint& Loc, + const StateTy* state) { + ID.Add(Loc); + GRTrait<StateTy>::Profile(ID, state); + } + + inline void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, getLocation(), getState()); + } + + void addPredecessor(ExplodedNode* V) { + ExplodedNodeImpl::addPredecessor(V); + } + + ExplodedNode* getFirstPred() { + return pred_empty() ? NULL : *(pred_begin()); + } + + const ExplodedNode* getFirstPred() const { + return const_cast<ExplodedNode*>(this)->getFirstPred(); + } + + // Iterators over successor and predecessor vertices. + typedef ExplodedNode** succ_iterator; + typedef const ExplodedNode* const * const_succ_iterator; + typedef ExplodedNode** pred_iterator; + typedef const ExplodedNode* const * const_pred_iterator; + + pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); } + pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); } + + const_pred_iterator pred_begin() const { + return const_cast<ExplodedNode*>(this)->pred_begin(); + } + const_pred_iterator pred_end() const { + return const_cast<ExplodedNode*>(this)->pred_end(); + } + + succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); } + succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); } + + const_succ_iterator succ_begin() const { + return const_cast<ExplodedNode*>(this)->succ_begin(); + } + const_succ_iterator succ_end() const { + return const_cast<ExplodedNode*>(this)->succ_end(); + } +}; + +class InterExplodedGraphMapImpl; + +class ExplodedGraphImpl { +protected: + friend class GRCoreEngineImpl; + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + // Type definitions. + typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy; + typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy; + + /// Roots - The roots of the simulation graph. Usually there will be only + /// one, but clients are free to establish multiple subgraphs within a single + /// SimulGraph. Moreover, these subgraphs can often merge when paths from + /// different roots reach the same state at the same program location. + RootsTy Roots; + + /// EndNodes - The nodes in the simulation graph which have been + /// specially marked as the endpoint of an abstract simulation path. + EndNodesTy EndNodes; + + /// Allocator - BumpPtrAllocator to create nodes. + llvm::BumpPtrAllocator Allocator; + + /// cfg - The CFG associated with this analysis graph. + CFG& cfg; + + /// CodeDecl - The declaration containing the code being analyzed. This + /// can be a FunctionDecl or and ObjCMethodDecl. + Decl& CodeDecl; + + /// Ctx - The ASTContext used to "interpret" CodeDecl. + ASTContext& Ctx; + + /// NumNodes - The number of nodes in the graph. + unsigned NumNodes; + + /// getNodeImpl - Retrieve the node associated with a (Location,State) + /// pair, where 'State' is represented as an opaque void*. This method + /// is intended to be used only by GRCoreEngineImpl. + virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, + const void* State, + bool* IsNew) = 0; + + virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0; + + /// addRoot - Add an untyped node to the set of roots. + ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) { + Roots.push_back(V); + return V; + } + + /// addEndOfPath - Add an untyped node to the set of EOP nodes. + ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) { + EndNodes.push_back(V); + return V; + } + + // ctor. + ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx) + : cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {} + +public: + virtual ~ExplodedGraphImpl() {} + + unsigned num_roots() const { return Roots.size(); } + unsigned num_eops() const { return EndNodes.size(); } + + bool empty() const { return NumNodes == 0; } + unsigned size() const { return NumNodes; } + + llvm::BumpPtrAllocator& getAllocator() { return Allocator; } + CFG& getCFG() { return cfg; } + ASTContext& getContext() { return Ctx; } + + Decl& getCodeDecl() { return CodeDecl; } + const Decl& getCodeDecl() const { return CodeDecl; } + + const FunctionDecl* getFunctionDecl() const { + return llvm::dyn_cast<FunctionDecl>(&CodeDecl); + } + + typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap; + + ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg, + const ExplodedNodeImpl* const * NEnd, + InterExplodedGraphMapImpl *M, + llvm::DenseMap<const void*, const void*> *InverseMap) + const; +}; + +class InterExplodedGraphMapImpl { + llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M; + friend class ExplodedGraphImpl; + void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To); + +protected: + ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const; + + InterExplodedGraphMapImpl(); +public: + virtual ~InterExplodedGraphMapImpl() {} +}; + +//===----------------------------------------------------------------------===// +// Type-specialized ExplodedGraph classes. +//===----------------------------------------------------------------------===// + +template <typename STATE> +class InterExplodedGraphMap : public InterExplodedGraphMapImpl { +public: + InterExplodedGraphMap() {}; + ~InterExplodedGraphMap() {}; + + ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const { + return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N)); + } +}; + +template <typename STATE> +class ExplodedGraph : public ExplodedGraphImpl { +public: + typedef STATE StateTy; + typedef ExplodedNode<StateTy> NodeTy; + typedef llvm::FoldingSet<NodeTy> AllNodesTy; + +protected: + /// Nodes - The nodes in the graph. + AllNodesTy Nodes; + +protected: + virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L, + const void* State, + bool* IsNew) { + + return getNode(L, static_cast<const StateTy*>(State), IsNew); + } + + virtual ExplodedGraphImpl* MakeEmptyGraph() const { + return new ExplodedGraph(cfg, CodeDecl, Ctx); + } + +public: + ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx) + : ExplodedGraphImpl(c, cd, ctx) {} + + /// getNode - Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + NodeTy* getNode(const ProgramPoint& L, const StateTy* State, + bool* IsNew = NULL) { + + // Profile 'State' to determine if we already have an existing node. + llvm::FoldingSetNodeID profile; + void* InsertPos = 0; + + NodeTy::Profile(profile, L, State); + NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); + + if (!V) { + // Allocate a new node. + V = (NodeTy*) Allocator.Allocate<NodeTy>(); + new (V) NodeTy(L, State); + + // Insert the node into the node set and return it. + Nodes.InsertNode(V, InsertPos); + + ++NumNodes; + + if (IsNew) *IsNew = true; + } + else + if (IsNew) *IsNew = false; + + return V; + } + + // Iterators. + typedef NodeTy** roots_iterator; + typedef const NodeTy** const_roots_iterator; + typedef NodeTy** eop_iterator; + typedef const NodeTy** const_eop_iterator; + typedef typename AllNodesTy::iterator node_iterator; + typedef typename AllNodesTy::const_iterator const_node_iterator; + + node_iterator nodes_begin() { + return Nodes.begin(); + } + + node_iterator nodes_end() { + return Nodes.end(); + } + + const_node_iterator nodes_begin() const { + return Nodes.begin(); + } + + const_node_iterator nodes_end() const { + return Nodes.end(); + } + + roots_iterator roots_begin() { + return reinterpret_cast<roots_iterator>(Roots.begin()); + } + + roots_iterator roots_end() { + return reinterpret_cast<roots_iterator>(Roots.end()); + } + + const_roots_iterator roots_begin() const { + return const_cast<ExplodedGraph>(this)->roots_begin(); + } + + const_roots_iterator roots_end() const { + return const_cast<ExplodedGraph>(this)->roots_end(); + } + + eop_iterator eop_begin() { + return reinterpret_cast<eop_iterator>(EndNodes.begin()); + } + + eop_iterator eop_end() { + return reinterpret_cast<eop_iterator>(EndNodes.end()); + } + + const_eop_iterator eop_begin() const { + return const_cast<ExplodedGraph>(this)->eop_begin(); + } + + const_eop_iterator eop_end() const { + return const_cast<ExplodedGraph>(this)->eop_end(); + } + + std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*> + Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap<const void*, const void*> *InverseMap = 0) const { + + if (NBeg == NEnd) + return std::make_pair((ExplodedGraph*) 0, + (InterExplodedGraphMap<STATE>*) 0); + + assert (NBeg < NEnd); + + const ExplodedNodeImpl* const* NBegImpl = + (const ExplodedNodeImpl* const*) NBeg; + const ExplodedNodeImpl* const* NEndImpl = + (const ExplodedNodeImpl* const*) NEnd; + + llvm::OwningPtr<InterExplodedGraphMap<STATE> > + M(new InterExplodedGraphMap<STATE>()); + + ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(), + InverseMap); + + return std::make_pair(static_cast<ExplodedGraph*>(G), M.take()); + } +}; + +template <typename StateTy> +class ExplodedNodeSet { + + typedef ExplodedNode<StateTy> NodeTy; + typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy; + ImplTy Impl; + +public: + ExplodedNodeSet(NodeTy* N) { + assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()); + Impl.insert(N); + } + + ExplodedNodeSet() {} + + inline void Add(NodeTy* N) { + if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N); + } + + typedef typename ImplTy::iterator iterator; + typedef typename ImplTy::const_iterator const_iterator; + + inline unsigned size() const { return Impl.size(); } + inline bool empty() const { return Impl.empty(); } + + inline void clear() { Impl.clear(); } + + inline iterator begin() { return Impl.begin(); } + inline iterator end() { return Impl.end(); } + + inline const_iterator begin() const { return Impl.begin(); } + inline const_iterator end() const { return Impl.end(); } +}; + +} // end clang namespace + +// GraphTraits + +namespace llvm { + template<typename StateTy> + struct GraphTraits<clang::ExplodedNode<StateTy>*> { + typedef clang::ExplodedNode<StateTy> NodeType; + typedef typename NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + + template<typename StateTy> + struct GraphTraits<const clang::ExplodedNode<StateTy>*> { + typedef const clang::ExplodedNode<StateTy> NodeType; + typedef typename NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Analysis/PathSensitive/GRAuditor.h new file mode 100644 index 000000000000..eca591d4af0e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRAuditor.h @@ -0,0 +1,39 @@ +//==- 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 + +#include "clang/AST/Expr.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" + +namespace clang { + +template <typename STATE> +class GRAuditor { +public: + typedef ExplodedNode<STATE> NodeTy; + typedef typename STATE::ManagerTy ManagerTy; + + virtual ~GRAuditor() {} + virtual bool Audit(NodeTy* N, ManagerTy& M) = 0; +}; + + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h new file mode 100644 index 000000000000..b4fd2704b81a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h @@ -0,0 +1,50 @@ +//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by GRCoreEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER +#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER + +namespace llvm { + class BumpPtrAllocator; +} + +namespace clang { + +class GRBlockCounter { + void* Data; + + GRBlockCounter(void* D) : Data(D) {} + +public: + GRBlockCounter() : Data(0) {} + + unsigned getNumVisited(unsigned BlockID) const; + + class Factory { + void* F; + public: + Factory(llvm::BumpPtrAllocator& Alloc); + ~Factory(); + + GRBlockCounter GetEmptyCounter(); + GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID); + }; + + friend class Factory; +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h new file mode 100644 index 000000000000..0fbdbde55bd5 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -0,0 +1,668 @@ +//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- 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 a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRENGINE +#define LLVM_CLANG_ANALYSIS_GRENGINE + +#include "clang/AST/Expr.h" +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "clang/Analysis/PathSensitive/GRWorkList.h" +#include "clang/Analysis/PathSensitive/GRBlockCounter.h" +#include "clang/Analysis/PathSensitive/GRAuditor.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { + +class GRStmtNodeBuilderImpl; +class GRBranchNodeBuilderImpl; +class GRIndirectGotoNodeBuilderImpl; +class GRSwitchNodeBuilderImpl; +class GREndPathNodeBuilderImpl; +class GRWorkList; + +//===----------------------------------------------------------------------===// +/// GRCoreEngineImpl - Implements the core logic of the graph-reachability +/// analysis. It traverses the CFG and generates the ExplodedGraph. +/// Program "states" are treated as opaque void pointers. +/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl) +/// provides the matching component to the engine that knows the actual types +/// for states. Note that this engine only dispatches to transfer functions +/// at the statement and block-level. The analyses themselves must implement +/// any transfer function logic and the sub-expression level (if any). +class GRCoreEngineImpl { +protected: + friend class GRStmtNodeBuilderImpl; + friend class GRBranchNodeBuilderImpl; + friend class GRIndirectGotoNodeBuilderImpl; + friend class GRSwitchNodeBuilderImpl; + friend class GREndPathNodeBuilderImpl; + + /// G - The simulation graph. Each node is a (location,state) pair. + llvm::OwningPtr<ExplodedGraphImpl> G; + + /// WList - A set of queued nodes that need to be processed by the + /// worklist algorithm. It is up to the implementation of WList to decide + /// the order that nodes are processed. + GRWorkList* WList; + + /// BCounterFactory - A factory object for created GRBlockCounter objects. + /// These are used to record for key nodes in the ExplodedGraph the + /// number of times different CFGBlocks have been visited along a path. + GRBlockCounter::Factory BCounterFactory; + + void GenerateNode(const ProgramPoint& Loc, const void* State, + ExplodedNodeImpl* Pred); + + /// getInitialState - Gets the void* representing the initial 'state' + /// of the analysis. This is simply a wrapper (implemented + /// in GRCoreEngine) that performs type erasure on the initial + /// state returned by the checker object. + virtual const void* getInitialState() = 0; + + void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred); + void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred); + void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred); + void HandlePostStmt(const PostStmt& S, CFGBlock* B, + unsigned StmtIdx, ExplodedNodeImpl *Pred); + + void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, + ExplodedNodeImpl* Pred); + + virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0; + + virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, + GRBlockCounter BC) = 0; + + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0; + + virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilderImpl& Builder) = 0; + + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0; + + virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0; + +private: + GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement. + GRCoreEngineImpl& operator=(const GRCoreEngineImpl&); + +protected: + GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl) + : G(g), WList(wl), BCounterFactory(g->getAllocator()) {} + +public: + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of + /// steps. Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(unsigned Steps); + + virtual ~GRCoreEngineImpl(); + + CFG& getCFG() { return G->getCFG(); } +}; + +class GRStmtNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock& B; + const unsigned Idx; + ExplodedNodeImpl* Pred; + ExplodedNodeImpl* LastNode; + + typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy; + DeferredTy Deferred; + + void GenerateAutoTransition(ExplodedNodeImpl* N); + +public: + GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, + ExplodedNodeImpl* N, GRCoreEngineImpl* e); + + ~GRStmtNodeBuilderImpl(); + + ExplodedNodeImpl* getBasePredecessor() const { return Pred; } + + ExplodedNodeImpl* getLastNode() const { + return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; + } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNodeImpl* + generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred); + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0) { + ExplodedNodeImpl* N = getLastNode(); + assert (N && "Predecessor of new node is infeasible."); + return generateNodeImpl(S, State, N, K, tag); + } + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) { + ExplodedNodeImpl* N = getLastNode(); + assert (N && "Predecessor of new node is infeasible."); + return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag); + } + + /// getStmt - Return the current block-level expression associated with + /// this builder. + Stmt* getStmt() const { return B[Idx]; } + + /// getBlock - Return the CFGBlock associated with the block-level expression + /// of this builder. + CFGBlock* getBlock() const { return &B; } +}; + + +template<typename STATE> +class GRStmtNodeBuilder { +public: + typedef STATE StateTy; + typedef typename StateTy::ManagerTy StateManagerTy; + typedef ExplodedNode<StateTy> NodeTy; + +private: + GRStmtNodeBuilderImpl& NB; + StateManagerTy& Mgr; + const StateTy* CleanedState; + GRAuditor<StateTy>* Auditor; + +public: + GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) : + NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false), + BuildSinks(false), HasGeneratedNode(false), + PointKind(ProgramPoint::PostStmtKind), Tag(0) { + + CleanedState = getLastNode()->getState(); + } + + void setAuditor(GRAuditor<StateTy>* A) { + Auditor = A; + } + + NodeTy* getLastNode() const { + return static_cast<NodeTy*>(NB.getLastNode()); + } + + NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) { + HasGeneratedNode = true; + return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred, + ProgramPoint::Kind K) { + HasGeneratedNode = true; + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) { + return generateNode(S, St, Pred, PointKind); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) { + HasGeneratedNode = true; + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag)); + } + + NodeTy* generateNode(Stmt* S, const StateTy* St) { + return generateNode(S, St, PointKind); + } + + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + unsigned getCurrentBlockCount() const { + return NB.getCurrentBlockCount(); + } + + const StateTy* GetState(NodeTy* Pred) const { + if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor()) + return CleanedState; + else + return Pred->getState(); + } + + void SetCleanedState(const StateTy* St) { + CleanedState = St; + } + + NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St) { + return MakeNode(Dst, S, Pred, St, PointKind); + } + + NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) { + + const StateTy* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + NodeTy* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; + } + + NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S, + NodeTy* Pred, const StateTy* St) { + bool Tmp = BuildSinks; + BuildSinks = true; + NodeTy* N = MakeNode(Dst, S, Pred, St); + BuildSinks = Tmp; + return N; + } + + bool PurgingDeadSymbols; + bool BuildSinks; + bool HasGeneratedNode; + ProgramPoint::Kind PointKind; + const void *Tag; +}; + +class GRBranchNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + CFGBlock* DstT; + CFGBlock* DstF; + ExplodedNodeImpl* Pred; + + typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy; + DeferredTy Deferred; + + bool GeneratedTrue; + bool GeneratedFalse; + +public: + GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, + ExplodedNodeImpl* pred, GRCoreEngineImpl* e) + : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), + GeneratedTrue(false), GeneratedFalse(false) {} + + ~GRBranchNodeBuilderImpl(); + + ExplodedNodeImpl* getPredecessor() const { return Pred; } + const ExplodedGraphImpl& getGraph() const { return *Eng.G; } + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch); + + CFGBlock* getTargetBlock(bool branch) const { + return branch ? DstT : DstF; + } + + void markInfeasible(bool branch) { + if (branch) GeneratedTrue = true; + else GeneratedFalse = true; + } +}; + +template<typename STATE> +class GRBranchNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRBranchNodeBuilderImpl& NB; + +public: + GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {} + + const GraphTy& getGraph() const { + return static_cast<const GraphTy&>(NB.getGraph()); + } + + NodeTy* getPredecessor() const { + return static_cast<NodeTy*>(NB.getPredecessor()); + } + + const StateTy* getState() const { + return getPredecessor()->getState(); + } + + NodeTy* generateNode(const StateTy* St, bool branch) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch)); + } + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + CFGBlock* getTargetBlock(bool branch) const { + return NB.getTargetBlock(branch); + } + + void markInfeasible(bool branch) { + NB.markInfeasible(branch); + } +}; + +class GRIndirectGotoNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + CFGBlock& DispatchBlock; + Expr* E; + ExplodedNodeImpl* Pred; +public: + GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, + Expr* e, CFGBlock* dispatch, + GRCoreEngineImpl* eng) + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + + + class Iterator { + CFGBlock::succ_iterator I; + + friend class GRIndirectGotoNodeBuilderImpl; + Iterator(CFGBlock::succ_iterator i) : I(i) {} + public: + + Iterator& operator++() { ++I; return *this; } + bool operator!=(const Iterator& X) const { return I != X.I; } + + LabelStmt* getLabel() const { + return llvm::cast<LabelStmt>((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + Iterator begin() { return Iterator(DispatchBlock.succ_begin()); } + Iterator end() { return Iterator(DispatchBlock.succ_end()); } + + ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State, + bool isSink); + + Expr* getTarget() const { return E; } + const void* getState() const { return Pred->State; } +}; + +template<typename STATE> +class GRIndirectGotoNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRIndirectGotoNodeBuilderImpl& NB; + +public: + GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {} + + typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator; + + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } + + Expr* getTarget() const { return NB.getTarget(); } + + NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){ + return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink)); + } + + const StateTy* getState() const { + return static_cast<const StateTy*>(NB.getState()); + } +}; + +class GRSwitchNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock* Src; + Expr* Condition; + ExplodedNodeImpl* Pred; +public: + GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src, + Expr* condition, GRCoreEngineImpl* eng) + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + + class Iterator { + CFGBlock::succ_reverse_iterator I; + + friend class GRSwitchNodeBuilderImpl; + Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + public: + + Iterator& operator++() { ++I; return *this; } + bool operator!=(const Iterator& X) const { return I != X.I; } + + CaseStmt* getCase() const { + return llvm::cast<CaseStmt>((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + Iterator begin() { return Iterator(Src->succ_rbegin()+1); } + Iterator end() { return Iterator(Src->succ_rend()); } + + ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, + const void* State); + + ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State, + bool isSink); + + Expr* getCondition() const { return Condition; } + const void* getState() const { return Pred->State; } +}; + +template<typename STATE> +class GRSwitchNodeBuilder { + typedef STATE StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + + GRSwitchNodeBuilderImpl& NB; + +public: + GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {} + + typedef GRSwitchNodeBuilderImpl::Iterator iterator; + + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } + + Expr* getCondition() const { return NB.getCondition(); } + + NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) { + return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St)); + } + + NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) { + return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink)); + } + + const StateTy* getState() const { + return static_cast<const StateTy*>(NB.getState()); + } +}; + + +class GREndPathNodeBuilderImpl { + GRCoreEngineImpl& Eng; + CFGBlock& B; + ExplodedNodeImpl* Pred; + bool HasGeneratedNode; + +public: + GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N, + GRCoreEngineImpl* e) + : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + + ~GREndPathNodeBuilderImpl(); + + ExplodedNodeImpl* getPredecessor() const { return Pred; } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNodeImpl* generateNodeImpl(const void* State, + const void *tag = 0, + ExplodedNodeImpl *P = 0); + + CFGBlock* getBlock() const { return &B; } +}; + + +template<typename STATE> +class GREndPathNodeBuilder { + typedef STATE StateTy; + typedef ExplodedNode<StateTy> NodeTy; + + GREndPathNodeBuilderImpl& NB; + +public: + GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {} + + NodeTy* getPredecessor() const { + return static_cast<NodeTy*>(NB.getPredecessor()); + } + + GRBlockCounter getBlockCounter() const { + return NB.getBlockCounter(); + } + + unsigned getCurrentBlockCount() const { + return NB.getCurrentBlockCount(); + } + + const StateTy* getState() const { + return getPredecessor()->getState(); + } + + NodeTy* MakeNode(const StateTy* St, const void *tag = 0) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag)); + } + + NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) { + return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred)); + } +}; + + +template<typename SUBENGINE> +class GRCoreEngine : public GRCoreEngineImpl { +public: + typedef SUBENGINE SubEngineTy; + typedef typename SubEngineTy::StateTy StateTy; + typedef typename StateTy::ManagerTy StateManagerTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef typename GraphTy::NodeTy NodeTy; + +protected: + SubEngineTy& SubEngine; + + virtual const void* getInitialState() { + return SubEngine.getInitialState(); + } + + virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) { + GREndPathNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessEndPath(Builder); + } + + virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) { + GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager()); + SubEngine.ProcessStmt(S, Builder); + } + + virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State, + GRBlockCounter BC) { + return SubEngine.ProcessBlockEntrance(Blk, + static_cast<const StateTy*>(State), + BC); + } + + virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilderImpl& BuilderImpl) { + GRBranchNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessBranch(Condition, Terminator, Builder); + } + + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) { + GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessIndirectGoto(Builder); + } + + virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) { + GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl); + SubEngine.ProcessSwitch(Builder); + } + +public: + /// Construct a GRCoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), + GRWorkList::MakeBFS()), + SubEngine(subengine) {} + + /// Construct a GRCoreEngine object to analyze the provided CFG and to + /// use the provided worklist object to execute the worklist algorithm. + /// The GRCoreEngine object assumes ownership of 'wlist'. + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist, + SubEngineTy& subengine) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist), + SubEngine(subengine) {} + + virtual ~GRCoreEngine() {} + + /// getGraph - Returns the exploded graph. + GraphTy& getGraph() { + return *static_cast<GraphTy*>(G.get()); + } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transfered to the caller. + GraphTy* takeGraph() { + return static_cast<GraphTy*>(G.take()); + } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h new file mode 100644 index 000000000000..2068b1beaa13 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -0,0 +1,738 @@ +//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that +// is built on GRCoreEngine, 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 + +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/Type.h" +#include "clang/AST/ExprObjC.h" + +namespace clang { + + class PathDiagnosticClient; + class Diagnostic; + class ObjCForCollectionStmt; + +class GRExprEngine { +public: + typedef GRState StateTy; + typedef ExplodedGraph<StateTy> GraphTy; + typedef GraphTy::NodeTy NodeTy; + + // Builders. + typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder; + typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder; + typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder; + typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder; + typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder; + typedef ExplodedNodeSet<StateTy> NodeSet; + +protected: + GRCoreEngine<GRExprEngine> CoreEngine; + + /// G - the simulation graph. + GraphTy& G; + + /// Liveness - live-variables information the ValueDecl* and block-level + /// Expr* in the CFG. Used to prune out dead state. + LiveVariables& Liveness; + + /// Builder - The current GRStmtNodeBuilder which is used when building the + /// nodes for a given statement. + StmtNodeBuilder* Builder; + + /// StateMgr - Object that manages the data for all created states. + GRStateManager StateMgr; + + /// SymMgr - Object that manages the symbol information. + SymbolManager& SymMgr; + + /// ValMgr - Object that manages/creates SVals. + ValueManager &ValMgr; + + /// EntryNode - The immediate predecessor node. + NodeTy* EntryNode; + + /// CleanedState - The state for EntryNode "cleaned" of all dead + /// variables and symbols (as determined by a liveness analysis). + const GRState* CleanedState; + + /// CurrentStmt - The current block-level statement. + Stmt* CurrentStmt; + + // Obj-C Class Identifiers. + IdentifierInfo* NSExceptionII; + + // Obj-C Selectors. + Selector* NSExceptionInstanceRaiseSelectors; + Selector RaiseSel; + + llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; + + /// PurgeDead - Remove dead bindings before processing a statement. + bool PurgeDead; + + /// BR - The BugReporter associated with this engine. It is important that + // this object be placed at the very end of member variables so that its + // destructor is called before the rest of the GRExprEngine is destroyed. + GRBugReporter BR; + + /// EargerlyAssume - A flag indicating how the engine should handle + // expressions such as: 'x = (y != 0)'. When this flag is true then + // the subexpression 'y != 0' will be eagerly assumed to be true or false, + // thus evaluating it to the integers 0 or 1 respectively. The upside + // is that this can increase analysis precision until we have a better way + // to lazily evaluate such logic. The downside is that it eagerly + // bifurcates paths. + const bool EagerlyAssume; + +public: + typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes; + typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy; + + /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' definitely being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetExplicit; + + /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' possibly being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetImplicit; + + /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' definitely being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; + + /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' possibly being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; + + /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning + /// the address of a stack variable. + ErrorNodes RetsStackAddr; + + /// RetsUndef - Nodes in the ExplodedGraph that result from returning + /// an undefined value. + ErrorNodes RetsUndef; + + /// UndefBranches - Nodes in the ExplodedGraph that result from + /// taking a branch based on an undefined value. + ErrorNodes UndefBranches; + + /// UndefStores - Sinks in the ExplodedGraph that result from + /// making a store to an undefined lvalue. + ErrorNodes UndefStores; + + /// NoReturnCalls - Sinks in the ExplodedGraph that result from + // calling a function with the attribute "noreturn". + ErrorNodes NoReturnCalls; + + /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on a symbolic pointer that MAY be NULL. + ErrorNodes ImplicitNullDeref; + + /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on a symbolic pointer that MUST be NULL. + ErrorNodes ExplicitNullDeref; + + /// UnitDeref - Nodes in the ExplodedGraph that result from + /// taking a dereference on an undefined value. + ErrorNodes UndefDeref; + + /// ImplicitBadDivides - Nodes in the ExplodedGraph that result from + /// evaluating a divide or modulo operation where the denominator + /// MAY be zero. + ErrorNodes ImplicitBadDivides; + + /// ExplicitBadDivides - Nodes in the ExplodedGraph that result from + /// evaluating a divide or modulo operation where the denominator + /// MUST be zero or undefined. + ErrorNodes ExplicitBadDivides; + + /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + /// constructing a zero-sized VLA where the size may be zero. + ErrorNodes ImplicitBadSizedVLA; + + /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from + /// constructing a zero-sized VLA where the size must be zero. + ErrorNodes ExplicitBadSizedVLA; + + /// UndefResults - Nodes in the ExplodedGraph where the operands are defined + /// by the result is not. Excludes divide-by-zero errors. + ErrorNodes UndefResults; + + /// BadCalls - Nodes in the ExplodedGraph resulting from calls to function + /// pointers that are NULL (or other constants) or Undefined. + ErrorNodes BadCalls; + + /// UndefReceiver - Nodes in the ExplodedGraph resulting from message + /// ObjC message expressions where the receiver is undefined (uninitialized). + ErrorNodes UndefReceivers; + + /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions + /// where a pass-by-value argument has an undefined value. + UndefArgsTy UndefArgs; + + /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from + /// message expressions where a pass-by-value argument has an undefined + /// value. + UndefArgsTy MsgExprUndefArgs; + + /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from + /// out-of-bound memory accesses where the index MAY be out-of-bound. + ErrorNodes ImplicitOOBMemAccesses; + + /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from + /// out-of-bound memory accesses where the index MUST be out-of-bound. + ErrorNodes ExplicitOOBMemAccesses; + +public: + GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L, + BugReporterData& BRD, + bool purgeDead, bool eagerlyAssume = true, + StoreManagerCreator SMC = CreateBasicStoreManager, + ConstraintManagerCreator CMC = CreateBasicConstraintManager); + + ~GRExprEngine(); + + void ExecuteWorkList(unsigned Steps = 150000) { + CoreEngine.ExecuteWorkList(Steps); + } + + /// getContext - Return the ASTContext associated with this analysis. + ASTContext& getContext() const { return G.getContext(); } + + /// getCFG - Returns the CFG associated with this analysis. + CFG& getCFG() { return G.getCFG(); } + + GRTransferFuncs& getTF() { return *StateMgr.TF; } + + BugReporter& getBugReporter() { return BR; } + + /// setTransferFunctions + void setTransferFunctions(GRTransferFuncs* tf); + + void setTransferFunctions(GRTransferFuncs& tf) { + setTransferFunctions(&tf); + } + + /// ViewGraph - Visualize the ExplodedGraph created by executing the + /// simulation. + void ViewGraph(bool trim = false); + + void ViewGraph(NodeTy** Beg, NodeTy** End); + + /// getLiveness - Returned computed live-variables information for the + /// analyzed function. + const LiveVariables& getLiveness() const { return Liveness; } + LiveVariables& getLiveness() { return Liveness; } + + /// getInitialState - Return the initial state used for the root vertex + /// in the ExplodedGraph. + const GRState* getInitialState(); + + GraphTy& getGraph() { return G; } + const GraphTy& getGraph() const { return G; } + + void RegisterInternalChecks(); + + bool isRetStackAddr(const NodeTy* N) const { + return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefControlFlow(const NodeTy* N) const { + return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefStore(const NodeTy* N) const { + return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isImplicitNullDeref(const NodeTy* N) const { + return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isExplicitNullDeref(const NodeTy* N) const { + return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefDeref(const NodeTy* N) const { + return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isImplicitBadDivide(const NodeTy* N) const { + return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isExplicitBadDivide(const NodeTy* N) const { + return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isNoReturnCall(const NodeTy* N) const { + return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefResult(const NodeTy* N) const { + return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isBadCall(const NodeTy* N) const { + return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0; + } + + bool isUndefArg(const NodeTy* N) const { + return N->isSink() && + (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() || + MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end()); + } + + bool isUndefReceiver(const NodeTy* N) const { + return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0; + } + + typedef ErrorNodes::iterator ret_stackaddr_iterator; + ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); } + ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); } + + typedef ErrorNodes::iterator ret_undef_iterator; + ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); } + ret_undef_iterator ret_undef_end() { return RetsUndef.end(); } + + typedef ErrorNodes::iterator undef_branch_iterator; + undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } + undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } + + typedef ErrorNodes::iterator null_deref_iterator; + null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); } + null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); } + + null_deref_iterator implicit_null_derefs_begin() { + return ImplicitNullDeref.begin(); + } + null_deref_iterator implicit_null_derefs_end() { + return ImplicitNullDeref.end(); + } + + typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { + return NilReceiverStructRetExplicit.begin(); + } + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { + return NilReceiverStructRetExplicit.end(); + } + + typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_begin() { + return NilReceiverLargerThanVoidPtrRetExplicit.begin(); + } + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_end() { + return NilReceiverLargerThanVoidPtrRetExplicit.end(); + } + + typedef ErrorNodes::iterator undef_deref_iterator; + undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } + undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } + + typedef ErrorNodes::iterator bad_divide_iterator; + + bad_divide_iterator explicit_bad_divides_begin() { + return ExplicitBadDivides.begin(); + } + + bad_divide_iterator explicit_bad_divides_end() { + return ExplicitBadDivides.end(); + } + + bad_divide_iterator implicit_bad_divides_begin() { + return ImplicitBadDivides.begin(); + } + + bad_divide_iterator implicit_bad_divides_end() { + return ImplicitBadDivides.end(); + } + + typedef ErrorNodes::iterator undef_result_iterator; + undef_result_iterator undef_results_begin() { return UndefResults.begin(); } + undef_result_iterator undef_results_end() { return UndefResults.end(); } + + typedef ErrorNodes::iterator bad_calls_iterator; + bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); } + bad_calls_iterator bad_calls_end() { return BadCalls.end(); } + + typedef UndefArgsTy::iterator undef_arg_iterator; + undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); } + undef_arg_iterator undef_arg_end() { return UndefArgs.end(); } + + undef_arg_iterator msg_expr_undef_arg_begin() { + return MsgExprUndefArgs.begin(); + } + undef_arg_iterator msg_expr_undef_arg_end() { + return MsgExprUndefArgs.end(); + } + + typedef ErrorNodes::iterator undef_receivers_iterator; + + undef_receivers_iterator undef_receivers_begin() { + return UndefReceivers.begin(); + } + + undef_receivers_iterator undef_receivers_end() { + return UndefReceivers.end(); + } + + typedef ErrorNodes::iterator oob_memacc_iterator; + oob_memacc_iterator implicit_oob_memacc_begin() { + return ImplicitOOBMemAccesses.begin(); + } + oob_memacc_iterator implicit_oob_memacc_end() { + return ImplicitOOBMemAccesses.end(); + } + oob_memacc_iterator explicit_oob_memacc_begin() { + return ExplicitOOBMemAccesses.begin(); + } + oob_memacc_iterator explicit_oob_memacc_end() { + return ExplicitOOBMemAccesses.end(); + } + + void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); + void AddCheck(GRSimpleAPICheck* A); + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + void ProcessStmt(Stmt* S, StmtNodeBuilder& builder); + + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. + bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC); + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder); + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder); + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + void ProcessSwitch(SwitchNodeBuilder& builder); + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + void ProcessEndPath(EndPathNodeBuilder& builder) { + getTF().EvalEndPath(*this, builder); + StateMgr.EndPath(builder.getState()); + } + + GRStateManager& getStateManager() { return StateMgr; } + const GRStateManager& getStateManager() const { return StateMgr; } + + StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + + ConstraintManager& getConstraintManager() { + return StateMgr.getConstraintManager(); + } + + // FIXME: Remove when we migrate over to just using ValueManager. + BasicValueFactory& getBasicVals() { + return StateMgr.getBasicVals(); + } + const BasicValueFactory& getBasicVals() const { + 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; } + +protected: + + const GRState* GetState(NodeTy* N) { + return N == EntryNode ? CleanedState : N->getState(); + } + +public: + + const GRState* BindExpr(const GRState* St, Expr* Ex, SVal V) { + return StateMgr.BindExpr(St, Ex, V); + } + + const GRState* BindExpr(const GRState* St, const Expr* Ex, SVal V) { + return BindExpr(St, const_cast<Expr*>(Ex), V); + } + +protected: + + const GRState* BindBlkExpr(const GRState* St, Expr* Ex, SVal V) { + return StateMgr.BindExpr(St, Ex, V, true, false); + } + + const GRState* BindLoc(const GRState* St, Loc LV, SVal V) { + return StateMgr.BindLoc(St, LV, V); + } + + SVal GetSVal(const GRState* St, Stmt* Ex) { + return StateMgr.GetSVal(St, Ex); + } + + SVal GetSVal(const GRState* St, const Stmt* Ex) { + return GetSVal(St, const_cast<Stmt*>(Ex)); + } + + SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) { + return StateMgr.GetBlkExprSVal(St, Ex); + } + + SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) { + return StateMgr.GetSVal(St, LV, T); + } + + inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) { + return NonLoc::MakeVal(getBasicVals(), X, Ex->getType()); + } + + /// Assume - Create new state by assuming that a given expression + /// is true or false. + const GRState* Assume(const GRState* St, SVal Cond, bool Assumption, + bool& isFeasible) { + return StateMgr.Assume(St, Cond, Assumption, isFeasible); + } + + const GRState* Assume(const GRState* St, Loc Cond, bool Assumption, + bool& isFeasible) { + return StateMgr.Assume(St, Cond, Assumption, isFeasible); + } + + const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound, + bool Assumption, bool& isFeasible) { + return StateMgr.AssumeInBound(St, Idx, UpperBound, Assumption, isFeasible); + } + +public: + NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); +protected: + + /// Visit - Transfer function logic for all statements. Dispatches to + /// other functions that handle specific kinds of statements. + void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); + + /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is + /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its + /// storage location. Note that not all kinds of expressions has lvalue. + void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst); + + /// VisitArraySubscriptExpr - Transfer function for array accesses. + void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred, + NodeSet& Dst, bool asLValue); + + /// VisitAsmStmt - Transfer function logic for inline asm. + void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst); + + void VisitAsmStmtHelperOutputs(AsmStmt* A, + AsmStmt::outputs_iterator I, + AsmStmt::outputs_iterator E, + NodeTy* Pred, NodeSet& Dst); + + void VisitAsmStmtHelperInputs(AsmStmt* A, + AsmStmt::inputs_iterator I, + AsmStmt::inputs_iterator E, + NodeTy* Pred, NodeSet& Dst); + + /// VisitBinaryOperator - Transfer function logic for binary operators. + void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + + + /// VisitCall - Transfer function for function calls. + void VisitCall(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, + NodeSet& Dst); + void VisitCallRec(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, + NodeSet& Dst, const FunctionProtoType *, + unsigned ParamIdx = 0); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst); + + /// VisitCastPointerToInteger - Transfer function (called by VisitCast) that + /// handles pointer to integer casts and array to integer casts. + void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy, + Expr* CastE, NodeTy* Pred, NodeSet& Dst); + + /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. + void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred, + NodeSet& Dst, bool asLValue); + + /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. + void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + /// VisitDeclStmt - Transfer function logic for DeclStmts. + void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst); + + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst); + + void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst); + + /// VisitLogicalExpr - Transfer function logic for '&&', '||' + void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + + /// VisitMemberExpr - Transfer function for member expressions. + void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue); + + /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + /// VisitObjCForCollectionStmt - Transfer function logic for + /// ObjCForCollectionStmt. + void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred, + NodeSet& Dst); + + void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred, + NodeSet& Dst, SVal ElementV); + + /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. + void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst); + + void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, + ObjCMessageExpr::arg_iterator I, + ObjCMessageExpr::arg_iterator E, + NodeTy* Pred, NodeSet& Dst); + + void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred, + NodeSet& Dst); + + /// VisitReturnStmt - Transfer function logic for return statements. + void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst); + + /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred, + NodeSet& Dst); + + /// VisitUnaryOperator - Transfer function logic for unary operators. + void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst, + bool asLValue); + + const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred, + SVal Denom); + + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic + /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) + /// with those assumptions. + void EvalEagerlyAssume(NodeSet& Dst, NodeSet& Src, Expr *Ex); + + SVal EvalCast(SVal X, QualType CastT) { + if (X.isUnknownOrUndef()) + return X; + + if (isa<Loc>(X)) + return getTF().EvalCast(*this, cast<Loc>(X), CastT); + else + return getTF().EvalCast(*this, cast<NonLoc>(X), CastT); + } + + SVal EvalMinus(UnaryOperator* U, SVal X) { + return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X; + } + + SVal EvalComplement(SVal X) { + return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X; + } + +public: + + SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) { + return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T) + : R; + } + + SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) { + return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, + cast<NonLoc>(R), T) : R; + } + + void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, + ExplodedNode<GRState>* Pred, QualType T); + + void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T); + + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R, + QualType T); + +protected: + + void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred); + + void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) { + assert (Builder && "GRStmtNodeBuilder must be defined."); + getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred); + } + + void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred); + + const GRState* MarkBranch(const GRState* St, Stmt* Terminator, + bool branchTaken); + + /// EvalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by EvalStore, VisitDeclStmt, and others. + void EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + const GRState* St, SVal location, SVal Val); + +public: + void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, + const GRState* St, SVal location, const void *tag = 0); + + NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred, + const GRState* St, SVal location, + const void *tag = 0); + + + void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St, + SVal TargetLV, SVal Val, const void *tag = 0); + + void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred, + const GRState* St, SVal TargetLV, SVal Val, + const void *tag = 0); + +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h new file mode 100644 index 000000000000..6c23745de23a --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h @@ -0,0 +1,101 @@ +//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- 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 smart builder "references" which are used to marshal +// builders between GRExprEngine objects and their related components. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#include "clang/Analysis/PathSensitive/GRExprEngine.h" + +namespace clang { + + +// SaveAndRestore - A utility class that uses RAII to save and restore +// the value of a variable. +template<typename T> +struct SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } +private: + T& X; + T old_value; +}; + +// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old +// value of a variable is saved, and during the dstor the old value is +// or'ed with the new value. +struct SaveOr { + SaveOr(bool& x) : X(x), old_value(x) { x = false; } + ~SaveOr() { X |= old_value; } +private: + bool& X; + const bool old_value; +}; + +class GRStmtNodeBuilderRef { + GRExprEngine::NodeSet &Dst; + GRExprEngine::StmtNodeBuilder &B; + GRExprEngine& Eng; + GRExprEngine::NodeTy* 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; + + GRStmtNodeBuilderRef(); // do not implement + void operator=(const GRStmtNodeBuilderRef&); // do not implement + + GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst, + GRExprEngine::StmtNodeBuilder &builder, + GRExprEngine& eng, + GRExprEngine::NodeTy* pred, + const GRState *st, + const Stmt* s, bool auto_create_node) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), + OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {} + +public: + + ~GRStmtNodeBuilderRef() { + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { + if (AutoCreateNode) + B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + else + Dst.Add(Pred); + } + } + + GRStateRef getState() { + return GRStateRef(state, Eng.getStateManager()); + } + + GRStateManager& getStateManager() { + return Eng.getStateManager(); + } + + GRExprEngine::NodeTy* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state); + } +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h new file mode 100644 index 000000000000..e54b31dfe883 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -0,0 +1,40 @@ +// 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/Analysis/PathSensitive/GRAuditor.h" +#include "clang/Analysis/PathSensitive/GRState.h" + +namespace clang { + +class Diagnostic; +class BugReporter; +class ASTContext; +class GRExprEngine; +class PathDiagnosticClient; +template <typename T> class ExplodedGraph; + + +class GRSimpleAPICheck : public GRAuditor<GRState> { +public: + GRSimpleAPICheck() {} + virtual ~GRSimpleAPICheck() {} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h new file mode 100644 index 000000000000..d61feea4819e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -0,0 +1,820 @@ +//== GRState*h - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState* +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H +#define LLVM_CLANG_ANALYSIS_VALUESTATE_H + +// FIXME: Reduce the number of includes. + +#include "clang/Analysis/PathSensitive/Environment.h" +#include "clang/Analysis/PathSensitive/Store.h" +#include "clang/Analysis/PathSensitive/ConstraintManager.h" +#include "clang/Analysis/PathSensitive/ValueManager.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" + +#include <functional> + +namespace clang { + +class GRStateManager; +class GRTransferFuncs; + +typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&); +typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); + +//===----------------------------------------------------------------------===// +// GRStateTrait - Traits used by the Generic Data Map of a GRState. +//===----------------------------------------------------------------------===// + +template <typename T> struct GRStatePartialTrait; + +template <typename T> struct GRStateTrait { + typedef typename T::data_type data_type; + static inline void* GDMIndex() { return &T::TagInt; } + static inline void* MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void* const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + +//===----------------------------------------------------------------------===// +// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals. +//===----------------------------------------------------------------------===// + +/// GRState - This class encapsulates the actual data values for +/// for a "state" in our symbolic value tracking. It is intended to be +/// used as a functional object; that is once it is created and made +/// "persistent" in a FoldingSet its values will never change. +class GRState : public llvm::FoldingSetNode { +public: + // Typedefs. + typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + + typedef GRStateManager ManagerTy; + +private: + void operator=(const GRState& R) const; + + friend class GRStateManager; + + Environment Env; + Store St; + + // FIXME: Make these private. +public: + GenericDataMap GDM; + +public: + + /// This ctor is used when creating the first GRState object. + GRState(const Environment& env, Store st, GenericDataMap gdm) + : Env(env), + St(st), + GDM(gdm) {} + + /// Copy ctor - We must explicitly define this or else the "Next" ptr + /// in FoldingSetNode will also get copied. + GRState(const GRState& RHS) + : llvm::FoldingSetNode(), + Env(RHS.Env), + St(RHS.St), + GDM(RHS.GDM) {} + + /// getEnvironment - Return the environment associated with this state. + /// The environment is the mapping from expressions to values. + const Environment& getEnvironment() const { return Env; } + + /// getStore - Return the store associated with this state. The store + /// is a mapping from locations to values. + Store getStore() const { return St; } + + /// getGDM - Return the generic data map associated with this state. + GenericDataMap getGDM() const { return GDM; } + + /// Profile - Profile the contents of a GRState object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { + V->Env.Profile(ID); + ID.AddPointer(V->St); + V->GDM.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + SVal LookupExpr(Expr* E) const { + return Env.LookupExpr(E); + } + + // Iterators. + typedef Environment::seb_iterator seb_iterator; + seb_iterator seb_begin() const { return Env.seb_begin(); } + seb_iterator seb_end() const { return Env.beb_end(); } + + typedef Environment::beb_iterator beb_iterator; + beb_iterator beb_begin() const { return Env.beb_begin(); } + beb_iterator beb_end() const { return Env.beb_end(); } + + // Trait based GDM dispatch. + void* const* FindGDM(void* K) const; + + template <typename T> + typename GRStateTrait<T>::data_type + get() const { + return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex())); + } + + template<typename T> + typename GRStateTrait<T>::lookup_type + get(typename GRStateTrait<T>::key_type key) const { + void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); + return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key); + } + + template<typename T> + bool contains(typename GRStateTrait<T>::key_type key) const { + void* const* d = FindGDM(GRStateTrait<T>::GDMIndex()); + return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key); + } + + // State pretty-printing. + class Printer { + public: + virtual ~Printer() {} + virtual void Print(std::ostream& Out, const GRState* state, + const char* nl, const char* sep) = 0; + }; + + void print(std::ostream& Out, StoreManager& StoreMgr, + ConstraintManager& ConstraintMgr, + Printer **Beg = 0, Printer **End = 0, + const char* nl = "\n", const char *sep = "") const; + + // Tags used for the Generic Data Map. + struct NullDerefTag { + static int TagInt; + typedef const SVal* data_type; + }; +}; + +template<> struct GRTrait<GRState*> { + static inline void* toPtr(GRState* St) { return (void*) St; } + static inline GRState* toState(void* P) { return (GRState*) P; } + static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) { + // At this point states have already been uniqued. Just + // add the pointer. + profile.AddPointer(St); + } +}; + + +class GRStateSet { + typedef llvm::SmallPtrSet<const GRState*,5> ImplTy; + ImplTy Impl; +public: + GRStateSet() {} + + inline void Add(const GRState* St) { + Impl.insert(St); + } + + typedef ImplTy::const_iterator iterator; + + inline unsigned size() const { return Impl.size(); } + inline bool empty() const { return Impl.empty(); } + + inline iterator begin() const { return Impl.begin(); } + inline iterator end() const { return Impl.end(); } + + class AutoPopulate { + GRStateSet& S; + unsigned StartSize; + const GRState* St; + public: + AutoPopulate(GRStateSet& s, const GRState* st) + : S(s), StartSize(S.size()), St(st) {} + + ~AutoPopulate() { + if (StartSize == S.size()) + S.Add(St); + } + }; +}; + +//===----------------------------------------------------------------------===// +// GRStateManager - Factory object for GRStates. +//===----------------------------------------------------------------------===// + +class GRStateRef; + +class GRStateManager { + friend class GRExprEngine; + friend class GRStateRef; + +private: + EnvironmentManager EnvMgr; + llvm::OwningPtr<StoreManager> StoreMgr; + llvm::OwningPtr<ConstraintManager> ConstraintMgr; + GRState::IntSetTy::Factory ISetFactory; + + GRState::GenericDataMap::Factory GDMFactory; + + typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; + GDMContextsTy GDMContexts; + + /// Printers - A set of printer objects used for pretty-printing a GRState. + /// GRStateManager owns these objects. + std::vector<GRState::Printer*> Printers; + + /// StateSet - FoldingSet containing all the states created for analyzing + /// a particular function. This is used to unique states. + llvm::FoldingSet<GRState> StateSet; + + /// ValueMgr - Object that manages the data for all created SVals. + ValueManager ValueMgr; + + /// Alloc - A BumpPtrAllocator to allocate states. + llvm::BumpPtrAllocator& Alloc; + + /// CurrentStmt - The block-level statement currently being visited. This + /// is set by GRExprEngine. + Stmt* CurrentStmt; + + /// cfg - The CFG for the analyzed function/method. + CFG& cfg; + + /// codedecl - The Decl representing the function/method being analyzed. + const Decl& codedecl; + + /// TF - Object that represents a bundle of transfer functions + /// for manipulating and creating SVals. + GRTransferFuncs* TF; + + /// Liveness - live-variables information of the ValueDecl* and block-level + /// Expr* in the CFG. Used to get initial store and prune out dead state. + LiveVariables& Liveness; + +private: + + Environment RemoveBlkExpr(const Environment& Env, Expr* E) { + return EnvMgr.RemoveBlkExpr(Env, E); + } + + // FIXME: Remove when we do lazy initializaton of variable bindings. +// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) { +// return SetSVal(St, getLoc(D), V); +// } + +public: + + GRStateManager(ASTContext& Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManagerCreator CreateConstraintManager, + llvm::BumpPtrAllocator& alloc, CFG& c, + const Decl& cd, LiveVariables& L) + : EnvMgr(alloc), + ISetFactory(alloc), + GDMFactory(alloc), + ValueMgr(alloc, Ctx), + Alloc(alloc), + cfg(c), + codedecl(cd), + Liveness(L) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this)); + } + + ~GRStateManager(); + + const GRState* getInitialState(); + + ASTContext &getContext() { return ValueMgr.getContext(); } + const ASTContext &getContext() const { return ValueMgr.getContext(); } + + const Decl &getCodeDecl() { return codedecl; } + GRTransferFuncs& getTransferFuncs() { return *TF; } + + BasicValueFactory &getBasicVals() { + return ValueMgr.getBasicValueFactory(); + } + const BasicValueFactory& getBasicVals() const { + return ValueMgr.getBasicValueFactory(); + } + + SymbolManager &getSymbolManager() { + return ValueMgr.getSymbolManager(); + } + const SymbolManager &getSymbolManager() const { + return ValueMgr.getSymbolManager(); + } + + ValueManager &getValueManager() { return ValueMgr; } + const ValueManager &getValueManager() const { return ValueMgr; } + + LiveVariables& getLiveVariables() { return Liveness; } + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } + + MemRegionManager& getRegionManager() { + return ValueMgr.getRegionManager(); + } + const MemRegionManager& getRegionManager() const { + return ValueMgr.getRegionManager(); + } + + StoreManager& getStoreManager() { return *StoreMgr; } + ConstraintManager& getConstraintManager() { return *ConstraintMgr; } + + const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) { + // Store manager should return a persistent state. + return StoreMgr->BindDecl(St, VD, IVal); + } + + const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) { + // Store manager should return a persistent state. + return StoreMgr->BindDeclWithNoInit(St, VD); + } + + /// BindCompoundLiteral - Return the state that has the bindings currently + /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + const GRState* BindCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL, SVal V) { + return StoreMgr->BindCompoundLiteral(St, CL, V); + } + + const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + SymbolReaper& SymReaper); + + const GRState* RemoveSubExprBindings(const GRState* St) { + GRState NewSt = *St; + NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env); + return getPersistentState(NewSt); + } + + + // Utility methods for getting regions. + + VarRegion* getRegion(const VarDecl* D) { + return getRegionManager().getVarRegion(D); + } + + const MemRegion* getSelfRegion(const GRState* state) { + return StoreMgr->getSelfRegion(state->getStore()); + } + + // Get the lvalue for a variable reference. + SVal GetLValue(const GRState* St, const VarDecl* D) { + return StoreMgr->getLValueVar(St, D); + } + + // Get the lvalue for a StringLiteral. + SVal GetLValue(const GRState* St, const StringLiteral* E) { + return StoreMgr->getLValueString(St, E); + } + + SVal GetLValue(const GRState* St, const CompoundLiteralExpr* CL) { + return StoreMgr->getLValueCompoundLiteral(St, CL); + } + + // Get the lvalue for an ivar reference. + SVal GetLValue(const GRState* St, const ObjCIvarDecl* D, SVal Base) { + return StoreMgr->getLValueIvar(St, D, Base); + } + + // Get the lvalue for a field reference. + SVal GetLValue(const GRState* St, SVal Base, const FieldDecl* D) { + return StoreMgr->getLValueField(St, Base, D); + } + + // Get the lvalue for an array index. + SVal GetLValue(const GRState* St, QualType ElementType, SVal Base, SVal Idx) { + return StoreMgr->getLValueElement(St, ElementType, Base, Idx); + } + + // Methods that query & manipulate the Environment. + + SVal GetSVal(const GRState* St, Stmt* Ex) { + return St->getEnvironment().GetSVal(Ex, getBasicVals()); + } + + SVal GetSValAsScalarOrLoc(const GRState* state, const Stmt *S) { + if (const Expr *Ex = dyn_cast<Expr>(S)) { + QualType T = Ex->getType(); + if (Loc::IsLocType(T) || T->isIntegerType()) + return GetSVal(state, S); + } + + return UnknownVal(); + } + + + SVal GetSVal(const GRState* St, const Stmt* Ex) { + return St->getEnvironment().GetSVal(const_cast<Stmt*>(Ex), getBasicVals()); + } + + SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) { + return St->getEnvironment().GetBlkExprSVal(Ex, getBasicVals()); + } + + + + const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V, + bool isBlkExpr, bool Invalidate) { + + const Environment& OldEnv = St->getEnvironment(); + Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate); + + if (NewEnv == OldEnv) + return St; + + GRState NewSt = *St; + NewSt.Env = NewEnv; + return getPersistentState(NewSt); + } + + const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V, + bool Invalidate = true) { + + bool isBlkExpr = false; + + if (Ex == CurrentStmt) { + // FIXME: Should this just be an assertion? When would we want to set + // the value of a block-level expression if it wasn't CurrentStmt? + isBlkExpr = cfg.isBlkExpr(Ex); + + if (!isBlkExpr) + return St; + } + + return BindExpr(St, Ex, V, isBlkExpr, Invalidate); + } + + SVal ArrayToPointer(Loc Array) { + return StoreMgr->ArrayToPointer(Array); + } + + // Methods that manipulate the GDM. + const GRState* addGDM(const GRState* St, void* Key, void* Data); + + // Methods that query or create regions. + bool hasStackStorage(const MemRegion* R) { + return getRegionManager().hasStackStorage(R); + } + + // Methods that query & manipulate the Store. + + void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { + StoreMgr->iterBindings(state->getStore(), F); + } + + + SVal GetSVal(const GRState* state, Loc LV, QualType T = QualType()) { + return StoreMgr->Retrieve(state, LV, T); + } + + SVal GetSVal(const GRState* state, const MemRegion* R) { + return StoreMgr->Retrieve(state, loc::MemRegionVal(R)); + } + + SVal GetSValAsScalarOrLoc(const GRState* state, const MemRegion *R) { + // We only want to do fetches from regions that we can actually bind + // values. For example, SymbolicRegions of type 'id<...>' cannot + // have direct bindings (but their can be bindings on their subregions). + if (!R->isBoundable(getContext())) + return UnknownVal(); + + if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + QualType T = TR->getValueType(getContext()); + if (Loc::IsLocType(T) || T->isIntegerType()) + return GetSVal(state, R); + } + + return UnknownVal(); + } + + const GRState* BindLoc(const GRState* St, Loc LV, SVal V) { + return StoreMgr->Bind(St, LV, V); + } + + void Unbind(GRState& St, Loc LV) { + St.St = StoreMgr->Remove(St.St, LV); + } + + const GRState* Unbind(const GRState* St, Loc LV); + + const GRState* getPersistentState(GRState& Impl); + + // MakeStateWithStore - get a persistent state with the new store. + const GRState* MakeStateWithStore(const GRState* St, Store store); + + bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V); + bool isEqual(const GRState* state, Expr* Ex, uint64_t); + + + //==---------------------------------------------------------------------==// + // Generic Data Map methods. + //==---------------------------------------------------------------------==// + // + // GRStateManager and GRState support a "generic data map" that allows + // different clients of GRState objects to embed arbitrary data within a + // GRState object. The generic data map is essentially an immutable map + // from a "tag" (that acts as the "key" for a client) and opaque values. + // Tags/keys and values are simply void* values. The typical way that clients + // generate unique tags are by taking the address of a static variable. + // Clients are responsible for ensuring that data values referred to by a + // the data pointer are immutable (and thus are essentially purely functional + // data). + // + // The templated methods below use the GRStateTrait<T> class + // to resolve keys into the GDM and to return data values to clients. + // + + // Trait based GDM dispatch. + template <typename T> + const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) { + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(D)); + } + + template<typename T> + const GRState* set(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type V, + typename GRStateTrait<T>::context_type C) { + + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C))); + } + + template <typename T> + const GRState* add(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C))); + } + + template <typename T> + const GRState* remove(const GRState* st, + typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + + return addGDM(st, GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C))); + } + + + void* FindGDMContext(void* index, + void* (*CreateContext)(llvm::BumpPtrAllocator&), + void (*DeleteContext)(void*)); + + template <typename T> + typename GRStateTrait<T>::context_type get_context() { + void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(), + GRStateTrait<T>::CreateContext, + GRStateTrait<T>::DeleteContext); + + return GRStateTrait<T>::MakeContext(p); + } + + //==---------------------------------------------------------------------==// + // Constraints on values. + //==---------------------------------------------------------------------==// + // + // Each GRState records constraints on symbolic values. These constraints + // are managed using the ConstraintManager associated with a GRStateManager. + // 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. + // + // 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). + // + // (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). + // + + const GRState* Assume(const GRState* St, SVal Cond, bool Assumption, + bool& isFeasible) { + const GRState *state = + ConstraintMgr->Assume(St, Cond, Assumption, isFeasible); + assert(!isFeasible || state); + return isFeasible ? state : NULL; + } + + const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound, + bool Assumption, bool& isFeasible) { + const GRState *state = + ConstraintMgr->AssumeInBound(St, Idx, UpperBound, Assumption, + isFeasible); + assert(!isFeasible || state); + return isFeasible ? state : NULL; + } + + const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) { + return ConstraintMgr->getSymVal(St, sym); + } + + void EndPath(const GRState* St) { + ConstraintMgr->EndPath(St); + } + + bool scanReachableSymbols(SVal val, const GRState* state, + SymbolVisitor& visitor); +}; + +//===----------------------------------------------------------------------===// +// GRStateRef - A "fat" reference to GRState that also bundles GRStateManager. +//===----------------------------------------------------------------------===// + +class GRStateRef { + const GRState* St; + GRStateManager* Mgr; +public: + GRStateRef(const GRState* st, GRStateManager& mgr) : St(st), Mgr(&mgr) {} + + const GRState* getState() const { return St; } + operator const GRState*() const { return St; } + GRStateManager& getManager() const { return *Mgr; } + + SVal GetSVal(Expr* Ex) { + return Mgr->GetSVal(St, Ex); + } + + SVal GetBlkExprSVal(Expr* Ex) { + return Mgr->GetBlkExprSVal(St, Ex); + } + + SVal GetSValAsScalarOrLoc(const Expr *Ex) { + return Mgr->GetSValAsScalarOrLoc(St, Ex); + } + + SVal GetSVal(Loc LV, QualType T = QualType()) { + return Mgr->GetSVal(St, LV, T); + } + + SVal GetSVal(const MemRegion* R) { + return Mgr->GetSVal(St, R); + } + + SVal GetSValAsScalarOrLoc(const MemRegion *R) { + return Mgr->GetSValAsScalarOrLoc(St, R); + } + + GRStateRef BindExpr(Stmt* Ex, SVal V, bool isBlkExpr, bool Invalidate) { + return GRStateRef(Mgr->BindExpr(St, Ex, V, isBlkExpr, Invalidate), *Mgr); + } + + GRStateRef BindExpr(Stmt* Ex, SVal V, bool Invalidate = true) { + return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr); + } + + GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) { + return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr); + } + + GRStateRef BindLoc(Loc LV, SVal V) { + return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr); + } + + GRStateRef BindLoc(SVal LV, SVal V) { + if (!isa<Loc>(LV)) return *this; + return BindLoc(cast<Loc>(LV), V); + } + + GRStateRef Unbind(Loc LV) { + return GRStateRef(Mgr->Unbind(St, LV), *Mgr); + } + + // Trait based GDM dispatch. + template<typename T> + typename GRStateTrait<T>::data_type get() const { + return St->get<T>(); + } + + template<typename T> + typename GRStateTrait<T>::lookup_type + get(typename GRStateTrait<T>::key_type key) const { + return St->get<T>(key); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::data_type D) { + return GRStateRef(Mgr->set<T>(St, D), *Mgr); + } + + template <typename T> + typename GRStateTrait<T>::context_type get_context() { + return Mgr->get_context<T>(); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type E, + typename GRStateTrait<T>::context_type C) { + return GRStateRef(Mgr->set<T>(St, K, E, C), *Mgr); + } + + template<typename T> + GRStateRef set(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::value_type E) { + return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr); + } + + template<typename T> + GRStateRef add(typename GRStateTrait<T>::key_type K) { + return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr); + } + + template<typename T> + GRStateRef remove(typename GRStateTrait<T>::key_type K, + typename GRStateTrait<T>::context_type C) { + return GRStateRef(Mgr->remove<T>(St, K, C), *Mgr); + } + + template<typename T> + GRStateRef remove(typename GRStateTrait<T>::key_type K) { + return GRStateRef(Mgr->remove<T>(St, K, get_context<T>()), *Mgr); + } + + template<typename T> + bool contains(typename GRStateTrait<T>::key_type key) const { + return St->contains<T>(key); + } + + // Lvalue methods. + SVal GetLValue(const VarDecl* VD) { + return Mgr->GetLValue(St, VD); + } + + GRStateRef Assume(SVal Cond, bool Assumption, bool& isFeasible) { + return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr); + } + + template <typename CB> + CB scanReachableSymbols(SVal val) { + CB cb(*this); + Mgr->scanReachableSymbols(val, St, cb); + return cb; + } + + SymbolManager& getSymbolManager() { return Mgr->getSymbolManager(); } + BasicValueFactory& getBasicVals() { return Mgr->getBasicVals(); } + + // Pretty-printing. + void print(std::ostream& Out, const char* nl = "\n", + const char *sep = "") const; + + void printStdErr() const; + + void printDOT(std::ostream& Out) const; +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h new file mode 100644 index 000000000000..ce43cda31e9e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h @@ -0,0 +1,148 @@ +//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 partial implementations of template specializations of +// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement +// set/get methods for mapulating a GRState's generic data map. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H +#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H + +namespace llvm { + class BumpPtrAllocator; + template <typename K, typename D, typename I> class ImmutableMap; + template <typename K, typename I> class ImmutableSet; + template <typename T> class ImmutableList; + template <typename T> class ImmutableListImpl; +} + +namespace clang { + template <typename T> struct GRStatePartialTrait; + + // Partial-specialization for ImmutableMap. + + template <typename Key, typename Data, typename Info> + struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { + typedef llvm::ImmutableMap<Key,Data,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + typedef Data value_type; + typedef const value_type* lookup_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + static lookup_type Lookup(data_type B, key_type K) { + return B.lookup(K); + } + static data_type Set(data_type B, key_type K, value_type E,context_type F){ + return F.Add(B, K, E); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial-specialization for ImmutableSet. + + template <typename Key, typename Info> + struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > { + typedef llvm::ImmutableSet<Key,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + + static data_type Add(data_type B, key_type K, context_type F) { + return F.Add(B, K); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static bool Contains(data_type B, key_type K) { + return B.contains(K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + // Partial-specialization for ImmutableList. + + template <typename T> + struct GRStatePartialTrait< llvm::ImmutableList<T> > { + typedef llvm::ImmutableList<T> data_type; + typedef T key_type; + typedef typename data_type::Factory& context_type; + + static data_type Add(data_type L, key_type K, context_type F) { + return F.Add(K, L); + } + + static inline data_type MakeData(void* const* p) { + return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) + : data_type(0); + } + + static inline void* MakeVoidPtr(data_type D) { + return (void*) D.getInternalPointer(); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h new file mode 100644 index 000000000000..0f353d07004f --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -0,0 +1,123 @@ +//== 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/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include <vector> + +namespace clang { + + class GRExprEngine; + class BugReporter; + class ObjCMessageExpr; + class GRStmtNodeBuilderRef; + +class GRTransferFuncs { + friend class GRExprEngine; +protected: + virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng, + BinaryOperator::Opcode Op, + NonLoc L, NonLoc R, QualType T) { + return UnknownVal(); + } + +public: + GRTransferFuncs() {} + virtual ~GRTransferFuncs() {} + + virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} + virtual void RegisterChecks(BugReporter& BR) {} + + // Casts. + + virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0; + virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0; + + // Unary Operators. + + virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0; + + virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0; + + // Binary Operators. + // FIXME: We're moving back towards using GREXprEngine directly. No need + // for OStates + virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng, + const GRState* St, Expr* Ex, + BinaryOperator::Opcode Op, NonLoc L, NonLoc R, + QualType T); + + virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, + Loc L, Loc R) = 0; + + // Pointer arithmetic. + + virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state, + BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0; + + // Calls. + + virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + CallExpr* CE, SVal L, + ExplodedNode<GRState>* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ObjCMessageExpr* ME, + ExplodedNode<GRState>* Pred) {} + + // Stores. + + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} + + // End-of-path and dead symbol notification. + + virtual void EvalEndPath(GRExprEngine& Engine, + GREndPathNodeBuilder<GRState>& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ExplodedNode<GRState>* Pred, + Stmt* S, const GRState* state, + SymbolReaper& SymReaper) {} + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder<GRState>& Builder, + ReturnStmt* S, + ExplodedNode<GRState>* Pred) {} + + // Assumptions. + + virtual const GRState* EvalAssume(GRStateManager& VMgr, + const GRState* St, + SVal Cond, bool Assumption, + bool& isFeasible) { + return St; + } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h new file mode 100644 index 000000000000..c76532294c1f --- /dev/null +++ b/include/clang/Analysis/PathSensitive/GRWorkList.h @@ -0,0 +1,76 @@ +//==- 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/Analysis/PathSensitive/GRBlockCounter.h" + +namespace clang { + +class ExplodedNodeImpl; + +class GRWorkListUnit { + ExplodedNodeImpl* Node; + GRBlockCounter Counter; + CFGBlock* Block; + unsigned BlockIdx; + +public: + GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C, + CFGBlock* B, unsigned idx) + : Node(N), + Counter(C), + Block(B), + BlockIdx(idx) {} + + explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C) + : Node(N), + Counter(C), + Block(NULL), + BlockIdx(0) {} + + ExplodedNodeImpl* getNode() const { return Node; } + GRBlockCounter getBlockCounter() const { return Counter; } + 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(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) { + Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); + } + + void Enqueue(ExplodedNodeImpl* 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/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h new file mode 100644 index 000000000000..0e8da2aee318 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -0,0 +1,665 @@ +//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines MemRegion and its subclasses. MemRegion defines a +// partially-typed abstraction of memory useful for path-sensitive dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H +#define LLVM_CLANG_ANALYSIS_MEMREGION_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/Support/Allocator.h" +#include <string> + +namespace llvm { class raw_ostream; } + +namespace clang { + +class MemRegionManager; + + +/// MemRegion - The root abstract class for all memory regions. +class MemRegion : public llvm::FoldingSetNode { +public: + enum Kind { MemSpaceRegionKind, + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + CodeTextRegionKind, + CompoundLiteralRegionKind, + StringRegionKind, ElementRegionKind, + TypedViewRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind, FieldRegionKind, + ObjCIvarRegionKind, ObjCObjectRegionKind, + END_DECL_REGIONS, + END_TYPED_REGIONS }; +private: + const Kind kind; + +protected: + MemRegion(Kind k) : kind(k) {} + virtual ~MemRegion(); + +public: + // virtual MemExtent getExtent(MemRegionManager& mrm) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; + + std::string getString() const; + + virtual void print(llvm::raw_ostream& os) const; + + Kind getKind() const { return kind; } + + template<typename RegionTy> const RegionTy* getAs() const; + + virtual bool isBoundable(ASTContext&) const { return true; } + + static bool classof(const MemRegion*) { return true; } +}; + +/// MemSpaceRegion - A memory region that represents and "memory space"; +/// for example, the set of global variables, the stack frame, etc. +class MemSpaceRegion : public MemRegion { + friend class MemRegionManager; + MemSpaceRegion() : MemRegion(MemSpaceRegionKind) {} + +public: + //RegionExtent getExtent() const { return UndefinedExtent(); } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + bool isBoundable(ASTContext &) const { return false; } + + static bool classof(const MemRegion* R) { + return R->getKind() == MemSpaceRegionKind; + } +}; + +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { +protected: + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} + +public: + const MemRegion* getSuperRegion() const { + return superRegion; + } + + bool isSubRegionOf(const MemRegion* R) const; + + static bool classof(const MemRegion* R) { + return R->getKind() > MemSpaceRegionKind; + } +}; + +/// AllocaRegion - A region that represents an untyped blob of bytes created +/// by a call to 'alloca'. +class AllocaRegion : public SubRegion { + friend class MemRegionManager; +protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of + // memory allocated by alloca at the same call site. + const Expr* Ex; + + AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion* superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + +public: + + const Expr* getExpr() const { return Ex; } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, + unsigned Cnt); + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == AllocaRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getValueType(ASTContext &C) const = 0; + + virtual QualType getLocationType(ASTContext& C) const { + // FIXME: We can possibly optimize this later to cache this value. + return C.getPointerType(getValueType(C)); + } + + QualType getDesugaredValueType(ASTContext& C) const { + QualType T = getValueType(C); + return T.getTypePtr() ? T->getDesugaredType() : T; + } + + QualType getDesugaredLocationType(ASTContext& C) const { + return getLocationType(C)->getDesugaredType(); + } + + bool isBoundable(ASTContext &C) const { + return !getValueType(C).isNull(); + } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS; + } +}; + +/// CodeTextRegion - A region that represents code texts of a function. It wraps +/// two kinds of code texts: real function and symbolic function. Real function +/// is a function declared in the program. Symbolic function is a function +/// pointer that we don't know which function it points to. +class CodeTextRegion : public TypedRegion { +public: + enum CodeKind { Declared, Symbolic }; + +private: + // The function pointer kind that this CodeTextRegion represents. + CodeKind codekind; + + // Data may be a SymbolRef or FunctionDecl*. + const void* Data; + + // Cached function pointer type. + QualType LocationType; + +public: + + CodeTextRegion(const FunctionDecl* fd, QualType t, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), + codekind(Declared), + Data(fd), + LocationType(t) {} + + CodeTextRegion(SymbolRef sym, QualType t, const MemRegion* sreg) + : TypedRegion(sreg, CodeTextRegionKind), + codekind(Symbolic), + Data(sym), + LocationType(t) {} + + QualType getValueType(ASTContext &C) const { + // Do not get the object type of a CodeTextRegion. + assert(0); + return QualType(); + } + + QualType getLocationType(ASTContext &C) const { + return LocationType; + } + + bool isDeclared() const { return codekind == Declared; } + bool isSymbolic() const { return codekind == Symbolic; } + + const FunctionDecl* getDecl() const { + assert(codekind == Declared); + return static_cast<const FunctionDecl*>(Data); + } + + SymbolRef getSymbol() const { + assert(codekind == Symbolic); + return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data)); + } + + bool isBoundable(ASTContext&) const { return false; } + + virtual void print(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const void* data, QualType t); + + static bool classof(const MemRegion* R) { + return R->getKind() == CodeTextRegionKind; + } +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// clases, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public SubRegion { +protected: + const SymbolRef sym; + +public: + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + + SymbolRef getSymbol() const { + return sym; + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym); + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// StringRegion - Region associated with a StringLiteral. +class StringRegion : public TypedRegion { + friend class MemRegionManager; + const StringLiteral* Str; +protected: + + StringRegion(const StringLiteral* str, MemRegion* sreg) + : TypedRegion(sreg, StringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, + const MemRegion* superRegion); + +public: + + const StringLiteral* getStringLiteral() const { return Str; } + + QualType getValueType(ASTContext& C) const { + return Str->getType(); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, Str, superRegion); + } + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == StringRegionKind; + } +}; + +class TypedViewRegion : public TypedRegion { + friend class MemRegionManager; + QualType LValueType; + + TypedViewRegion(QualType lvalueType, const MemRegion* sreg) + : TypedRegion(sreg, TypedViewRegionKind), LValueType(lvalueType) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, + const MemRegion* superRegion); + +public: + + void print(llvm::raw_ostream& os) const; + + QualType getLocationType(ASTContext&) const { + return LValueType; + } + + QualType getValueType(ASTContext&) const { + const PointerType* PTy = LValueType->getAsPointerType(); + assert(PTy); + return PTy->getPointeeType(); + } + + bool isBoundable(ASTContext &C) const { + return isa<PointerType>(LValueType); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, LValueType, superRegion); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == TypedViewRegionKind; + } + + const MemRegion *removeViews() const; +}; + + +/// CompoundLiteralRegion - A memory region representing a compound literal. +/// Compound literals are essentially temporaries that are stack allocated +/// or in the global constant pool. +class CompoundLiteralRegion : public TypedRegion { +private: + friend class MemRegionManager; + const CompoundLiteralExpr* CL; + + CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) + : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const CompoundLiteralExpr* CL, + const MemRegion* superRegion); +public: + QualType getValueType(ASTContext& C) const { + return C.getCanonicalType(CL->getType()); + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + void print(llvm::raw_ostream& os) const; + + const CompoundLiteralExpr* getLiteralExpr() const { return CL; } + + static bool classof(const MemRegion* R) { + return R->getKind() == CompoundLiteralRegionKind; + } +}; + +class DeclRegion : public TypedRegion { +protected: + const Decl* D; + + DeclRegion(const Decl* d, const MemRegion* sReg, Kind k) + : TypedRegion(sReg, k), D(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, + const MemRegion* superRegion, Kind k); + +public: + const Decl* getDecl() const { return D; } + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS; + } +}; + +class VarRegion : public DeclRegion { + friend class MemRegionManager; + + VarRegion(const VarDecl* vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + } + +public: + const VarDecl* getDecl() const { return cast<VarDecl>(D); } + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + void print(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == VarRegionKind; + } +}; + +class FieldRegion : public DeclRegion { + friend class MemRegionManager; + + FieldRegion(const FieldDecl* fd, const MemRegion* sReg) + : DeclRegion(fd, sReg, FieldRegionKind) {} + +public: + + void print(llvm::raw_ostream& os) const; + + const FieldDecl* getDecl() const { return cast<FieldDecl>(D); } + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == FieldRegionKind; + } +}; + +class ObjCObjectRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg) + : DeclRegion(ivd, sReg, ObjCObjectRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCInterfaceDecl* ivd, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind); + } + +public: + const ObjCInterfaceDecl* getInterface() const { + return cast<ObjCInterfaceDecl>(D); + } + + QualType getValueType(ASTContext& C) const { + return C.getObjCInterfaceType(getInterface()); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCObjectRegionKind; + } +}; + +class ObjCIvarRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) + : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); + } + +public: + const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); } + QualType getValueType(ASTContext&) const { return getDecl()->getType(); } + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCIvarRegionKind; + } +}; + +class ElementRegion : public TypedRegion { + friend class MemRegionManager; + + QualType ElementType; + SVal Index; + + ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg) + : TypedRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { + assert((!isa<nonloc::ConcreteInt>(&Idx) || + cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && + "The index must be signed"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, + SVal Idx, const MemRegion* superRegion); + +public: + + SVal getIndex() const { return Index; } + + QualType getValueType(ASTContext&) const { + return ElementType; + } + + QualType getElementType() const { + return ElementType; + } + + void print(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ElementRegionKind; + } +}; + +template<typename RegionTy> +const RegionTy* MemRegion::getAs() const { + const MemRegion *R = this; + + do { + if (const RegionTy* RT = dyn_cast<RegionTy>(R)) + return RT; + + if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) { + R = TR->getSuperRegion(); + continue; + } + + break; + } + while (R); + + return 0; +} + +//===----------------------------------------------------------------------===// +// MemRegionManager - Factory object for creating regions. +//===----------------------------------------------------------------------===// + +class MemRegionManager { + llvm::BumpPtrAllocator& A; + llvm::FoldingSet<MemRegion> Regions; + + MemSpaceRegion* globals; + MemSpaceRegion* stack; + MemSpaceRegion* heap; + MemSpaceRegion* unknown; + MemSpaceRegion* code; + +public: + MemRegionManager(llvm::BumpPtrAllocator& a) + : A(a), globals(0), stack(0), heap(0), unknown(0), code(0) {} + + ~MemRegionManager() {} + + /// getStackRegion - Retrieve the memory region associated with the + /// current stack frame. + MemSpaceRegion* getStackRegion(); + + /// getGlobalsRegion - Retrieve the memory region associated with + /// all global variables. + MemSpaceRegion* getGlobalsRegion(); + + /// getHeapRegion - Retrieve the memory region associated with the + /// generic "heap". + MemSpaceRegion* getHeapRegion(); + + /// getUnknownRegion - Retrieve the memory region associated with unknown + /// memory space. + MemSpaceRegion* getUnknownRegion(); + + MemSpaceRegion* getCodeRegion(); + + bool isGlobalsRegion(const MemRegion* R) { + assert(R); + return R == globals; + } + + /// onStack - check if the region is allocated on the stack. + bool onStack(const MemRegion* R); + + /// onHeap - check if the region is allocated on the heap, usually by malloc. + bool onHeap(const MemRegion* R); + + /// getAllocaRegion - Retrieve a region associated with a call to alloca(). + AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt); + + /// getCompoundLiteralRegion - Retrieve the region associated with a + /// given CompoundLiteral. + CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr* CL); + + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. + SymbolicRegion* getSymbolicRegion(SymbolRef sym); + + StringRegion* getStringRegion(const StringLiteral* Str); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl. + VarRegion* getVarRegion(const VarDecl* vd); + + /// getElementRegion - Retrieve the memory region associated with the + /// associated element type, index, and super region. + ElementRegion* getElementRegion(QualType elementType, SVal Idx, + const MemRegion* superRegion); + + /// getFieldRegion - Retrieve or create the memory region associated with + /// a specified FieldDecl. 'superRegion' corresponds to the containing + /// memory region (which typically represents the memory representing + /// a structure or class). + FieldRegion* getFieldRegion(const FieldDecl* fd, + const MemRegion* superRegion); + + /// getObjCObjectRegion - Retrieve or create the memory region associated with + /// the instance of a specified Objective-C class. + ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID, + const MemRegion* superRegion); + + /// getObjCIvarRegion - Retrieve or create the memory region associated with + /// a specified Objective-c instance variable. 'superRegion' corresponds + /// to the containing region (which typically represents the Objective-C + /// object). + ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd, + const MemRegion* superRegion); + + TypedViewRegion* getTypedViewRegion(QualType LValueType, + const MemRegion* superRegion); + + CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t); + CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t); + + bool hasStackStorage(const MemRegion* R); + +private: + MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); +}; +} // end clang namespace + +namespace llvm { +static inline raw_ostream& operator<<(raw_ostream& O, + const clang::MemRegion* R) { + R->print(O); + return O; +} +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h new file mode 100644 index 000000000000..ee6d4dcf1f37 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -0,0 +1,447 @@ +//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SVal, Loc, and NonLoc, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H +#define LLVM_CLANG_ANALYSIS_RVALUE_H + +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/ImmutableList.h" + +//==------------------------------------------------------------------------==// +// Base SVal types. +//==------------------------------------------------------------------------==// + +namespace clang { + +class CompoundValData; +class BasicValueFactory; +class MemRegion; +class MemRegionManager; +class GRStateManager; + +class SVal { +public: + enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; + enum { BaseBits = 2, BaseMask = 0x3 }; + +protected: + void* Data; + unsigned Kind; + +protected: + SVal(const void* d, bool isLoc, unsigned ValKind) + : Data(const_cast<void*>(d)), + Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} + + explicit SVal(BaseKind k, void* D = NULL) + : Data(D), Kind(k) {} + +public: + SVal() : Data(0), Kind(0) {} + ~SVal() {}; + + /// BufferTy - A temporary buffer to hold a set of SVals. + typedef llvm::SmallVector<SVal,5> BufferTy; + + inline unsigned getRawKind() const { return Kind; } + inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } + inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + + inline void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getRawKind()); + ID.AddPointer(reinterpret_cast<void*>(Data)); + } + + inline bool operator==(const SVal& R) const { + return getRawKind() == R.getRawKind() && Data == R.Data; + } + + inline bool operator!=(const SVal& R) const { + return !(*this == R); + } + + inline bool isUnknown() const { + return getRawKind() == UnknownKind; + } + + inline bool isUndef() const { + return getRawKind() == UndefinedKind; + } + + inline bool isUnknownOrUndef() const { + return getRawKind() <= UnknownKind; + } + + inline bool isValid() const { + return getRawKind() > UnknownKind; + } + + bool isZeroConstant() const; + + /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; + bool hasConjuredSymbol() const; + + /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// Otherwise return 0. + const FunctionDecl* getAsFunctionDecl() const; + + /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and + /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* + SymbolRef getAsLocSymbol() const; + + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. + /// Otherwise return a SymbolRef where 'isValid()' returns false. + SymbolRef getAsSymbol() const; + + /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then + /// return that expression. Otherwise return NULL. + const SymExpr *getAsSymbolicExpression() const; + + void print(std::ostream& OS) const; + void print(llvm::raw_ostream& OS) const; + void printStdErr() const; + + // Iterators. + class symbol_iterator { + llvm::SmallVector<const SymExpr*, 5> itr; + void expand(); + public: + symbol_iterator() {} + symbol_iterator(const SymExpr* SE); + + symbol_iterator& operator++(); + SymbolRef operator*(); + + bool operator==(const symbol_iterator& X) const; + bool operator!=(const symbol_iterator& X) const; + }; + + symbol_iterator symbol_begin() const { + const SymExpr *SE = getAsSymbolicExpression(); + if (SE) + return symbol_iterator(SE); + else + return symbol_iterator(); + } + + symbol_iterator symbol_end() const { return symbol_iterator(); } + + // Implement isa<T> support. + static inline bool classof(const SVal*) { return true; } +}; + +class UnknownVal : public SVal { +public: + UnknownVal() : SVal(UnknownKind) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UnknownKind; + } +}; + +class UndefinedVal : public SVal { +public: + UndefinedVal() : SVal(UndefinedKind) {} + UndefinedVal(void* D) : SVal(UndefinedKind, D) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UndefinedKind; + } + + void* getData() const { return Data; } +}; + +class NonLoc : public SVal { +protected: + NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {} + +public: + void print(llvm::raw_ostream& Out) const; + + // Utility methods to create NonLocs. + + static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X, + bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, + unsigned BitWidth, bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I, + bool isUnsigned); + + static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I); + + static NonLoc MakeIntTruthVal(BasicValueFactory& BasicVals, bool b); + + static NonLoc MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals, + BasicValueFactory& BasicVals); + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind; + } +}; + +class Loc : public SVal { +protected: + Loc(unsigned SubKind, const void* D) + : SVal(const_cast<void*>(D), true, SubKind) {} + +public: + void print(llvm::raw_ostream& Out) const; + + Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {} + Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } + + static Loc MakeVal(const MemRegion* R); + + static Loc MakeVal(AddrLabelExpr* E); + + static Loc MakeNull(BasicValueFactory &BasicVals); + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind; + } + + static inline bool IsLocType(QualType T) { + return T->isPointerType() || T->isObjCQualifiedIdType() + || T->isBlockPointerType(); + } +}; + +//==------------------------------------------------------------------------==// +// Subclasses of NonLoc. +//==------------------------------------------------------------------------==// + +namespace nonloc { + +enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, + LocAsIntegerKind, CompoundValKind }; + +class SymbolVal : public NonLoc { +public: + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + + SymbolRef getSymbol() const { + return (const SymbolData*) Data; + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymbolValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymbolValKind; + } +}; + +class SymExprVal : public NonLoc { +public: + SymExprVal(const SymExpr *SE) + : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {} + + const SymExpr *getSymbolicExpression() const { + return reinterpret_cast<SymExpr*>(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymExprValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymExprValKind; + } +}; + +class ConcreteInt : public NonLoc { +public: + ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const; + + ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +class LocAsInteger : public NonLoc { + LocAsInteger(const std::pair<SVal, uintptr_t>& data) : + NonLoc(LocAsIntegerKind, &data) { + assert (isa<Loc>(data.first)); + } + +public: + + Loc getLoc() const { + return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first); + } + + const Loc& getPersistentLoc() const { + const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first; + return cast<Loc>(V); + } + + unsigned getNumBits() const { + return ((std::pair<SVal, unsigned>*) Data)->second; + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LocAsIntegerKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == LocAsIntegerKind; + } + + static LocAsInteger Make(BasicValueFactory& Vals, Loc V, unsigned Bits); +}; + +class CompoundVal : public NonLoc { + friend class NonLoc; + + CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + +public: + const CompoundValData* getValue() const { + return static_cast<CompoundValData*>(Data); + } + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const; + iterator end() const; + + static bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; + } + + static bool classof(const NonLoc* V) { + return V->getSubKind() == CompoundValKind; + } +}; + +} // end namespace clang::nonloc + +//==------------------------------------------------------------------------==// +// Subclasses of Loc. +//==------------------------------------------------------------------------==// + +namespace loc { + +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; + +class GotoLabel : public Loc { +public: + GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} + + LabelStmt* getLabel() const { + return static_cast<LabelStmt*>(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == GotoLabelKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == GotoLabelKind; + } +}; + + +class MemRegionVal : public Loc { +public: + MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + + const MemRegion* getRegion() const { + return static_cast<MemRegion*>(Data); + } + + template <typename REGION> + const REGION* getRegionAs() const { + return llvm::dyn_cast<REGION>(getRegion()); + } + + inline bool operator==(const MemRegionVal& R) const { + return getRegion() == R.getRegion(); + } + + inline bool operator!=(const MemRegionVal& R) const { + return getRegion() != R.getRegion(); + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == MemRegionKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == MemRegionKind; + } +}; + +class ConcreteInt : public Loc { +public: + ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +} // end clang::loc namespace +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h new file mode 100644 index 000000000000..1f081f4eb0d0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -0,0 +1,204 @@ +//== Store.h - Interface for maps from Locations to 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 defined the types Store and StoreManager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_STORE_H +#define LLVM_CLANG_ANALYSIS_STORE_H + +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Analysis/PathSensitive/ValueManager.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include <iosfwd> + +namespace clang { + +typedef const void* Store; + +class GRState; +class GRStateManager; +class Stmt; +class Expr; +class ObjCIvarDecl; +class SubRegionMap; + +class StoreManager { +protected: + ValueManager &ValMgr; + GRStateManager &StateMgr; + + /// MRMgr - Manages region objects associated with this StoreManager. + MemRegionManager &MRMgr; + + StoreManager(GRStateManager &stateMgr); + +protected: + virtual const GRState* AddRegionView(const GRState* St, + const MemRegion* View, + const MemRegion* Base) { + return St; + } + +public: + virtual ~StoreManager() {} + + /// Return the value bound to specified location in a given state. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] T An optional type that provides a hint indicating the + /// expected type of the returned value. This is used if the value is + /// lazily computed. + /// \return The value bound to the location \c loc. + virtual SVal Retrieve(const GRState* state, Loc loc, + QualType T = QualType()) = 0; + + /// Return a state with the specified value bound to the given location. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] val The value to bind to location \c loc. + /// \return A pointer to a GRState object that contains the same bindings as + /// \c state with the addition of having the value specified by \c val bound + /// to the location given for \c loc. + virtual const GRState* Bind(const GRState* state, Loc loc, SVal val) = 0; + + virtual Store Remove(Store St, Loc L) = 0; + + /// BindCompoundLiteral - Return the store that has the bindings currently + /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + virtual const GRState* BindCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL, + SVal V) = 0; + + /// getInitialStore - Returns the initial "empty" store representing the + /// value bindings upon entry to an analyzed function. + virtual Store getInitialStore() = 0; + + /// getRegionManager - Returns the internal RegionManager object that is + /// used to query and manipulate MemRegion objects. + MemRegionManager& getRegionManager() { return MRMgr; } + + /// getSubRegionMap - Returns an opaque map object that clients can query + /// to get the subregions of a given MemRegion object. It is the + // caller's responsibility to 'delete' the returned map. + virtual SubRegionMap* getSubRegionMap(const GRState *state) = 0; + + virtual SVal getLValueVar(const GRState* St, const VarDecl* VD) = 0; + + virtual SVal getLValueString(const GRState* St, const StringLiteral* S) = 0; + + virtual SVal getLValueCompoundLiteral(const GRState* St, + const CompoundLiteralExpr* CL) = 0; + + virtual SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, + SVal Base) = 0; + + virtual SVal getLValueField(const GRState* St, SVal Base, + const FieldDecl* D) = 0; + + virtual SVal getLValueElement(const GRState* St, QualType elementType, + SVal Base, SVal Offset) = 0; + + virtual SVal getSizeInElements(const GRState* St, const MemRegion* R) { + return UnknownVal(); + } + + /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit + /// conversions between arrays and pointers. + virtual SVal ArrayToPointer(Loc Array) = 0; + + + class CastResult { + const GRState* State; + const MemRegion* R; + public: + const GRState* getState() const { return State; } + const MemRegion* getRegion() const { return R; } + CastResult(const GRState* s, const MemRegion* r = 0) : State(s), R(r) {} + }; + + /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from + /// a MemRegion* to a specific location type. 'R' is the region being + /// casted and 'CastToTy' the result type of the cast. + virtual CastResult CastRegion(const GRState* state, const MemRegion* R, + QualType CastToTy); + + /// EvalBinOp - Perform pointer arithmetic. + virtual SVal EvalBinOp(const GRState *state, + BinaryOperator::Opcode Op, Loc L, NonLoc R) { + return UnknownVal(); + } + + /// getSelfRegion - Returns the region for the 'self' (Objective-C) or + /// 'this' object (C++). When used when analyzing a normal function this + /// method returns NULL. + virtual const MemRegion* getSelfRegion(Store store) = 0; + + virtual Store + RemoveDeadBindings(const GRState* state, Stmt* Loc, SymbolReaper& SymReaper, + llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; + + virtual const GRState* BindDecl(const GRState* St, const VarDecl* VD, + SVal InitVal) = 0; + + virtual const GRState* BindDeclWithNoInit(const GRState* St, + const VarDecl* VD) = 0; + + virtual const GRState* setExtent(const GRState* St, + const MemRegion* R, SVal Extent) { + return St; + } + + virtual const GRState* setDefaultValue(const GRState* St, + const MemRegion* R, SVal V) { + return St; + } + + virtual void print(Store store, std::ostream& Out, + const char* nl, const char *sep) = 0; + + class BindingsHandler { + public: + virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, + const MemRegion* R, SVal val) = 0; + }; + + /// iterBindings - Iterate over the bindings in the Store. + virtual void iterBindings(Store store, BindingsHandler& f) = 0; +}; + +/// SubRegionMap - An abstract interface that represents a queryable map +/// between MemRegion objects and their subregions. +class SubRegionMap { +public: + virtual ~SubRegionMap() {} + + class Visitor { + public: + virtual ~Visitor() {}; + virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; + }; + + virtual bool iterSubRegions(const MemRegion* R, Visitor& V) const = 0; +}; + +StoreManager* CreateBasicStoreManager(GRStateManager& StMgr); +StoreManager* CreateRegionStoreManager(GRStateManager& StMgr); + +} // end clang namespace + +#endif diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h new file mode 100644 index 000000000000..d424526d4eb0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -0,0 +1,329 @@ +//== SymbolManager.h - Management of Symbolic 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 SymbolManager, a class that manages symbolic values +// created for use by GRExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H +#define LLVM_CLANG_ANALYSIS_SYMMGR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class MemRegion; + class ASTContext; + class BasicValueFactory; +} + +namespace clang { + +class SymExpr : public llvm::FoldingSetNode { +public: + enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS, + SymIntKind, SymSymKind }; +private: + Kind K; + +protected: + SymExpr(Kind k) : K(k) {} + +public: + virtual ~SymExpr() {} + + Kind getKind() const { return K; } + + virtual QualType getType(ASTContext&) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; + + // Implement isa<T> support. + static inline bool classof(const SymExpr*) { return true; } +}; + +typedef unsigned SymbolID; + +class SymbolData : public SymExpr { +private: + const SymbolID Sym; + +protected: + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + +public: + virtual ~SymbolData() {} + + SymbolID getSymbolID() const { return Sym; } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + Kind k = SE->getKind(); + return k > BEGIN_SYMBOLS && k < END_SYMBOLS; + } +}; + +typedef const SymbolData* SymbolRef; + +class SymbolRegionValue : public SymbolData { + const MemRegion *R; +public: + SymbolRegionValue(SymbolID sym, const MemRegion *r) + : SymbolData(RegionValueKind, sym), R(r) {} + + const MemRegion* getRegion() const { return R; } + + static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R) { + profile.AddInteger((unsigned) RegionValueKind); + profile.AddPointer(R); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R); + } + + QualType getType(ASTContext&) const; + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == RegionValueKind; + } +}; + +class SymbolConjured : public SymbolData { + const Stmt* S; + QualType T; + unsigned Count; + const void* SymbolTag; + +public: + SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count, + const void* symbolTag) + : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), + SymbolTag(symbolTag) {} + + const Stmt* getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void* getTag() const { return SymbolTag; } + + QualType getType(ASTContext&) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, + QualType T, unsigned Count, const void* SymbolTag) { + profile.AddInteger((unsigned) ConjuredKind); + profile.AddPointer(S); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(SymbolTag); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, S, T, Count, SymbolTag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == ConjuredKind; + } +}; + +// SymIntExpr - Represents symbolic expression like 'x' + 3. +class SymIntExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const llvm::APSInt& RHS; + QualType T; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + const SymExpr *getLHS() const { return LHS; } + const llvm::APSInt &getRHS() const { return RHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const llvm::APSInt& rhs, + QualType t) { + ID.AddInteger((unsigned) SymIntKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(&rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymIntKind; + } +}; + +// SymSymExpr - Represents symbolic expression like 'x' + 'y'. +class SymSymExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const SymExpr *RHS; + QualType T; + +public: + SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) + : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + const SymExpr *getLHS() const { return LHS; } + const SymExpr *getRHS() const { return RHS; } + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { + ID.AddInteger((unsigned) SymSymKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymSymKind; + } +}; + +class SymbolManager { + typedef llvm::FoldingSet<SymExpr> DataSetTy; + DataSetTy DataSet; + unsigned SymbolCounter; + llvm::BumpPtrAllocator& BPAlloc; + BasicValueFactory &BV; + ASTContext& Ctx; + +public: + SymbolManager(ASTContext& ctx, BasicValueFactory &bv, + llvm::BumpPtrAllocator& bpalloc) + : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} + + ~SymbolManager(); + + static bool canSymbolicate(QualType T); + + /// Make a unique symbol for MemRegion R according to its kind. + const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R); + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0); + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); + } + + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t); + + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) { + return getSymIntExpr(&lhs, op, rhs, t); + } + + const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + QualType getType(const SymExpr *SE) const { + return SE->getType(Ctx); + } + + ASTContext &getContext() { return Ctx; } + BasicValueFactory &getBasicVals() { return BV; } +}; + +class SymbolReaper { + typedef llvm::ImmutableSet<SymbolRef> SetTy; + typedef SetTy::Factory FactoryTy; + + FactoryTy F; + SetTy TheLiving; + SetTy TheDead; + LiveVariables& Liveness; + SymbolManager& SymMgr; + +public: + SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr) + : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()), + Liveness(liveness), SymMgr(symmgr) {} + + bool isLive(SymbolRef sym); + + bool isLive(const Stmt* Loc, const Stmt* ExprVal) const { + return Liveness.isLive(Loc, ExprVal); + } + + bool isLive(const Stmt* Loc, const VarDecl* VD) const { + return Liveness.isLive(Loc, VD); + } + + void markLive(SymbolRef sym); + bool maybeDead(SymbolRef sym); + + typedef SetTy::iterator dead_iterator; + dead_iterator dead_begin() const { return TheDead.begin(); } + dead_iterator dead_end() const { return TheDead.end(); } + + bool hasDeadSymbols() const { + return !TheDead.isEmpty(); + } +}; + +class SymbolVisitor { +public: + // VisitSymbol - A visitor method invoked by + // GRStateManager::scanReachableSymbols. The method returns \c true if + // symbols should continue be scanned and \c false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual ~SymbolVisitor(); +}; + +} // end clang namespace + +namespace llvm { + llvm::raw_ostream& operator<<(llvm::raw_ostream& Out, + const clang::SymExpr *SE); +} +namespace std { + std::ostream& operator<<(std::ostream& Out, + const clang::SymExpr *SE); +} + +#endif diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h new file mode 100644 index 000000000000..89af975de7af --- /dev/null +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -0,0 +1,103 @@ +//== ValueManager.h - Aggregate manager of symbols and SVals ----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ValueManager, a class that manages symbolic values +// and SVals created for use by GRExprEngine and related classes. It +// wraps SymbolManager, MemRegionManager, and BasicValueFactory. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H + +#include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Analysis/PathSensitive/SVals.h" +#include "clang/Analysis/PathSensitive/BasicValueFactory.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" + +namespace llvm { class BumpPtrAllocator; } + +namespace clang { +class ValueManager { + + ASTContext &Context; + BasicValueFactory BasicVals; + + /// SymMgr - Object that manages the symbol information. + SymbolManager SymMgr; + + + MemRegionManager MemMgr; + +public: + ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context) + : Context(context), BasicVals(Context, alloc), + SymMgr(Context, BasicVals, alloc), + MemMgr(alloc) {} + + // Accessors to submanagers. + + ASTContext &getContext() { return Context; } + const ASTContext &getContext() const { return Context; } + + BasicValueFactory &getBasicValueFactory() { return BasicVals; } + const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } + + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } + + MemRegionManager &getRegionManager() { return MemMgr; } + const MemRegionManager &getRegionManager() const { return MemMgr; } + + // Forwarding methods to SymbolManager. + + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); + } + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); + } + + // Aggregation methods that use multiple submanagers. + + Loc makeRegionVal(SymbolRef Sym) { + return Loc::MakeVal(MemMgr.getSymbolicRegion(Sym)); + } + + /// makeZeroVal - Construct an SVal representing '0' for the specified type. + SVal makeZeroVal(QualType T); + /// makeZeroArrayIndex - Construct an SVal representing '0' index for array + /// elements. + SVal makeZeroArrayIndex(); + + /// GetRegionValueSymbolVal - make a unique symbol for value of R. + SVal getRegionValueSymbolVal(const MemRegion* R); + + SVal getConjuredSymbolVal(const Expr *E, unsigned Count); + SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count); + + SVal getFunctionPointer(const FunctionDecl* FD); + + NonLoc makeNonLoc(SymbolRef sym); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType T); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType T); + + NonLoc makeTruthVal(bool b, QualType T); +}; +} // end clang namespace +#endif + diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h new file mode 100644 index 000000000000..d2b536ca1cb2 --- /dev/null +++ b/include/clang/Analysis/ProgramPoint.h @@ -0,0 +1,351 @@ +//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT +#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT + +#include "clang/AST/CFG.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <utility> + +namespace clang { + +class ProgramPoint { +public: + enum Kind { BlockEdgeKind = 0x0, + BlockEntranceKind = 0x1, + BlockExitKind = 0x2, + // Keep the following four together and in this order. + PostStmtKind = 0x3, + PostLocationChecksSucceedKind = 0x4, + PostOutOfBoundsCheckFailedKind = 0x5, + PostNullCheckFailedKind = 0x6, + PostUndefLocationCheckFailedKind = 0x7, + PostLoadKind = 0x8, + PostStoreKind = 0x9, + PostPurgeDeadSymbolsKind = 0x10, + PostStmtCustomKind = 0x11, + PostLValueKind = 0x12, + MinPostStmtKind = PostStmtKind, + MaxPostStmtKind = PostLValueKind }; + +private: + enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 }; + + std::pair<uintptr_t,uintptr_t> Data; + const void *Tag; + +protected: + ProgramPoint(const void* P, Kind k, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P), + (uintptr_t) k), Tag(tag) {} + + ProgramPoint(const void* P1, const void* P2, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P1) | TwoPointers, + reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} + + ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0) + : Data(reinterpret_cast<uintptr_t>(P1) | Custom, + reinterpret_cast<uintptr_t>(P2)), Tag(tag) {} + +protected: + void* getData1NoMask() const { + Kind k = getKind(); k = k; + assert(k == BlockEntranceKind || k == BlockExitKind); + return reinterpret_cast<void*>(Data.first); + } + + void* getData1() const { + Kind k = getKind(); k = k; + assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind)); + return reinterpret_cast<void*>(Data.first & ~Mask); + } + + void* getData2() const { + Kind k = getKind(); k = k; + assert(k == BlockEdgeKind || k == PostStmtCustomKind); + return reinterpret_cast<void*>(Data.second); + } + + const void *getTag() const { return Tag; } + +public: + Kind getKind() const { + switch (Data.first & Mask) { + case TwoPointers: return BlockEdgeKind; + case Custom: return PostStmtCustomKind; + default: return (Kind) Data.second; + } + } + + // For use with DenseMap. This hash is probably slow. + unsigned getHashValue() const { + llvm::FoldingSetNodeID ID; + ID.AddPointer(reinterpret_cast<void*>(Data.first)); + ID.AddPointer(reinterpret_cast<void*>(Data.second)); + ID.AddPointer(Tag); + return ID.ComputeHash(); + } + + static bool classof(const ProgramPoint*) { return true; } + + bool operator==(const ProgramPoint & RHS) const { + return Data == RHS.Data && Tag == RHS.Tag; + } + + bool operator!=(const ProgramPoint& RHS) const { + return Data != RHS.Data || Tag != RHS.Tag; + } + + bool operator<(const ProgramPoint& RHS) const { + return Data < RHS.Data && Tag < RHS.Tag; + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddPointer(reinterpret_cast<void*>(Data.first)); + if (getKind() != PostStmtCustomKind) + ID.AddPointer(reinterpret_cast<void*>(Data.second)); + else { + const std::pair<const void*, const void*> *P = + reinterpret_cast<std::pair<const void*, const void*>*>(Data.second); + ID.AddPointer(P->first); + ID.AddPointer(P->second); + } + ID.AddPointer(Tag); + } +}; + +class BlockEntrance : public ProgramPoint { +public: + BlockEntrance(const CFGBlock* B, const void *tag = 0) + : ProgramPoint(B, BlockEntranceKind, tag) {} + + CFGBlock* getBlock() const { + return reinterpret_cast<CFGBlock*>(getData1NoMask()); + } + + Stmt* getFirstStmt() const { + CFGBlock* B = getBlock(); + return B->empty() ? NULL : B->front(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEntranceKind; + } +}; + +class BlockExit : public ProgramPoint { +public: + BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {} + + CFGBlock* getBlock() const { + return reinterpret_cast<CFGBlock*>(getData1NoMask()); + } + + Stmt* getLastStmt() const { + CFGBlock* B = getBlock(); + return B->empty() ? NULL : B->back(); + } + + Stmt* getTerminator() const { + return getBlock()->getTerminator(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockExitKind; + } +}; + +class PostStmt : public ProgramPoint { +protected: + PostStmt(const Stmt* S, Kind k,const void *tag = 0) + : ProgramPoint(S, k, tag) {} + + PostStmt(const Stmt* S, const void* data, bool, const void *tag =0) + : ProgramPoint(S, data, true, tag) {} + +public: + PostStmt(const Stmt* S, const void *tag = 0) + : ProgramPoint(S, PostStmtKind, tag) {} + + Stmt* getStmt() const { return (Stmt*) getData1(); } + + template<typename T> + T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= MinPostStmtKind && k <= MaxPostStmtKind; + } +}; + +class PostLocationChecksSucceed : public PostStmt { +public: + PostLocationChecksSucceed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLocationChecksSucceedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLocationChecksSucceedKind; + } +}; + +class PostStmtCustom : public PostStmt { +public: + PostStmtCustom(const Stmt* S, + const std::pair<const void*, const void*>* TaggedData) + : PostStmt(S, TaggedData, true) { + assert(getKind() == PostStmtCustomKind); + } + + const std::pair<const void*, const void*>& getTaggedPair() const { + return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2()); + } + + const void* getTag() const { return getTaggedPair().first; } + + const void* getTaggedData() const { return getTaggedPair().second; } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStmtCustomKind; + } +}; + +class PostOutOfBoundsCheckFailed : public PostStmt { +public: + PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostOutOfBoundsCheckFailedKind; + } +}; + +class PostUndefLocationCheckFailed : public PostStmt { +public: + PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostUndefLocationCheckFailedKind; + } +}; + +class PostNullCheckFailed : public PostStmt { +public: + PostNullCheckFailed(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostNullCheckFailedKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostNullCheckFailedKind; + } +}; + +class PostLoad : public PostStmt { +public: + PostLoad(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLoadKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLoadKind; + } +}; + +class PostStore : public PostStmt { +public: + PostStore(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostStoreKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStoreKind; + } +}; + +class PostLValue : public PostStmt { +public: + PostLValue(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostLValueKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLValueKind; + } +}; + +class PostPurgeDeadSymbols : public PostStmt { +public: + PostPurgeDeadSymbols(const Stmt* S, const void *tag = 0) + : PostStmt(S, PostPurgeDeadSymbolsKind, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostPurgeDeadSymbolsKind; + } +}; + +class BlockEdge : public ProgramPoint { +public: + BlockEdge(const CFGBlock* B1, const CFGBlock* B2) + : ProgramPoint(B1, B2) {} + + CFGBlock* getSrc() const { + return static_cast<CFGBlock*>(getData1()); + } + + CFGBlock* getDst() const { + return static_cast<CFGBlock*>(getData2()); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEdgeKind; + } +}; + + +} // end namespace clang + + +namespace llvm { // Traits specialization for DenseMap + +template <> struct DenseMapInfo<clang::ProgramPoint> { + +static inline clang::ProgramPoint getEmptyKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); +} + +static inline clang::ProgramPoint getTombstoneKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x)); +} + +static unsigned getHashValue(const clang::ProgramPoint& Loc) { + return Loc.getHashValue(); +} + +static bool isEqual(const clang::ProgramPoint& L, + const clang::ProgramPoint& R) { + return L == R; +} + +static bool isPod() { + return true; +} +}; +} // end namespace llvm + +#endif diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h new file mode 100644 index 000000000000..a592be815419 --- /dev/null +++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -0,0 +1,307 @@ +// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*-- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definition of dataflow types used by analyses such +// as LiveVariables and UninitializedValues. The underlying dataflow values +// are implemented as bitvectors, but the definitions in this file include +// the necessary boilerplate to use with our dataflow framework. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STMTDECLBVDVAL_H +#define LLVM_CLANG_STMTDECLBVDVAL_H + +#include "clang/AST/CFG.h" +#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + + class Stmt; + class ASTContext; + +struct DeclBitVector_Types { + + class Idx { + unsigned I; + public: + explicit Idx(unsigned i) : I(i) {} + Idx() : I(~0U) {} + + bool isValid() const { + return I != ~0U; + } + operator unsigned() const { + assert (isValid()); + return I; + } + }; + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy { + public: + typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy; + typedef DMapTy::const_iterator decl_iterator; + + protected: + DMapTy DMap; + unsigned NDecls; + + public: + + AnalysisDataTy() : NDecls(0) {} + virtual ~AnalysisDataTy() {} + + bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); } + + Idx getIdx(const NamedDecl* SD) const { + DMapTy::const_iterator I = DMap.find(SD); + return I == DMap.end() ? Idx() : Idx(I->second); + } + + unsigned getNumDecls() const { return NDecls; } + + void Register(const NamedDecl* SD) { + if (!isTracked(SD)) DMap[SD] = NDecls++; + } + + decl_iterator begin_decl() const { return DMap.begin(); } + decl_iterator end_decl() const { return DMap.end(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy { + llvm::BitVector DeclBV; + public: + + void resetDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.reset(); + } + + void setDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + } + + bool operator==(const ValTy& RHS) const { + assert (sizesEqual(RHS)); + return DeclBV == RHS.DeclBV; + } + + void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; } + + llvm::BitVector::reference getBit(unsigned i) { + return DeclBV[i]; + } + + bool getBit(unsigned i) const { + return DeclBV[i]; + } + + llvm::BitVector::reference + operator()(const NamedDecl* ND, const AnalysisDataTy& AD) { + return getBit(AD.getIdx(ND)); + } + + bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const { + return getBit(AD.getIdx(ND)); + } + + llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } + const llvm::BitVector::reference getDeclBit(unsigned i) const { + return const_cast<llvm::BitVector&>(DeclBV)[i]; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV |= RHS.DeclBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV &= RHS.DeclBV; + return *this; + } + + ValTy& OrDeclBits(const ValTy& RHS) { + return operator|=(RHS); + } + + ValTy& AndDeclBits(const ValTy& RHS) { + return operator&=(RHS); + } + + bool sizesEqual(const ValTy& RHS) const { + return DeclBV.size() == RHS.DeclBV.size(); + } + }; + + //===--------------------------------------------------------------------===// + // Some useful merge operations. + //===--------------------------------------------------------------------===// + + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; + struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; +}; + + +struct StmtDeclBitVector_Types { + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy { + ASTContext* ctx; + CFG* cfg; + public: + AnalysisDataTy() : ctx(0), cfg(0) {} + virtual ~AnalysisDataTy() {} + + void setContext(ASTContext& c) { ctx = &c; } + ASTContext& getContext() { + assert(ctx && "ASTContext should not be NULL."); + return *ctx; + } + + void setCFG(CFG& c) { cfg = &c; } + CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } + + bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); } + using DeclBitVector_Types::AnalysisDataTy::isTracked; + + unsigned getIdx(const Stmt* S) const { + CFG::BlkExprNumTy I = cfg->getBlkExprNum(S); + assert(I && "Stmtession not tracked for bitvector."); + return I; + } + using DeclBitVector_Types::AnalysisDataTy::getIdx; + + unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy : public DeclBitVector_Types::ValTy { + llvm::BitVector BlkExprBV; + typedef DeclBitVector_Types::ValTy ParentTy; + + static inline ParentTy& ParentRef(ValTy& X) { + return static_cast<ParentTy&>(X); + } + + static inline const ParentTy& ParentRef(const ValTy& X) { + return static_cast<const ParentTy&>(X); + } + + public: + + void resetBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.reset(); + } + + void setBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + resetBlkExprValues(AD); + } + + void setValues(AnalysisDataTy& AD) { + setDeclValues(AD); + setBlkExprValues(AD); + } + + bool operator==(const ValTy& RHS) const { + return ParentRef(*this) == ParentRef(RHS) + && BlkExprBV == RHS.BlkExprBV; + } + + void copyValues(const ValTy& RHS) { + ParentRef(*this).copyValues(ParentRef(RHS)); + BlkExprBV = RHS.BlkExprBV; + } + + llvm::BitVector::reference + operator()(const Stmt* S, const AnalysisDataTy& AD) { + return BlkExprBV[AD.getIdx(S)]; + } + const llvm::BitVector::reference + operator()(const Stmt* S, const AnalysisDataTy& AD) const { + return const_cast<ValTy&>(*this)(S,AD); + } + + using DeclBitVector_Types::ValTy::operator(); + + + llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } + const llvm::BitVector::reference getStmtBit(unsigned i) const { + return const_cast<llvm::BitVector&>(BlkExprBV)[i]; + } + + ValTy& OrBlkExprBits(const ValTy& RHS) { + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& AndBlkExprBits(const ValTy& RHS) { + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) |= ParentRef(RHS); + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) &= ParentRef(RHS); + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + bool sizesEqual(const ValTy& RHS) const { + return ParentRef(*this).sizesEqual(ParentRef(RHS)) + && BlkExprBV.size() == RHS.BlkExprBV.size(); + } + }; + + //===--------------------------------------------------------------------===// + // Some useful merge operations. + //===--------------------------------------------------------------------===// + + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; + struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; + +}; +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h new file mode 100644 index 000000000000..ee79c517030f --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -0,0 +1,91 @@ +//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- C++ --*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the template class CFGRecStmtDeclVisitor, which extends +// CFGRecStmtVisitor by implementing (typed) visitation of decls. +// +// FIXME: This may not be fully complete. We currently explore only subtypes +// of ScopedDecl. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H + +#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" + +#define DISPATCH_CASE(CASE,CLASS) \ +case Decl::CASE: \ +static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\ +break; + +#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {} +#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\ + { static_cast<ImplClass*>(this)->VisitVarDecl(D); } + + +namespace clang { +template <typename ImplClass> +class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { +public: + + void VisitDeclRefExpr(DeclRefExpr* DR) { + static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); + } + + void VisitDeclStmt(DeclStmt* DS) { + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl* D = *DI; + static_cast<ImplClass*>(this)->VisitDecl(D); + // Visit the initializer. + if (VarDecl* VD = dyn_cast<VarDecl>(D)) + if (Expr* I = VD->getInit()) + static_cast<ImplClass*>(this)->Visit(I); + } + } + + void VisitDecl(Decl* D) { + switch (D->getKind()) { + DISPATCH_CASE(Function,FunctionDecl) + DISPATCH_CASE(Var,VarDecl) + DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same) + DISPATCH_CASE(OriginalParmVar,OriginalParmVarDecl) // FIXME: (same) + DISPATCH_CASE(ImplicitParam,ImplicitParamDecl) + DISPATCH_CASE(EnumConstant,EnumConstantDecl) + DISPATCH_CASE(Typedef,TypedefDecl) + DISPATCH_CASE(Record,RecordDecl) // FIXME: Refine. VisitStructDecl? + DISPATCH_CASE(Enum,EnumDecl) + default: + assert(false && "Subtype of ScopedDecl not handled."); + } + } + + DEFAULT_DISPATCH(VarDecl) + DEFAULT_DISPATCH(FunctionDecl) + DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl) + DEFAULT_DISPATCH_VARDECL(ParmVarDecl) + DEFAULT_DISPATCH(ImplicitParamDecl) + DEFAULT_DISPATCH(EnumConstantDecl) + DEFAULT_DISPATCH(TypedefDecl) + DEFAULT_DISPATCH(RecordDecl) + DEFAULT_DISPATCH(EnumDecl) + DEFAULT_DISPATCH(ObjCInterfaceDecl) + DEFAULT_DISPATCH(ObjCClassDecl) + DEFAULT_DISPATCH(ObjCMethodDecl) + DEFAULT_DISPATCH(ObjCProtocolDecl) + DEFAULT_DISPATCH(ObjCCategoryDecl) +}; + +} // end namespace clang + +#undef DISPATCH_CASE +#undef DEFAULT_DISPATCH +#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h new file mode 100644 index 000000000000..4d3201962250 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -0,0 +1,35 @@ +//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the template class CFGRecStmtVisitor, which extends +// CFGStmtVisitor by implementing a default recursive visit of all statements. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H + +#include "clang/Analysis/Visitors/CFGStmtVisitor.h" + +namespace clang { +template <typename ImplClass> +class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { +public: + + void VisitStmt(Stmt* S) { + static_cast< ImplClass* >(this)->VisitChildren(S); + } + + // Defining operator() allows the visitor to be used as a C++ style functor. + void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h new file mode 100644 index 000000000000..f42bbde8f148 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -0,0 +1,156 @@ +//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- 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 CFGStmtVisitor interface, which extends +// StmtVisitor. This interface is useful for visiting statements in a CFG +// where some statements have implicit control-flow and thus should +// be treated specially. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H +#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/CFG.h" + +namespace clang { + +#define DISPATCH_CASE(CLASS) \ +case Stmt::CLASS ## Class: return \ +static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); + +#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ +{ return\ + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\ + cast<Expr>(S)); } + +template <typename ImplClass, typename RetTy=void> +class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { + Stmt* CurrentBlkStmt; + + struct NullifyStmt { + Stmt*& S; + + NullifyStmt(Stmt*& s) : S(s) {} + ~NullifyStmt() { S = NULL; } + }; + +public: + CFGStmtVisitor() : CurrentBlkStmt(NULL) {} + + Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; } + + RetTy Visit(Stmt* S) { + if (S == CurrentBlkStmt || + !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) + return StmtVisitor<ImplClass,RetTy>::Visit(S); + else + return RetTy(); + } + + /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in + /// CFGBlocks. Root statements are the statements that appear explicitly in + /// the list of statements in a CFGBlock. For substatements, or when there + /// is no implementation provided for a BlockStmt_XXX method, we default + /// to using StmtVisitor's Visit method. + RetTy BlockStmt_Visit(Stmt* S) { + CurrentBlkStmt = S; + NullifyStmt cleanup(CurrentBlkStmt); + + switch (S->getStmtClass()) { + + DISPATCH_CASE(StmtExpr) + DISPATCH_CASE(ConditionalOperator) + DISPATCH_CASE(ObjCForCollectionStmt) + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->isLogicalOp()) + return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B); + else if (B->getOpcode() == BinaryOperator::Comma) + return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); + // Fall through. + } + + default: + if (isa<Expr>(S)) + return + static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); + else + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + } + + DEFAULT_BLOCKSTMT_VISIT(StmtExpr) + DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) + + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); + } + + RetTy BlockStmt_VisitExpr(Expr* E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); + } + + RetTy BlockStmt_VisitStmt(Stmt* S) { + return static_cast<ImplClass*>(this)->Visit(S); + } + + RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + RetTy BlockStmt_VisitComma(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + //===--------------------------------------------------------------------===// + // Utility methods. Not called by default (but subclasses may use them). + //===--------------------------------------------------------------------===// + + /// VisitChildren: Call "Visit" on each child of S. + void VisitChildren(Stmt* S) { + + switch (S->getStmtClass()) { + default: + break; + + case Stmt::StmtExprClass: { + CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt(); + if (CS->body_empty()) return; + static_cast<ImplClass*>(this)->Visit(CS->body_back()); + return; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->getOpcode() != BinaryOperator::Comma) break; + static_cast<ImplClass*>(this)->Visit(B->getRHS()); + return; + } + } + + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + if (*I) static_cast<ImplClass*>(this)->Visit(*I); + } +}; + +#undef DEFAULT_BLOCKSTMT_VISIT +#undef DISPATCH_CASE + +} // end namespace clang + +#endif diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h new file mode 100644 index 000000000000..25101235ddd2 --- /dev/null +++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h @@ -0,0 +1,64 @@ +//==- CFGVarDeclVisitor - Generic visitor of VarDecls in a CFG --*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the template class CFGVarDeclVisitor, which provides +// a generic way to visit all the VarDecl's in a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H + +#include "clang/Analysis/Visitors/CFGStmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/CFG.h" + +namespace clang { + +template <typename ImplClass> +class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> { + const CFG& cfg; +public: + CFGVarDeclVisitor(const CFG& c) : cfg(c) {} + + void VisitStmt(Stmt* S) { + static_cast<ImplClass*>(this)->VisitChildren(S); + } + + void VisitDeclRefExpr(DeclRefExpr* DR) { + static_cast<ImplClass*>(this)->VisitDeclChain(DR->getDecl()); + } + + void VisitDeclStmt(DeclStmt* DS) { + static_cast<ImplClass*>(this)->VisitDeclChain(DS->getDecl()); + } + + void VisitDeclChain(ScopedDecl* D) { + for (; D != NULL ; D = D->getNextDeclarator()) + static_cast<ImplClass*>(this)->VisitScopedDecl(D); + } + + void VisitScopedDecl(ScopedDecl* D) { + if (VarDecl* V = dyn_cast<VarDecl>(D)) + static_cast<ImplClass*>(this)->VisitVarDecl(V); + } + + void VisitVarDecl(VarDecl* D) {} + + void VisitAllDecls() { + for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) + for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI) + static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI)); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt new file mode 100644 index 000000000000..9e643bb3c2c1 --- /dev/null +++ b/include/clang/Basic/CMakeLists.txt @@ -0,0 +1,20 @@ +macro(clang_diag_gen component) + tablegen(Diagnostic${component}Kinds.inc + -gen-clang-diags-defs -clang-component=${component}) + add_custom_target(ClangDiagnostic${component} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Diagnostic${component}Kinds.inc) +endmacro(clang_diag_gen) + +set(LLVM_TARGET_DEFINITIONS Diagnostic.td) +clang_diag_gen(Analysis) +clang_diag_gen(AST) +clang_diag_gen(Common) +clang_diag_gen(Driver) +clang_diag_gen(Frontend) +clang_diag_gen(Lex) +clang_diag_gen(Parse) +clang_diag_gen(Sema) +tablegen(DiagnosticGroups.inc + -gen-clang-diag-groups) +add_custom_target(ClangDiagnosticGroups + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/DiagnosticGroups.inc) diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h new file mode 100644 index 000000000000..73e2fcd12fee --- /dev/null +++ b/include/clang/Basic/ConvertUTF.h @@ -0,0 +1,159 @@ +/*===--- ConvertUTF.h - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *==------------------------------------------------------------------------==*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, + or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +#ifdef CLANG_NEEDS_THESE_ONE_DAY +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); +#endif + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h new file mode 100644 index 000000000000..22e7fb3f85ea --- /dev/null +++ b/include/clang/Basic/Diagnostic.h @@ -0,0 +1,697 @@ +//===--- Diagnostic.h - C Language Family Diagnostic 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-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTIC_H +#define LLVM_CLANG_DIAGNOSTIC_H + +#include "clang/Basic/SourceLocation.h" +#include <string> +#include <cassert> + +namespace llvm { + template <typename T> class SmallVectorImpl; +} + +namespace clang { + class DiagnosticClient; + class SourceRange; + class DiagnosticBuilder; + class IdentifierInfo; + class LangOptions; + + // 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 + 1000, + 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) 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 + }; + } + +/// \brief Annotates a diagnostic with some code that should be +/// inserted, removed, or replaced to fix the problem. +/// +/// This kind of hint should be used when we are certain that the +/// introduction, removal, or modification of a particular (small!) +/// amount of code will correct a compilation error. The compiler +/// should also provide full recovery from such errors, such that +/// suppressing the diagnostic output can still result in successful +/// compilation. +class CodeModificationHint { +public: + /// \brief Tokens that should be removed to correct the error. + SourceRange RemoveRange; + + /// \brief The location at which we should insert code to correct + /// the error. + SourceLocation InsertionLoc; + + /// \brief The actual code to insert at the insertion location, as a + /// string. + std::string CodeToInsert; + + /// \brief Empty code modification hint, indicating that no code + /// modification is known. + CodeModificationHint() : RemoveRange(), InsertionLoc() { } + + /// \brief Create a code modification hint that inserts the given + /// code string at a specific location. + static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc, + const std::string &Code) { + CodeModificationHint Hint; + Hint.InsertionLoc = InsertionLoc; + Hint.CodeToInsert = Code; + return Hint; + } + + /// \brief Create a code modification hint that removes the given + /// source range. + static CodeModificationHint CreateRemoval(SourceRange RemoveRange) { + CodeModificationHint Hint; + Hint.RemoveRange = RemoveRange; + return Hint; + } + + /// \brief Create a code modification hint that replaces the given + /// source range with the given code string. + static CodeModificationHint CreateReplacement(SourceRange RemoveRange, + const std::string &Code) { + CodeModificationHint Hint; + Hint.RemoveRange = RemoveRange; + Hint.InsertionLoc = RemoveRange.getBegin(); + Hint.CodeToInsert = Code; + return Hint; + } +}; + +/// 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. +class Diagnostic { +public: + /// Level - The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored, Note, Warning, Error, Fatal + }; + + /// ExtensionHandling - How do we handle otherwise-unmapped extension? This + /// is controlled by -pedantic and -pedantic-errors. + enum ExtensionHandling { + Ext_Ignore, Ext_Warn, Ext_Error + }; + + enum ArgumentKind { + ak_std_string, // std::string + ak_c_string, // const char * + ak_sint, // int + ak_uint, // unsigned + ak_identifierinfo, // IdentifierInfo + ak_qualtype, // QualType + ak_declarationname, // DeclarationName + ak_nameddecl // NamedDecl * + }; + +private: + unsigned char AllExtensionsSilenced; // Used by __extension__ + bool IgnoreAllWarnings; // Ignore all warnings: -w + bool WarningsAsErrors; // Treat warnings like errors: + bool SuppressSystemWarnings; // Suppress warnings in system headers. + ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? + DiagnosticClient *Client; + + /// DiagMappings - 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. + mutable unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2]; + + /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or + /// fatal error is emitted, and is sticky. + bool ErrorOccurred; + bool FatalErrorOccurred; + + /// LastDiagLevel - This is the level of the last diagnostic emitted. This is + /// used to emit continuation diagnostics with the same level as the + /// diagnostic that they follow. + Diagnostic::Level LastDiagLevel; + + unsigned NumDiagnostics; // Number of diagnostics reported + unsigned NumErrors; // Number of diagnostics that are errors + + /// 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 + /// present in the diagnostic. + /// This is a hack to avoid a layering violation between libbasic and libsema. + typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModifierLen, + const char *Argument, unsigned ArgumentLen, + llvm::SmallVectorImpl<char> &Output, + void *Cookie); + void *ArgToStringCookie; + ArgToStringFnTy ArgToStringFn; +public: + explicit Diagnostic(DiagnosticClient *client = 0); + ~Diagnostic(); + + //===--------------------------------------------------------------------===// + // Diagnostic characterization methods, used by a client to customize how + // + + DiagnosticClient *getClient() { return Client; }; + const DiagnosticClient *getClient() const { return Client; }; + + void setClient(DiagnosticClient* client) { Client = client; } + + /// setIgnoreAllWarnings - When set to true, any unmapped warnings are + /// ignored. If this and WarningsAsErrors are both set, then this one wins. + void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } + bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } + + /// setWarningsAsErrors - When set to true, any warnings reported are issued + /// as errors. + void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } + bool getWarningsAsErrors() const { return WarningsAsErrors; } + + /// setSuppressSystemWarnings - When set to true mask warnings that + /// come from system headers. + void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } + bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + + /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped + /// extension diagnostics are mapped onto ignore/warning/error. This + /// corresponds to the GCC -pedantic and -pedantic-errors option. + void setExtensionHandlingBehavior(ExtensionHandling H) { + ExtBehavior = H; + } + + /// AllExtensionsSilenced - This is a counter bumped when an __extension__ + /// block is encountered. When non-zero, all extension diagnostics are + /// entirely silenced, no matter how they are mapped. + void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } + void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } + + /// setDiagnosticMapping - This allows the client to specify that certain + /// warnings are ignored. Notes can never be mapped, errors can only be + /// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily. + 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) && + "Cannot map errors!"); + setDiagnosticMappingInternal(Diag, Map, true); + } + + /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. + /// "unknown-pragmas" to have the specified mapping. This returns true and + /// ignores the request if "Group" was unknown, false otherwise. + bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map); + + bool hasErrorOccurred() const { return ErrorOccurred; } + bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } + + unsigned getNumErrors() const { return NumErrors; } + unsigned getNumDiagnostics() const { return NumDiagnostics; } + + /// getCustomDiagID - Return an ID for a diagnostic with the specified message + /// and level. If this is the first request for this diagnosic, it is + /// registered and created, otherwise the existing ID is returned. + unsigned getCustomDiagID(Level L, const char *Message); + + + /// ConvertArgToString - This method converts a diagnostic argument (as an + /// intptr_t) into the string that represents it. + void ConvertArgToString(ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModLen, + const char *Argument, unsigned ArgLen, + llvm::SmallVectorImpl<char> &Output) const { + ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output, + ArgToStringCookie); + } + + void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { + ArgToStringFn = Fn; + ArgToStringCookie = Cookie; + } + + //===--------------------------------------------------------------------===// + // 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); + + /// 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); + + /// getDiagnosticLevel - Based on the way the client configured the Diagnostic + /// object, classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticClient. + Level getDiagnosticLevel(unsigned DiagID) const; + + /// 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); + + /// \brief Clear out the current diagnostic. + void Clear() { CurDiagID = ~0U; } + +private: + /// getDiagnosticMappingInfo - Return the mapping info currently set for the + /// specified builtin diagnostic. This returns the high bit encoding, or zero + /// if the field is completely uninitialized. + unsigned getDiagnosticMappingInfo(diag::kind Diag) const { + return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 15); + } + + void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map, + bool isUser) const { + if (isUser) Map |= 8; // Set the high bit for user mappings. + unsigned char &Slot = DiagMappings[DiagId/2]; + unsigned Shift = (DiagId & 1)*4; + Slot &= ~(15 << Shift); + Slot |= Map << Shift; + } + + /// getDiagnosticLevel - This is an internal implementation helper used when + /// DiagClass is already known. + Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const; + + // 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 DiagnosticBuilder; + friend class DiagnosticInfo; + + /// CurDiagLoc - This is the location of the current diagnostic that is in + /// flight. + FullSourceLoc CurDiagLoc; + + /// CurDiagID - This is the ID of the current diagnostic that is in flight. + /// This is set to ~0U when there is no diagnostic in flight. + unsigned CurDiagID; + + enum { + /// MaxArguments - The maximum number of arguments we can hold. We currently + /// only support up to 10 arguments (%0-%9). A single diagnostic with more + /// than that almost certainly has to be simplified anyway. + MaxArguments = 10 + }; + + /// NumDiagArgs - This contains the number of entries in Arguments. + signed char NumDiagArgs; + /// NumRanges - This is the number of ranges in the DiagRanges array. + unsigned char NumDiagRanges; + /// \brief The number of code modifications hints in the + /// CodeModificationHints array. + unsigned char NumCodeModificationHints; + + /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum + /// values, with one for each argument. This specifies whether the argument + /// is in DiagArgumentsStr or in DiagArguments. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// DiagArgumentsStr - This holds the values of each string argument for the + /// current diagnostic. This value is only used when the corresponding + /// ArgumentKind is ak_std_string. + std::string DiagArgumentsStr[MaxArguments]; + + /// DiagArgumentsVal - The values for the various substitution positions. This + /// is used when the argument is not an std::string. The specific value is + /// mangled into an intptr_t and the intepretation depends on exactly what + /// sort of argument kind it is. + intptr_t DiagArgumentsVal[MaxArguments]; + + /// DiagRanges - The list of ranges added to this diagnostic. It currently + /// only support 10 ranges, could easily be extended if needed. + const SourceRange *DiagRanges[10]; + + enum { MaxCodeModificationHints = 3 }; + + /// CodeModificationHints - If valid, provides a hint with some code + /// to insert, remove, or modify at a particular position. + CodeModificationHint CodeModificationHints[MaxCodeModificationHints]; + + /// ProcessDiag - This is the method used to report a diagnostic that is + /// finally fully formed. + void ProcessDiag(); +}; + +//===----------------------------------------------------------------------===// +// DiagnosticBuilder +//===----------------------------------------------------------------------===// + +/// DiagnosticBuilder - This is a little helper class used to produce +/// diagnostics. This is constructed by the Diagnostic::Report method, and +/// allows insertion of extra information (arguments and source ranges) into the +/// currently "in flight" diagnostic. When the temporary for the builder is +/// destroyed, the diagnostic is issued. +/// +/// Note that many of these will be created as temporary objects (many call +/// sites), so we want them to be small and we never want their address taken. +/// This ensures that compilers with somewhat reasonable optimizers will promote +/// the common fields to registers, eliminating increments of the NumArgs field, +/// for example. +class DiagnosticBuilder { + mutable Diagnostic *DiagObj; + mutable unsigned NumArgs, NumRanges, NumCodeModificationHints; + + void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT + friend class Diagnostic; + explicit DiagnosticBuilder(Diagnostic *diagObj) + : DiagObj(diagObj), NumArgs(0), NumRanges(0), + NumCodeModificationHints(0) {} + +public: + /// Copy constructor. When copied, this "takes" the diagnostic info from the + /// input and neuters it. + DiagnosticBuilder(const DiagnosticBuilder &D) { + DiagObj = D.DiagObj; + D.DiagObj = 0; + NumArgs = D.NumArgs; + NumRanges = D.NumRanges; + NumCodeModificationHints = D.NumCodeModificationHints; + } + + /// \brief Force the diagnostic builder to emit the diagnostic now. + /// + /// Once this function has been called, the DiagnosticBuilder object + /// should not be used again before it is destroyed. + void Emit() { + // If DiagObj is null, then its soul was stolen by the copy ctor + // or the user called Emit(). + if (DiagObj == 0) return; + + // When emitting diagnostics, we set the final argument count into + // the Diagnostic object. + DiagObj->NumDiagArgs = NumArgs; + DiagObj->NumDiagRanges = NumRanges; + DiagObj->NumCodeModificationHints = NumCodeModificationHints; + + // Process the diagnostic, sending the accumulated information to the + // DiagnosticClient. + DiagObj->ProcessDiag(); + + // Clear out the current diagnostic object. + DiagObj->Clear(); + + // This diagnostic is dead. + DiagObj = 0; + } + + /// Destructor - The dtor emits the diagnostic if it hasn't already + /// been emitted. + ~DiagnosticBuilder() { Emit(); } + + /// Operator bool: conversion of DiagnosticBuilder to bool always returns + /// true. This allows is to be used in boolean error contexts like: + /// return Diag(...); + operator bool() const { return true; } + + void AddString(const std::string &S) const { + assert(NumArgs < Diagnostic::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string; + DiagObj->DiagArgumentsStr[NumArgs++] = S; + } + + void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { + assert(NumArgs < Diagnostic::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = Kind; + DiagObj->DiagArgumentsVal[NumArgs++] = V; + } + + void AddSourceRange(const SourceRange &R) const { + assert(NumRanges < + sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && + "Too many arguments to diagnostic!"); + DiagObj->DiagRanges[NumRanges++] = &R; + } + + void AddCodeModificationHint(const CodeModificationHint &Hint) const { + assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints && + "Too many code modification hints!"); + DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint; + } +}; + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const std::string &S) { + DB.AddString(S); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const char *Str) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), + Diagnostic::ak_c_string); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { + DB.AddTaggedVal(I, Diagnostic::ak_sint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) { + DB.AddTaggedVal(I, Diagnostic::ak_sint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + unsigned I) { + DB.AddTaggedVal(I, Diagnostic::ak_uint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const IdentifierInfo *II) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), + Diagnostic::ak_identifierinfo); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const SourceRange &R) { + DB.AddSourceRange(R); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const CodeModificationHint &Hint) { + DB.AddCodeModificationHint(Hint); + return 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){ + assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); + CurDiagLoc = Loc; + CurDiagID = DiagID; + return DiagnosticBuilder(this); +} + +//===----------------------------------------------------------------------===// +// DiagnosticInfo +//===----------------------------------------------------------------------===// + +/// DiagnosticInfo - This is a little helper class (which is basically a smart +/// pointer that forward info from Diagnostic) that allows clients to enquire +/// about the currently in-flight diagnostic. +class DiagnosticInfo { + const Diagnostic *DiagObj; +public: + explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {} + + const Diagnostic *getDiags() const { return DiagObj; } + unsigned getID() const { return DiagObj->CurDiagID; } + const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; } + + unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } + + /// getArgKind - Return the kind of the specified index. Based on the kind + /// of argument, the accessors below can be used to get the value. + Diagnostic::ArgumentKind getArgKind(unsigned Idx) const { + assert(Idx < getNumArgs() && "Argument index out of range!"); + return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; + } + + /// getArgStdStr - Return the provided argument string specified by Idx. + const std::string &getArgStdStr(unsigned Idx) const { + assert(getArgKind(Idx) == Diagnostic::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsStr[Idx]; + } + + /// getArgCStr - Return the specified C string argument. + const char *getArgCStr(unsigned Idx) const { + assert(getArgKind(Idx) == Diagnostic::ak_c_string && + "invalid argument accessor!"); + return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// getArgSInt - Return the specified signed integer argument. + int getArgSInt(unsigned Idx) const { + assert(getArgKind(Idx) == Diagnostic::ak_sint && + "invalid argument accessor!"); + return (int)DiagObj->DiagArgumentsVal[Idx]; + } + + /// getArgUInt - Return the specified unsigned integer argument. + unsigned getArgUInt(unsigned Idx) const { + assert(getArgKind(Idx) == Diagnostic::ak_uint && + "invalid argument accessor!"); + return (unsigned)DiagObj->DiagArgumentsVal[Idx]; + } + + /// getArgIdentifier - Return the specified IdentifierInfo argument. + const IdentifierInfo *getArgIdentifier(unsigned Idx) const { + assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo && + "invalid argument accessor!"); + return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// getRawArg - Return the specified non-string argument in an opaque form. + intptr_t getRawArg(unsigned Idx) const { + assert(getArgKind(Idx) != Diagnostic::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsVal[Idx]; + } + + + /// getNumRanges - Return the number of source ranges associated with this + /// diagnostic. + unsigned getNumRanges() const { + return DiagObj->NumDiagRanges; + } + + const SourceRange &getRange(unsigned Idx) const { + assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); + return *DiagObj->DiagRanges[Idx]; + } + + unsigned getNumCodeModificationHints() const { + return DiagObj->NumCodeModificationHints; + } + + const CodeModificationHint &getCodeModificationHint(unsigned Idx) const { + return DiagObj->CodeModificationHints[Idx]; + } + + const CodeModificationHint *getCodeModificationHints() const { + return DiagObj->NumCodeModificationHints? + &DiagObj->CodeModificationHints[0] : 0; + } + + /// FormatDiagnostic - Format this diagnostic into a string, substituting the + /// formal arguments into the %0 slots. The result is appended onto the Str + /// array. + void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const; +}; + +/// DiagnosticClient - This is an abstract interface implemented by clients of +/// the front-end, which formats and prints fully processed diagnostics. +class DiagnosticClient { +public: + virtual ~DiagnosticClient(); + + /// setLangOptions - This is set by clients of diagnostics when they know the + /// language parameters of the diagnostics that may be sent through. Note + /// that this can change over time if a DiagClient has multiple languages sent + /// through it. It may also be set to null (e.g. when processing command line + /// options). + virtual void setLangOptions(const LangOptions *LO) {} + + /// IncludeInDiagnosticCounts - This method (whose default implementation + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticClient should be included in the number of diagnostics + /// reported by Diagnostic. + virtual bool IncludeInDiagnosticCounts() const; + + /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) = 0; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td new file mode 100644 index 000000000000..67d8eaafc9ec --- /dev/null +++ b/include/clang/Basic/Diagnostic.td @@ -0,0 +1,73 @@ +//===--- Diagnostic.td - C Language Family Diagnostic Handling ------------===// +// +// 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 the diagnostics +// and diagnostic control. +// +//===----------------------------------------------------------------------===// + +// Define the diagnostic mappings. +class DiagMapping; +def MAP_IGNORE : DiagMapping; +def MAP_WARNING : DiagMapping; +def MAP_ERROR : DiagMapping; +def MAP_FATAL : DiagMapping; + +// Define the diagnostic classes. +class DiagClass; +def CLASS_NOTE : DiagClass; +def CLASS_WARNING : DiagClass; +def CLASS_EXTENSION : DiagClass; +def CLASS_ERROR : DiagClass; + +// Diagnostic Groups. +class DiagGroup<string Name, list<DiagGroup> subgroups = []> { + string GroupName = Name; + list<DiagGroup> SubGroups = subgroups; +} +class InGroup<DiagGroup G> { DiagGroup Group = G; } +//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } + + +// This defines the diagnostic groups that have references to them. +include "DiagnosticGroups.td" + + +// All diagnostics emitted by the compiler are an indirect subclass of this. +class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> { + /// Component is specified by the file with a big let directive. + string Component = ?; + string Text = text; + DiagClass Class = DC; + DiagMapping DefaultMapping = defaultmapping; + DiagGroup Group; +} + +class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>; +class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>; +class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>; +class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>; +class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>; + + +class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; } +class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; } +class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; } +class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; } + +// Definitions for Diagnostics. +include "DiagnosticASTKinds.td" +include "DiagnosticAnalysisKinds.td" +include "DiagnosticCommonKinds.td" +include "DiagnosticDriverKinds.td" +include "DiagnosticFrontendKinds.td" +include "DiagnosticLexKinds.td" +include "DiagnosticParseKinds.td" +include "DiagnosticSemaKinds.td" + diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td new file mode 100644 index 000000000000..f075aaaf422f --- /dev/null +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -0,0 +1,29 @@ +//==--- DiagnosticASTKinds.td - libast diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "AST" in { + +//def note_comma_in_ice : Note< +// "C does not permit evaluated commas in an integer constant expression">; +def note_expr_divide_by_zero : Note<"division by zero">; + +// inline asm related. +def err_asm_invalid_escape : Error< + "invalid %% escape in inline assembly string">; +def err_asm_unknown_symbolic_operand_name : Error< + "unknown symbolic operand name in inline assembly string">; + +def err_asm_unterminated_symbolic_operand_name : Error< + "unterminated symbolic operand name in inline assembly string">; +def err_asm_empty_symbolic_operand_name : Error< + "empty symbolic operand name in inline assembly string">; +def err_asm_invalid_operand_number : Error< + "invalid operand number in inline asm string">; + +} diff --git a/include/clang/Basic/DiagnosticAnalysisKinds.td b/include/clang/Basic/DiagnosticAnalysisKinds.td new file mode 100644 index 000000000000..46dc0e60a7eb --- /dev/null +++ b/include/clang/Basic/DiagnosticAnalysisKinds.td @@ -0,0 +1,15 @@ +//==--- DiagnosticAnalysisKinds.td - libanalysis diagnostics --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Analysis" in { + +// CHECK: use of uninitialized values +def warn_uninit_val : Warning<"use of uninitialized variable">; + +} diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td new file mode 100644 index 000000000000..e059d5e60520 --- /dev/null +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -0,0 +1,58 @@ +//==--- DiagnosticCommonKinds.td - common diagnostics ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Common Helpers +//===----------------------------------------------------------------------===// + +let Component = "Common" in { + +def note_previous_definition : Note<"previous definition is here">; +def note_previous_declaration : Note<"previous declaration is here">; +def note_previous_implicit_declaration : Note< + "previous implicit declaration is here">; +def note_previous_use : Note<"previous use is here">; +def note_duplicate_case_prev : Note<"previous case defined here">; +def note_forward_declaration : Note<"forward declaration of %0">; +def note_type_being_defined : Note< + "definition of %0 is not complete until the closing '}'">; +/// note_matching - this is used as a continuation of a previous diagnostic, +/// e.g. to specify the '(' when we expected a ')'. +def note_matching : Note<"to match this '%0'">; + +def note_using_decl : Note<"using">; +def note_also_found_decl : Note<"also found">; + +// Parse && Lex +def err_expected_colon : Error<"expected ':'">; + +// Parse && Sema +def err_no_declarators : Error<"declaration does not declare anything">; +def err_param_redefinition : Error<"redefinition of 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">; + +// Sema && Lex +def ext_longlong : Extension< + "'long long' is an extension when C99 mode is not enabled">; +def warn_integer_too_large : Warning< + "integer constant is too large for its type">; +def warn_integer_too_large_for_signed : Warning< + "integer constant is so large that it is unsigned">; + +// Sema && AST +def note_invalid_subexpr_in_ice : Note< + "subexpression not valid in an integer constant expression">; + +// clang-cc +def err_pp_I_dash_not_supported : Error< + "-I- not supported, please use -iquote instead">; + +} diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td new file mode 100644 index 000000000000..327db00e0b28 --- /dev/null +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -0,0 +1,64 @@ +//==--- DiagnosticDriverKinds.td - libdriver diagnostics ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +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_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_opt_with_multiple_archs : Error< + "option '%0' cannot be used with multiple -arch options">; +def err_drv_invalid_output_with_multiple_archs : Error< + "cannot use '%0' output with multiple -arch options">; +def err_drv_no_input_files : Error<"no input files">; +def err_drv_use_of_Z_option : Error< + "unsupported use of internal gcc -Z option '%0'">; +def err_drv_output_argument_with_multiple_files : Error< + "cannot specify -o when generating multiple output files">; +def err_drv_unable_to_make_temp : Error< + "unable to make temporary file: %0">; +def err_drv_unable_to_remove_file : Error< + "unable to remove file: %0">; +def err_drv_command_failure : Error< + "unable to execute command: %0">; +def err_drv_invalid_darwin_version : Error< + "invalid Darwin version number: %0">; +def err_drv_missing_argument : Error< + "argument to '%0' is missing (expected %1 %plural{1:value|:values}1)">; +def err_drv_invalid_Xarch_argument : Error< + "invalid Xarch argument: '%0'">; +def err_drv_argument_only_allowed_with : Error< + "invalid argument '%0' only allowed with '%1'">; +def err_drv_argument_not_allowed_with : Error< + "invalid argument '%0' not allowed with '%1'">; +def err_drv_invalid_version_number : Error< + "invalid version number in '%0'">; +def err_drv_no_linker_llvm_support : Error< + "'%0': unable to pass LLVM bit-code files to linker">; +def err_drv_clang_unsupported : Error< + "the clang compiler does not support '%0'">; + +def warn_drv_input_file_unused : Warning< + "%0: '%1' input unused when '%2' is present">; +def warn_drv_unused_argument : Warning< + "argument unused during compilation: '%0'">; +def warn_drv_pipe_ignored_with_save_temps : Warning< + "-pipe ignored because -save-temps specified">; +def warn_drv_not_using_clang_cpp : Warning< + "not using the clang prepreprocessor due to user override">; +def warn_drv_not_using_clang_cxx : Warning< + "not using the clang compiler for C++ inputs">; +def warn_drv_not_using_clang_arch : Warning< + "not using the clang compiler for the '%0' architecture">; +def warn_drv_clang_unsupported : Warning< + "the clang compiler does not support '%0'">; + +} diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td new file mode 100644 index 000000000000..1bc296babd3b --- /dev/null +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -0,0 +1,136 @@ +//==--- DiagnosticFrontendKinds.td - frontend diagnostics -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Frontend" in { + +def err_fe_unknown_triple : Error< + "unknown target triple '%0', please use -triple or -arch">; +def err_fe_error_reading : Error<"error reading '%0'">; +def err_fe_error_reading_stdin : Error<"error reading stdin">; + +def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; +def note_fixit_in_macro : Note< + "FIX-IT unable to apply suggested code changes in a macro">; +def note_fixit_failed : Note< + "FIX-IT unable to apply suggested code changes">; +def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">; +def warn_fixit_no_changes : Note< + "FIX-IT detected errors it could not fix; no output will be generated">; + +// PCH reader +def warn_pch_target_triple : Error< + "PCH file was compiled for the target '%0' but the current translation " + "unit is being compiled for target '%1'">; +def warn_pch_c99 : Error< + "C99 support was %select{disabled|enabled}0 in PCH file but is " + "currently %select{disabled|enabled}1">; +def warn_pch_cplusplus : Error< + "C++ support was %select{disabled|enabled}0 in PCH file but is " + "currently %select{disabled|enabled}1">; +def warn_pch_cplusplus0x : Error< + "C++0x support was %select{disabled|enabled}0 in PCH file but is " + "currently %select{disabled|enabled}1">; +def warn_pch_objective_c : Error< + "Objective-C support was %select{disabled|enabled}0 in PCH file but is " + "currently %select{disabled|enabled}1">; +def warn_pch_objective_c2 : Error< + "Objective-C 2.0 support was %select{disabled|enabled}0 in PCH file but " + "is currently %select{disabled|enabled}1">; +def warn_pch_nonfragile_abi : Error< + "PCH file was compiled with the %select{32-bit|non-fragile}0 Objective-C " + "ABI but the %select{32-bit|non-fragile}1 Objective-C ABI is selected">; +def warn_pch_extensions : Error< + "extensions were %select{enabled|disabled}0 in PCH file but are " + "currently %select{enabled|disabled}1">; +def warn_pch_gnu_extensions : Error< + "GNU extensions were %select{disabled|enabled}0 in PCH file but are " + "currently %select{disabled|enabled}1">; +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_heinous_extensions : Error< + "heinous extensions were %select{disabled|enabled}0 in PCH file but are " + "currently %select{disabled|enabled}1">; +def warn_pch_lax_vector_conversions : Error< + "lax vector conversions were %select{disabled|enabled}0 in PCH file but " + "are currently %select{disabled|enabled}1">; +def warn_pch_exceptions : Error< + "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">; +def warn_pch_freestanding : Error< + "PCH file was compiled with a %select{hosted|freestanding}0 " + "implementation but a %select{hosted|freestanding}1 implementation " + "is selected">; +def warn_pch_builtins : Error< + "PCH file was compiled with builtins %select{enabled|disabled}0 but " + "builtins are currently %select{enabled|disabled}1">; +def warn_pch_thread_safe_statics : Error< + "PCH file was compiled %select{without|with}0 thread-safe statics but" + "thread-safe statics are currently %select{disabled|enabled}1">; +def warn_pch_blocks : Error< + "blocks were %select{disabled|enabled}0 in PCH file but " + "are currently %select{disabled|enabled}1">; +def warn_pch_math_errno : Error< + "math functions %select{do not respect|respect}0 'errno' in PCH " + "file but they are currently set to %select{not respect|respect}1 " + "'errno'">; +def warn_pch_overflow_checking : Error< + "signed integer overflow checking was %select{disabled|enabled}0 in PCH " + "file but is currently %select{disabled|enabled}1">; +def warn_pch_optimize : Error< + "the macro '__OPTIMIZE__' was %select{not defined|defined}0 in " + "the PCH file but is currently %select{undefined|defined}1">; +def warn_pch_optimize_size : Error< + "the macro '__OPTIMIZE_SIZE__' was %select{not defined|defined}0 in " + "the PCH file but is currently %select{undefined|defined}1">; +def warn_pch_static : Error< + "the PCH file was compiled %select{dynamic|static}0 but the " + "current translation unit is being compiled as %select{dynamic|static}1">; +def warn_pch_pic_level : Error< + "PCH file was compiled with PIC level %0, but the current translation " + "unit will be compiled with PIC level %1">; +def warn_pch_gnu_inline : Error< + "PCH file was compiled with %select{C99|GNU|}0 inline semantics but " + "%select{C99|GNU}1 inline semantics are currently selected">; +def warn_pch_no_inline : Error< + "the macro '__NO_INLINE__' was %select{not defined|defined}0 in " + "the PCH file but is currently %select{undefined|defined}1">; +def warn_pch_gc_mode : Error< + "the PCH file was built with %select{no||hybrid}0 garbage collection but " + "the current translation unit will compiled with %select{no||hybrid}1 " + "garbage collection">; +def warn_pch_version_too_old : Error< + "PCH file uses an older PCH format that is no longer supported">; +def warn_pch_version_too_new : Error< + "PCH file uses a newer PCH format that cannot be read">; +def warn_cmdline_conflicting_macro_def : Error< + "definition of the macro '%0' conflicts with the definition used to " + "build the precompiled header">; +def note_pch_macro_defined_as : Note< + "definition of macro '%0' in the precompiled header">; +def warn_cmdline_missing_macro_defs : Warning< + "macro definitions used to build the precompiled header are missing">; +def note_using_macro_def_from_pch : Note< + "using this macro definition from precompiled header">; +def warn_macro_name_used_in_pch : Error< + "definition of macro %0 conflicts with an identifier used in the " + "precompiled header">; +def warn_pch_compiler_options_mismatch : Error< + "compiler options used when building the precompiled header differ from " + "the options used when using the precompiled header">; +def warn_pch_access_control : Error< + "C++ access control 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; +} diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td new file mode 100644 index 000000000000..700826fa658f --- /dev/null +++ b/include/clang/Basic/DiagnosticGroups.td @@ -0,0 +1,133 @@ +//==--- DiagnosticGroups.td - Diagnostic Group Definitions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def ImplicitFunctionDeclare : DiagGroup<"implicit-function-declaration">; +def ImplicitInt : DiagGroup<"implicit-int">; + +// Aggregation warning settings. +def Implicit : DiagGroup<"implicit", [ + ImplicitFunctionDeclare, + ImplicitInt +]>; + + + +// Empty DiagGroups: these are recognized by clang but ignored. +def : DiagGroup<"aggregate-return">; +def : DiagGroup<"bad-function-cast">; +def : DiagGroup<"cast-align">; +def : DiagGroup<"cast-qual">; +def : DiagGroup<"char-align">; +def : DiagGroup<"char-subscripts">; +def Comment : DiagGroup<"comment">; +def : DiagGroup<"conversion">; +def : DiagGroup<"declaration-after-statement">; +def : DiagGroup<"disabled-optimization">; +def : DiagGroup<"discard-qual">; +def ExtraTokens : DiagGroup<"extra-tokens">; + +def FormatExtraArgs : DiagGroup<"format-extra-args">; +def FormatZeroLength : DiagGroup<"format-zero-length">; + +def FourByteMultiChar : DiagGroup<"four-char-constants">; +def : DiagGroup<"init-self">; +def : DiagGroup<"inline">; +def : DiagGroup<"int-to-pointer-cast">; +def : DiagGroup<"missing-braces">; +def : DiagGroup<"missing-declarations">; +def : DiagGroup<"missing-format-attribute">; +def : DiagGroup<"missing-noreturn">; +def MultiChar : DiagGroup<"multichar">; +def : DiagGroup<"nested-externs">; +def : DiagGroup<"newline-eof">; +def : DiagGroup<"long-long">; +def MismatchedTags : DiagGroup<"mismatched-tags">; +def : DiagGroup<"missing-field-initializers">; +def NonNull : DiagGroup<"nonnull">; +def : DiagGroup<"nonportable-cfstrings">; +def : DiagGroup<"old-style-definition">; +def : DiagGroup<"packed">; +def Parentheses : DiagGroup<"parentheses">; +def : DiagGroup<"pointer-arith">; +def : DiagGroup<"pointer-to-int-cast">; +def : DiagGroup<"redundant-decls">; +def ReturnType : DiagGroup<"return-type">; +def : DiagGroup<"sequence-point">; +def : DiagGroup<"shadow">; +def : DiagGroup<"shorten-64-to-32">; +def : DiagGroup<"sign-compare">; + +// Just silence warnings about common forms of -Wstrict-aliasing for now. +def : DiagGroup<"strict-aliasing=0">; +def : DiagGroup<"strict-aliasing=1">; +def : DiagGroup<"strict-aliasing=2">; +def : DiagGroup<"strict-aliasing">; + +// Just silence warnings about common forms of -Wstrict-aliasing for now. +def : DiagGroup<"strict-overflow=0">; +def : DiagGroup<"strict-overflow=1">; +def : DiagGroup<"strict-overflow=2">; +def : DiagGroup<"strict-overflow">; + +def InvalidOffsetof : DiagGroup<"invalid-offsetof">; +def : DiagGroup<"strict-prototypes">; +def : DiagGroup<"strict-selector-match">; +def Switch : DiagGroup<"switch">; +def Trigraphs : DiagGroup<"trigraphs">; + +def : DiagGroup<"type-limits">; +def Uninitialized : DiagGroup<"uninitialized">; +def UnknownPragmas : DiagGroup<"unknown-pragmas">; +def : DiagGroup<"unused-function">; +def : DiagGroup<"unused-label">; +def : DiagGroup<"unused-parameter">; +def UnusedValue : DiagGroup<"unused-value">; +def UnusedVariable : DiagGroup<"unused-variable">; +def : DiagGroup<"variadic-macros">; +def VectorConversions : DiagGroup<"vector-conversions">; // clang specific +def VolatileRegisterVar : DiagGroup<"volatile-register-var">; +def : DiagGroup<"write-strings">; + +// Aggregation warning settings. + + +// Format settings. +def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>; +def FormatSecurity : DiagGroup<"format-security", [Format]>; +def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>; +def FormatY2K : DiagGroup<"format-y2k", [Format]>; +def Format2 : DiagGroup<"format=2", + [FormatNonLiteral, FormatSecurity, FormatY2K]>; + + +def Extra : DiagGroup<"extra">; + +def Most : DiagGroup<"most", [ + Comment, + Format, + Implicit, + MismatchedTags, + MultiChar, + Switch, + Trigraphs, + Uninitialized, + UnknownPragmas, + UnusedValue, + UnusedVariable, + VectorConversions, + VolatileRegisterVar + ]>; + +// -Wall is -Wmost -Wparentheses +def : DiagGroup<"all", [Most, Parentheses]>; + +// Aliases. +def : DiagGroup<"", [Extra]>; // -W = -Wextra +def : DiagGroup<"endif-labels", [ExtraTokens]>; // endif-labels = endif-tokens + diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td new file mode 100644 index 000000000000..3d1f9320cd41 --- /dev/null +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -0,0 +1,277 @@ +//==--- DiagnosticLexKinds.td - liblex diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Lexer Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Lex" in { + +def null_in_string : Warning<"null character(s) preserved in string literal">; +def null_in_char : Warning<"null character(s) preserved in character literal">; +def null_in_file : Warning<"null character ignored">; +def warn_nested_block_comment : Warning<"'/*' within block comment">, + InGroup<Comment>; +def escaped_newline_block_comment_end : Warning< + "escaped newline between */ characters at block comment end">, + InGroup<Comment>; +def backslash_newline_space : Warning< + "backslash and newline separated by space">; + +// Trigraphs. +def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>; +def trigraph_ignored_block_comment : Warning< + "ignored trigraph would end block comment">, InGroup<Trigraphs>; +def trigraph_ends_block_comment : Warning<"trigraph ends block comment">, + InGroup<Trigraphs>; +def trigraph_converted : Warning<"trigraph converted to '%0' character">, + InGroup<Trigraphs>; + +def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">, + InGroup<Comment>; +def ext_bcpl_comment : Extension< + "// comments are not allowed in this language">, + InGroup<Comment>; +def ext_no_newline_eof : Extension<"no newline at end of file">; +def ext_backslash_newline_eof : Extension<"backslash-newline at end of file">; +def ext_dollar_in_identifier : Extension<"'$' in identifier">; +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 err_empty_character : Error<"empty character constant">; +def err_unterminated_block_comment : Error<"unterminated /* comment">; +def err_invalid_character_to_charify : Error< + "invalid argument to convert to character">; +def ext_multichar_character_literal : ExtWarn< + "multi-character character constant">, InGroup<MultiChar>; +def ext_four_char_character_literal : Extension< + "multi-character character constant">, InGroup<FourByteMultiChar>; + + +// Literal +def ext_nonstandard_escape : Extension< + "use of non-standard escape character '\\%0'">; +def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">; +def err_hex_escape_no_digits : Error<"\\x used with no following hex digits">; +def err_ucn_escape_no_digits : Error<"\\u used with no following hex digits">; +def err_ucn_escape_invalid : Error<"invalid universal character">; +def err_ucn_escape_incomplete : Error<"incomplete universal character name">; +def err_ucn_escape_too_big : Error<"universal character name is too long">; +def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">; +def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">; +def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">; +def err_invalid_suffix_integer_constant : Error< + "invalid suffix '%0' on integer constant">; +def err_invalid_suffix_float_constant : Error< + "invalid suffix '%0' on floating constant">; +def warn_extraneous_wide_char_constant : Warning< + "extraneous characters in wide character constant ignored">; +def warn_char_constant_too_large : Warning< + "character constant too long for its type">; +def err_exponent_has_no_digits : Error<"exponent has no digits">; +def ext_imaginary_constant : Extension<"imaginary constants are an extension">; +def err_hexconstant_requires_exponent : Error< + "hexadecimal floating constants require an exponent">; +def ext_hexconstant_invalid : Extension< + "hexadecimal floating constants are a C99 feature">; +def ext_binary_literal : Extension< + "binary integer literals are an extension">; +def err_pascal_string_too_long : Error<"Pascal string is too long">; +def warn_octal_escape_too_large : ExtWarn<"octal escape sequence out of range">; +def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">; + +//===----------------------------------------------------------------------===// +// Preprocessor Diagnostics +//===----------------------------------------------------------------------===// +def pp_hash_warning : Warning<"#warning%0">, InGroup<DiagGroup<"#warnings">>; +def pp_include_next_in_primary : Warning< + "#include_next in primary source file">; +def pp_include_macros_out_of_predefines : Error< + "the #__include_macros directive is only for internal use by -imacros">; +def pp_include_next_absolute_path : Warning<"#include_next with absolute path">; +def ext_c99_whitespace_required_after_macro_name : ExtWarn< + "ISO C99 requires whitespace after the macro name">; +def ext_missing_whitespace_after_macro_name : ExtWarn< + "whitespace required after macro name">; +def warn_missing_whitespace_after_macro_name : Warning< + "whitespace recommended after macro name">; + +def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">; +def pp_pragma_sysheader_in_main_file : Warning< + "#pragma system_header ignored in main file">; +def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; +def pp_out_of_date_dependency : Warning< + "current file is older than dependency %0">; +def pp_undef_builtin_macro : Warning<"undefining builtin macro">; +def pp_redef_builtin_macro : Warning<"redefining builtin macro">; +def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore, + InGroup<DiagGroup<"unused-macros">>; +def warn_pp_undef_identifier : Warning< + "%0 is not defined, evaluates to 0">, + InGroup<DiagGroup<"undef">>, DefaultIgnore; + +def pp_invalid_string_literal : Warning< + "invalid string literal, ignoring final '\\'">; +def warn_pp_expr_overflow : Warning< + "integer overflow in preprocessor expression">; +def warn_pp_convert_lhs_to_positive : Warning< + "left side of operator converted from negative value to unsigned: %0">; +def warn_pp_convert_rhs_to_positive : Warning< + "right side of operator converted from negative value to unsigned: %0">; + +def ext_pp_import_directive : Extension<"#import is a language extension">; +def ext_pp_ident_directive : Extension<"#ident is a language extension">; +def ext_pp_include_next_directive : Extension< + "#include_next is a language extension">; +def ext_pp_warning_directive : Extension<"#warning is a language extension">; + +def ext_pp_extra_tokens_at_eol : ExtWarn< + "extra tokens at end of #%0 directive">, InGroup<ExtraTokens>; + +def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; +def ext_pp_bad_vaargs_use : Extension< + "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; +def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">; +def ext_variadic_macro : Extension<"variadic macros were introduced in C99">; +def ext_named_variadic_macro : Extension< + "named variadic macros are a GNU extension">; +def ext_embedded_directive : Extension< + "embedding a directive within macro arguments is not portable">; +def ext_missing_varargs_arg : Extension< + "varargs argument missing, but tolerated as an extension">; +def ext_empty_fnmacro_arg : Extension< + "empty macro arguments were standardized in C99">; + +def ext_pp_base_file : Extension<"__BASE_FILE__ is a language extension">; +def ext_pp_include_level : Extension< + "__INCLUDE_LEVEL__ is a language extension">; +def ext_pp_timestamp : Extension<"__TIMESTAMP__ is a language extension">; +def ext_pp_counter : Extension< + "__COUNTER__ is a language extension">; + +def err_pp_invalid_directive : Error<"invalid preprocessing directive">; +def err_pp_hash_error : Error<"#error%0">; +def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def err_pp_empty_filename : Error<"empty filename">; +def err_pp_include_too_deep : Error<"#include nested too deeply">; +def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">; +def err_pp_macro_not_identifier : Error<"macro names must be identifiers">; +def err_pp_missing_macro_name : Error<"macro name missing">; +def err_pp_missing_rparen_in_macro_def : Error< + "missing ')' in macro parameter list">; +def err_pp_invalid_tok_in_arg_list : Error< + "invalid token in macro parameter list">; +def err_pp_expected_ident_in_arg_list : Error< + "expected identifier in macro parameter list">; +def err_pp_expected_comma_in_arg_list : Error< + "expected comma in macro parameter list">; +def err_pp_duplicate_name_in_arg_list : Error< + "duplicate macro parameter name %0">; +def err_pp_stringize_not_parameter : Error< + "'#' is not followed by a macro parameter">; +def err_pp_malformed_ident : Error<"invalid #ident directive">; +def err_pp_unterminated_conditional : Error< + "unterminated conditional directive">; +def pp_err_else_after_else : Error<"#else after #else">; +def pp_err_elif_after_else : Error<"#elif after #else">; +def pp_err_else_without_if : Error<"#else without #if">; +def pp_err_elif_without_if : Error<"#elif without #if">; +def err_pp_endif_without_if : Error<"#endif without #if">; +def err_pp_expected_value_in_expr : Error<"expected value in expression">; +def err_pp_missing_val_before_operator : Error<"missing value before operator">; +def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">; +def err_pp_expected_eol : Error< + "expected end of line in preprocessor expression">; +def err_pp_defined_requires_identifier : Error< + "operator 'defined' requires an identifier">; +def err_pp_missing_rparen : Error<"missing ')' after 'defined'">; +def err_pp_colon_without_question : Error<"':' without preceding '?'">; +def err_pp_division_by_zero : Error< + "division by zero in preprocessor expression">; +def err_pp_remainder_by_zero : Error< + "remainder by zero in preprocessor expression">; +def err_pp_expr_bad_token_binop : Error< + "token is not a valid binary operator in a preprocessor subexpression">; +def err_pp_expr_bad_token_start_expr : Error< + "invalid token at start of a preprocessor expression">; +def err_pp_invalid_poison : Error<"can only poison identifier tokens">; +def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">; +def err__Pragma_malformed : Error< + "_Pragma takes a parenthesized string literal">; +def err_pragma_comment_malformed : Error< + "pragma comment requires parenthesized identifier and optional string">; +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 : + 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">, + InGroup<UnknownPragmas>; +def warn_stdc_fenv_access_not_supported : + Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or" + " 'fatal'">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_option : + ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_token : + ExtWarn<"unexpected token in pragma diagnostic">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_unknown_warning : + ExtWarn<"unknown warning group '%0', ignored">, + InGroup<UnknownPragmas>; + +def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; +def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; +def err_paste_at_start : Error< + "'##' cannot appear at start of macro expansion">; +def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">; +def ext_paste_comma : Extension< + "Use of comma pasting extension is non-portable">; +def err_unterm_macro_invoc : Error< + "unterminated function-like macro invocation">; +def err_too_many_args_in_macro_invoc : Error< + "too many arguments provided to function-like macro invocation">; +def err_too_few_args_in_macro_invoc : Error< + "too few arguments provided to function-like macro invocation">; +def err_pp_bad_paste : Error< + "pasting formed '%0', an invalid preprocessing token">; +def err_pp_operator_used_as_macro_name : Error< + "C++ operator '%0' cannot be used as a macro name">; +def err_pp_illegal_floating_literal : Error< + "floating point literal in preprocessor expression">; +def err_pp_line_requires_integer : Error< + "#line directive requires a positive integer argument">; +def err_pp_line_invalid_filename : Error< + "invalid filename for #line directive">; +def warn_pp_line_decimal : Warning< + "#line directive interprets number as decimal, not octal">; +def err_pp_line_digit_sequence : Error< + "#line directive requires a simple digit sequence">; +def err_pp_linemarker_requires_integer : Error< + "line marker directive requires a positive integer argument">; +def err_pp_linemarker_invalid_filename : Error< + "invalid filename for line marker directive">; +def err_pp_linemarker_invalid_flag : Error< + "invalid flag line marker directive">; +def err_pp_linemarker_invalid_pop : Error< + "invalid line marker flag '2': cannot pop empty include stack">; +def ext_pp_line_too_big : Extension< + "C requires #line number to be less than %0, allowed as extension">; + +} diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td new file mode 100644 index 000000000000..2912344e06f8 --- /dev/null +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -0,0 +1,280 @@ +//==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Parser Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Parse" in { + +def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">; + +def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; +def ext_top_level_semi : Extension< + "extra ';' outside of a function">; +def ext_extra_struct_semi : Extension< + "extra ';' inside a struct or union">; + +def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; +def ext_plain_complex : ExtWarn< + "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_integer_complex : Extension< + "complex integer types are an extension">; +def ext_thread_before : Extension<"'__thread' before 'static'">; + +def ext_empty_struct_union_enum : Extension<"use of empty %0 extension">; + +def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; +def err_invalid_short_spec : Error<"'short %0' is invalid">; +def err_invalid_long_spec : Error<"'long %0' is invalid">; +def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; +def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; + +def ext_ident_list_in_param : Extension< + "type-less parameter names in function declaration">; +def ext_c99_variable_decl_in_for_loop : Extension< + "variable declaration in for loop is a C99-specific feature">; +def ext_c99_compound_literal : Extension< + "compound literals are a C99-specific feature">; +def ext_enumerator_list_comma : Extension< + "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific feature">; + +def ext_gnu_indirect_goto : Extension< + "use of GNU indirect-goto extension">; +def ext_gnu_address_of_label : Extension< + "use of GNU address-of-label extension">; +def ext_gnu_statement_expr : Extension< + "use of GNU statement expression extension">; +def ext_gnu_conditional_expr : Extension< + "use of GNU ?: expression extension, eliding middle term">; +def ext_gnu_empty_initializer : Extension< + "use of GNU empty initializer extension">; +def ext_gnu_array_range : Extension<"use of GNU array range extension">; +def ext_gnu_missing_equal_designator : ExtWarn< + "use of GNU 'missing =' extension in designator">; +def err_expected_equal_designator : Error<"expected '=' or another designator">; +def ext_gnu_old_style_field_designator : ExtWarn< + "use of GNU old-style field designator extension">; +def ext_gnu_case_range : Extension<"use of GNU case range extension">; + +// Generic errors. +def err_parse_error : Error<"parse error">; +def err_expected_expression : Error<"expected expression">; +def err_expected_type : Error<"expected a type">; +def err_expected_external_declaration : Error<"expected external declaration">; +def err_expected_ident : Error<"expected identifier">; +def err_expected_ident_lparen : Error<"expected identifier or '('">; +def err_expected_ident_lbrace : Error<"expected identifier or '{'">; +def err_expected_lbrace : Error<"expected '{'">; +def err_expected_lparen : Error<"expected '('">; +def err_expected_rparen : Error<"expected ')'">; +def err_expected_rsquare : Error<"expected ']'">; +def err_expected_rbrace : Error<"expected '}'">; +def err_expected_greater : Error<"expected '>'">; +def err_expected_semi_declation : Error< + "expected ';' at end of declaration">; +def err_expected_semi_decl_list : Error< + "expected ';' at end of declaration list">; +def ext_expected_semi_decl_list : Extension< + "expected ';' at end of declaration list">; +def err_expected_member_name_or_semi : Error< + "expected member name or ';' after declaration specifiers">; +def err_function_declared_typedef : Error< + "function definition declared 'typedef'">; +def err_expected_fn_body : Error< + "expected function body after function declarator">; +def err_expected_method_body : Error<"expected method body">; +def err_invalid_token_after_toplevel_declarator : Error< + "invalid token after top level declarator">; +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">; +def err_expected_less_after : Error<"expected '<' after '%0'">; +def err_expected_comma : Error<"expected ','">; +def err_expected_lbrace_in_compound_literal : Error< + "expected '{' in compound literal">; +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_expr : Error<"expected ';' after expression">; +def err_expected_semi_after_method_proto : Error< + "expected ';' after method prototype">; +def err_expected_semi_after_static_assert : Error< + "expected ';' after static_assert">; +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_expected_string_literal : Error<"expected string literal">; +def err_expected_asm_operand : Error< + "expected string literal or '[' for asm operand">; +def err_expected_selector_for_method : Error< + "expected selector for Objective-C method">; + +def err_unexpected_at : Error<"unexpected '@' in program">; + +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 err_argument_required_after_attribute : Error< + "argument required after attribute">; +def err_missing_param : Error<"expected parameter declarator">; +def err_unexpected_typedef_ident : Error< + "unexpected type name %0: expected identifier">; +def err_expected_class_name : Error<"expected class name">; +def err_unspecified_vla_size_with_static : Error< + "'static' may not be used with an unspecified variable length array size">; + +// Declarations. +def err_typename_requires_specqual : Error< + "type name requires a specifier or qualifier">; +def err_typename_invalid_storageclass : Error< + "type name does not allow storage class to be specified">; +def err_typename_invalid_functionspec : Error< + "type name does not allow function specifier to be specified">; +def err_invalid_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier">; +def err_unknown_typename : Error< + "unknown type name %0">; +def err_use_of_tag_name_without_tag : Error< + "use of tagged type %0 without '%1' tag">; + + +/// Objective-C parser diagnostics +def err_objc_no_attributes_on_category : Error< + "attributes may not be specified on a category">; +def err_objc_missing_end : Error<"missing @end">; +def warn_objc_protocol_qualifier_missing_id : Warning< + "protocol qualifiers without 'id' is archaic">; + +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_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< + "properties are an Objective-C 2 feature">; +def err_objc_unexpected_attr : Error< + "prefix attribute must be followed by an interface or protocol">; +def err_objc_directive_only_in_protocol : Error< + "directive may only be specified in protocols only">; +def err_missing_catch_finally : Error< + "@try statement without a @catch and @finally clause">; +def err_objc_concat_string : Error<"unexpected token after Objective-C string">; +def err_missing_sel_definition : Error<"cannot find definition of 'SEL'">; +def err_missing_id_definition : Error<"cannot find definition of 'id'">; +def err_missing_proto_definition : Error< + "cannot find definition of 'Protocol'">; +def err_missing_class_definition : Error<"cannot find definition of 'Class'">; +def warn_expected_implementation : Warning< + "@end must appear in an @implementation context">; +def error_property_ivar_decl : Error< + "property synthesize requires specification of an ivar">; + +def err_expected_field_designator : Error< + "expected a field designator, such as '.field = 4'">; + +def err_declaration_does_not_declare_param : Error< + "declaration does not declare a parameter">; +def err_no_matching_param : Error<"parameter named %0 is missing">; + +/// C++ parser diagnostics +def err_expected_unqualified_id : Error<"expected unqualified-id">; +def err_func_def_no_params : Error< + "function definition does not declare parameters">; +def err_expected_lparen_after_type : Error< + "expected '(' for function-style cast or type construction">; +def err_expected_equal_after_declarator : Error< + "expected '=' after declarator">; +def warn_parens_disambiguated_as_function_decl : Warning< + "parentheses were disambiguated as a function declarator">; +def err_expected_member_or_base_name : Error< + "expected class member or base class name">; +def ext_ellipsis_exception_spec : Extension< + "exception specification of '...' is a Microsoft extension">; +def err_expected_catch : Error<"expected catch">; +def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; + +// C++ derived classes +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'">; + +// Classes. +def err_anon_type_definition : Error< + "declaration of anonymous %0 must be a definition">; + + +/// C++ Templates +def err_expected_template : Error<"expected template">; +def err_expected_comma_greater : Error< + "expected ',' or '>' in template-parameter-list">; +def err_expected_type_id_after : Error<"expected type-id after '%0'">; +def err_expected_class_before : Error<"expected 'class' before '%0'">; +def err_template_spec_syntax_non_template : Error< + "identifier followed by '<' indicates a class template specialization but " + "%0 %select{does not refer to a template|refers to a function " + "template|<unused>|refers to a template template parameter}1">; +def err_id_after_template_in_nested_name_spec : Error< + "expected template name after 'template' keyword in nested name specifier">; +def err_id_after_template_in_typename_spec : Error< + "expected template name after 'template' keyword in typename specifier">; +def err_less_after_template_name_in_nested_name_spec : Error< + "expected '<' after 'template %0' in nested name specifier">; +def err_two_right_angle_brackets_need_space : Error< + "a space is required between consecutive right angle brackets (use '> >')">; +def warn_cxx0x_right_shift_in_template_arg : Warning< + "use of right-shift operator ('>>') in template argument will require " + "parentheses in C++0x">; +def err_multiple_template_declarators : Error< + "%select{|a template declaration|an explicit template specialization|" + "an explicit template instantiation}0 can " + "only %select{|declare|declare|instantiate}0 a single entity">; +def err_explicit_instantiation_with_definition : Error< + "explicit template instantiation cannot have a definition; if this " + "definition is meant to be an explicit specialization, add '<>' after the " + "'template' keyword">; + +def err_expected_qualified_after_typename : Error< + "expected a qualified name after 'typename'">; +def err_typename_refers_to_non_type_template : Error< + "typename specifier refers to a non-template">; +def err_expected_type_name_after_typename : Error< + "expected an identifier or template-id after '::'">; + +// Language specific pragmas +// - Generic warnings +def warn_pragma_expected_lparen : Warning< + "missing '(' after '#pragma %0' - ignoring">; +def warn_pragma_expected_rparen : Warning< + "missing ')' after '#pragma %0' - ignoring">; +def warn_pragma_expected_identifier : Warning< + "expected identifier in '#pragma %0' - ignored">; +// - #pragma pack +def warn_pragma_pack_invalid_action : Warning< + "unknown action for '#pragma pack' - ignored">; +def warn_pragma_pack_invalid_constant : Warning< + "invalid constant for '#pragma pack', expected %0 - ignored">; +def warn_pragma_pack_malformed : Warning< + "expected integer or identifier in '#pragma pack' - ignored">; +// - #pragma unused +def warn_pragma_unused_expected_var : Warning< + "expected '#pragma unused' argument to be a variable name">; +def warn_pragma_unused_expected_punc : Warning< + "expected ')' or ',' in '#pragma unused'">; + +} // end of Parser diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td new file mode 100644 index 000000000000..672e473678dd --- /dev/null +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -0,0 +1,1822 @@ +//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Semantic Analysis +//===----------------------------------------------------------------------===// + +let Component = "Sema" in { + +// Constant expressions +def err_expr_not_ice : Error< + "expression is not an integer constant expression">; +def ext_expr_not_ice : Extension< + "expression is not integer constant expression " + "(but is allowed as an extension)">; + +def ext_null_pointer_expr_not_ice : Extension< + "null pointer expression is not an integer constant expression " + "(but is allowed as an extension)">; + + + +// Semantic analysis of string and character constant literals. +def ext_predef_outside_function : Warning< + "predefined identifier is only valid inside function">; + +// C99 Designated Initializers +def err_array_designator_negative : Error< + "array designator value '%0' is negative">; +def err_array_designator_empty_range : Error< + "array designator range [%0, %1] is empty">; +def err_array_designator_non_array : Error< + "array designator cannot initialize non-array type %0">; +def err_array_designator_too_large : Error< + "array designator index (%0) exceeds array bounds (%1)">; +def err_field_designator_non_aggr : Error< + "field designator cannot initialize a " + "%select{non-struct, non-union|non-class}0 type %1">; +def err_field_designator_unknown : Error< + "field designator %0 does not refer to any field in type %1">; +def err_field_designator_nonfield : Error< + "field designator %0 does not refer to a non-static data member">; +def note_field_designator_found : Note<"field designator refers here">; +def err_designator_for_scalar_init : Error< + "designator in initializer for scalar type %0">; +def warn_subobject_initializer_overrides : Warning< + "subobject initialization overrides initialization of other fields " + "within its enclosing subobject">; +def warn_initializer_overrides : Warning< + "initializer overrides prior initialization of this subobject">; +def note_previous_initializer : Note< + "previous initialization %select{|with side effects }0is here" + "%select{| (side effects may not occur at run time)}0">; +def err_designator_into_flexible_array_member : Error< + "designator into flexible array member subobject">; +def note_flexible_array_member : Note< + "initialized flexible array member %0 is here">; +def ext_flexible_array_init : Extension< + "flexible array initialization is a GNU extension">; + +// Declarations. +def ext_vla : Extension< + "variable length arrays are a C99 feature, accepted as an extension">; +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_parameter_name_omitted : Error<"parameter name omitted">; +def warn_decl_in_param_list : Warning< + "declaration of %0 will not be visible outside of this function">; + +def warn_implicit_function_decl : Warning< + "implicit declaration of function %0">, + InGroup<ImplicitFunctionDeclare>, DefaultIgnore; +def ext_implicit_function_decl : Extension< + "implicit declaration of function %0 is invalid in C99">, + InGroup<ImplicitFunctionDeclare>; + +def err_ellipsis_first_arg : Error< + "ISO C requires a named argument before '...'">; +def err_declarator_need_ident : Error<"declarator requires an identifier">; +def err_bad_language : Error<"unknown linkage language">; +def warn_use_out_of_scope_declaration : Warning< + "use of out-of-scope declaration of %0">; +def err_inline_non_function : Error< + "'inline' can only appear on functions">; + +def err_invalid_thread : Error< + "'__thread' is only allowed on variable declarations">; +def err_thread_non_global : Error< + "'__thread' variables must have global storage">; +def err_thread_unsupported : Error< + "thread-local storage is unsupported for the current target">; + +/// Built-in functions. +def ext_implicit_lib_function_decl : ExtWarn< + "implicitly declaring C library function '%0' with type %1">; +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 warn_redecl_library_builtin : Warning< + "incompatible redeclaration of library function %0">; +def err_builtin_definition : Error<"definition of builtin function %0">; +def err_types_compatible_p_in_cplusplus : Error< + "__builtin_types_compatible_p is not valid in C++">; + +/// parser diagnostics +def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">; +def err_statically_allocated_object : Error< + "interface type cannot be statically allocated">; +def err_object_cannot_be_passed_returned_by_value : Error< + "interface type %1 cannot be %select{returned|passed}0 by value">; +def warn_enum_value_overflow : Warning<"overflow in enumeration value">; +def warn_pragma_pack_invalid_alignment : Warning< + "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">; +// Follow the MSVC implementation. +def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; +// FIXME: Dehardcode. +def warn_pragma_pack_pop_identifer_and_alignment : Warning< + "specifying both a name and alignment to 'pop' is undefined">; +def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">; + +def warn_pragma_unused_expected_localvar : Warning< + "only local variables can be arguments to '#pragma unused'">; + +/// Objective-C parser diagnostics +def err_duplicate_class_def : Error< + "duplicate interface definition for class %0">; +def err_undef_superclass : Error< + "cannot find interface declaration for %0, superclass of %1">; +def warn_previous_alias_decl : Warning<"previously declared alias is ignored">; +def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; +def warn_undef_interface : Warning<"cannot find interface declaration for %0">; +def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">; +def err_protocol_has_circular_dependency : Error< + "protocol has circular dependency">; +def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; +def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; +def warn_readonly_property : Warning< + "attribute 'readonly' of property %0 restricts attribute " + "'readwrite' of property inherited from %1">; + +def warn_property_attribute : Warning< + "property %0 '%1' attribute does not match the property inherited from %2">; +def warn_property_types_are_incompatible : Warning< + "property type %0 is incompatible with type %1 inherited from %2">; +def err_undef_interface : Error<"cannot find interface declaration for %0">; +def warn_dup_category_def : Warning< + "duplicate definition of category %1 on interface %0">; +def err_conflicting_super_class : Error<"conflicting super class name %0">; +def err_dup_implementation_class : Error<"reimplementation of class %0">; +def err_conflicting_ivar_type : Error< + "instance variable %0 has conflicting type: %1 vs %2">; +def err_conflicting_ivar_bitwidth : Error< + "instance variable %0 has conflicting bitfield width">; +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_undef_method_impl : Warning<"method definition for %0 not found">; + +def warn_conflicting_ret_types : Warning< + "conflicting return type in implementation of %0: %1 vs %2">; + +def warn_conflicting_param_types : Warning< + "conflicting parameter types in implementation of %0: %1 vs %2">; + +def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; +def warn_accessor_property_type_mismatch : Warning< + "type of property %0 does not match type of accessor %1">; +def note_declared_at : Note<"declared at">; +def err_setter_type_void : Error<"type of setter must be void">; +def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; +def err_objc_var_decl_inclass : + Error<"cannot declare variable inside @interface or @protocol">; +def error_missing_method_context : Error< + "missing context for method declaration">; +def err_objc_property_attr_mutually_exclusive : Error< + "property attributes '%0' and '%1' are mutually exclusive">; +def err_objc_property_requires_object : Error< + "property with '%0' attribute must be of object type">; +def warn_objc_property_no_assignment_attribute : Warning< + "no 'assign', 'retain', or 'copy' attribute is specified - " + "'assign' is assumed">; +def warn_objc_property_default_assign_on_object : Warning< + "default property attribute 'assign' not appropriate for non-gc object">; +def warn_property_attr_mismatch : Warning< + "property attribute in continuation class does not match the primary class">; +def warn_objc_property_copy_missing_on_block : Warning< + "'copy' attribute must be specified for the block property " + "when -fobjc-gc-only is specified">; +def err_use_continuation_class : Error< + "attribute of property in continuation class of %0 can only be 'readwrite'">; +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< + "missing context for property implementation declaration">; +def error_bad_property_decl : Error< + "property implementation must have its declaration in interface %0">; +def error_synthesize_category_decl : Error< + "@synthesize not allowed in a category's implementation">; +def error_missing_property_interface : Error< + "property implementation in a category with no category declaration">; +def error_bad_category_property_decl : Error< + "property implementation must have its declaration in the category %0">; +def error_bad_property_context : Error< + "property implementation must be in a class or category implementation">; +def error_missing_property_ivar_decl : Error< + "synthesized property %0 must either be named the same as a compatible" + " ivar or must explicitly name an ivar">; + +def error_synthesized_ivar_yet_not_supported : Error< + "instance variable synthesis not yet supported" + " (need to declare %0 explicitly)">; + +def error_property_ivar_type : Error< + "type of property %0 does not match type of ivar %1">; +def error_ivar_in_superclass_use : Error< + "property %0 attempting to use ivar %1 declared in super class %2">; +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">; +def error_dynamic_property_ivar_decl : Error< + "dynamic property can not have ivar specification">; +def error_duplicate_ivar_use : Error< + "synthesized properties %0 and %1 both claim ivar %2">; +def error_property_implemented : Error<"property %0 is already implemented">; +def warn_objc_property_attr_mutually_exclusive : Warning< + "property attributes '%0' and '%1' are mutually exclusive">, + InGroup<DiagGroup<"readonly-setter-attrs">>, DefaultIgnore; + +// C++ declarations +def err_static_assert_expression_is_not_constant : Error< + "static_assert expression is not an integral constant expression">; +def err_static_assert_failed : Error<"static_assert failed \"%0\"">; + +def err_friend_decl_outside_class : Error< + "'friend' used outside of class">; + +def err_abstract_type_in_decl : Error< + "%select{return|parameter|variable|field}1 type %0 is an abstract class">; +def err_allocation_of_abstract_type : Error< + "allocation of an object of abstract type %0">; + +def err_type_defined_in_type_specifier : Error< + "%0 can not be defined in a type specifier">; +def err_type_defined_in_result_type : Error< + "%0 can not be defined in the result type of a function">; +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">; + +def err_deleted_non_function : Error< + "only functions can have deleted definitions">; +def err_deleted_decl_not_first : Error< + "deleted definition must be first declaration">; + +// C++ exception specifications +def err_exception_spec_in_typedef : Error< + "exception specifications are not allowed in typedefs">; +def err_distant_exception_spec : Error< + "exception specifications are not allowed beyond a single level " + "of indirection">; +def err_incomplete_in_exception_spec : Error< + "%select{|pointer to |reference to }1incomplete type %0 is not allowed " + "in exception specification">; + +// C++ access checking +def err_class_redeclared_with_different_access : Error< + "%0 redeclared with '%1' access">; +def note_previous_access_declaration : Note< + "previously declared '%1' here">; + +// C++ name lookup +def err_incomplete_nested_name_spec : Error< + "incomplete type %0 named in nested name specifier">; + +// C++ class members +def err_storageclass_invalid_for_member : Error< + "storage class specified for a member declaration">; +def err_mutable_function : Error<"'mutable' cannot be applied to functions">; +def err_mutable_reference : Error<"'mutable' cannot be applied to references">; +def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">; +def err_mutable_nonmember : Error< + "'mutable' can only be applied to member variables">; +def err_virtual_non_function : Error< + "'virtual' can only appear on non-static member functions">; +def err_explicit_non_function : Error< + "'explicit' 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_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; +def err_static_out_of_line : Error< + "'static' can only be specified inside the class definition">; +def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">; +def err_not_integral_type_bitfield : Error< + "bit-field %0 has non-integral type %1">; +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">; +def err_member_function_initialization : Error< + "initializer on function does not look like a pure-specifier">; +def err_non_virtual_pure : Error< + "%0 is not virtual and cannot be declared pure">; +def err_implicit_object_parameter_init : Error< + "cannot initialize object parameter of type %0 with an expression " + "of type %1">; + +def err_different_return_type_for_overriding_virtual_function : Error< + "virtual function %0 has a different return type (%1) than the " + "function it overrides (which has return type %2)">; +def note_overridden_virtual_function : Note< + "overridden virtual function is here">; + +def err_covariant_return_inaccessible_base : Error< + "return type of virtual function %2 is not covariant with the return type " + "of the function it overrides " + "(conversion from %0 to inaccessible base class %1)">; +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 " + "%0 to base class %1:%2)">; +def err_covariant_return_not_derived : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 is not derived from %2)">; +def err_covariant_return_type_different_qualifications : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 has different qualifiers than %2)">; +def err_covariant_return_type_class_type_more_qualified : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (class type %1 is more qualified than class " + "type %2">; +// C++ constructors +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_constructor_return_type : Error< + "constructor cannot have a return type">; +def err_constructor_redeclared : Error<"constructor cannot be redeclared">; +def err_constructor_byvalue_arg : Error< + "copy constructor must pass its first argument by reference">; + +// C++ destructors +def err_destructor_not_member : Error< + "destructor must be a non-static member function">; +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_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">; +def err_destructor_variadic : Error<"destructor cannot be variadic">; +def err_destructor_typedef_name : Error< + "destructor cannot be declared using a typedef %0 of the class name">; + +// C++ initialization +def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">; +// FIXME: passing in an English string as %1! +def err_not_reference_to_const_init : Error< + "non-const lvalue reference to type %0 cannot be initialized " + "with a %1 of type %2">; +// FIXME: passing in an English string as %1! +def err_reference_init_drops_quals : Error< + "initialization of reference to type %0 with a %1 of type %2 drops " + "qualifiers">; +def err_reference_var_requires_init : Error< + "declaration of reference variable %0 requires an initializer">; +def err_const_var_requires_init : Error< + "declaration of const variable '%0' requires an initializer">; +def err_init_non_aggr_init_list : Error< + "initialization of non-aggregate type %0 with an initializer list">; +def err_init_reference_member_uninitialized : Error< + "reference member of type %0 uninitialized">; +def note_uninit_reference_member : Note< + "uninitialized reference member is here">; + +// Objective-C++ +def err_objc_decls_may_only_appear_in_global_scope : Error< + "Objective-C declarations may only appear in global scope">; +def err_nsobject_attribute : Error< + "__attribute ((NSObject)) is for pointer types only">; + +// Attributes +def err_attribute_can_be_applied_only_to_symbol_declaration : Error< + "%0 attribute can be applied only to symbol declaration">; +def err_attributes_are_not_compatible : Error< + "%0 and %1 attributes are not compatible">; +def err_attribute_wrong_number_arguments : Error< + "attribute requires %0 argument(s)">; +def err_attribute_missing_parameter_name : Error< + "attribute requires unquoted parameter">; +def err_attribute_invalid_vector_type : Error<"invalid vector type %0">; +def err_attribute_argument_not_int : Error< + "'%0' attribute requires integer constant">; +def err_attribute_argument_n_not_int : Error< + "'%0' attribute requires parameter %1 to be an integer constant">; +def err_attribute_argument_n_not_string : Error< + "'%0' attribute requires parameter %1 to be a string">; +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_nonnull_pointers_only : Error< + "nonnull attribute only applies to pointer arguments">; +def err_format_strftime_third_parameter : Error< + "strftime format attribute requires 3rd parameter to be 0">; +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_attribute_invalid_size : Error< + "vector size not an integral multiple of component size">; +def err_attribute_zero_size : Error<"zero vector size">; +def err_typecheck_vector_not_convertable : Error< + "can't convert between vector values of different size (%0 and %1)">; +def err_typecheck_ext_vector_not_typedef : Error< + "ext_vector_type only applies to types, not variables">; +def err_unsupported_vector_size : Error< + "unsupported type %0 for vector_size attribute, please use on typedef">; +def err_ext_vector_component_exceeds_length : Error< + "vector component access exceeds type %0">; +def err_ext_vector_component_requires_even : Error< + "vector component access invalid for odd-sized type %0">; +def err_ext_vector_component_name_illegal : Error< + "illegal vector component name '%0'">; +def err_attribute_address_space_not_int : Error< + "address space attribute requires an integer constant">; +def err_attribute_address_multiple_qualifiers : Error< + "multiple address spaces specified for type">; +def err_implicit_pointer_address_space_cast : Error< + "illegal implicit cast between two pointers with different address spaces">; +def err_as_qualified_auto_decl : Error< + "automatic variable qualified with an address space">; +def err_attribute_annotate_no_string : Error< + "argument to annotate attribute was not a string literal">; +def err_attribute_aligned_not_power_of_two : Error< + "requested alignment is not a power of 2">; +def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< + "'%0' redeclared without %1 attribute: previous %1 ignored">; +def warn_attribute_ignored : Warning<"%0 attribute ignored">; +def warn_attribute_weak_on_field : Warning< + "__weak attribute cannot be specified on a field declaration">; +def warn_attribute_weak_on_local : Warning< + "__weak attribute cannot be specified on an automatic variable">; +def warn_attribute_weak_import_invalid_on_definition : Warning< + "'weak_import' attribute cannot be specified on a definition">; +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}1 types">; +def warn_gnu_inline_attribute_requires_inline : Warning< + "'gnu_inline' attribute requires function to be marked 'inline'," + " attribute ignored">; + +def warn_attribute_ignored_for_field_of_type : Warning< + "%0 attribute ignored for field of type %1">; +def warn_transparent_union_attribute_field_size_align : Warning< + "%select{alignment|size}0 of field %1 (%2 bits) does not match the " + "%select{alignment|size}0 of the first field in transparent union; " + "transparent_union attribute ignored">; +def note_transparent_union_first_field_size_align : Note< + "%select{alignment|size}0 of first field is %1 bits">; +def warn_transparent_union_attribute_not_definition : Warning< + "transparent_union attribute can only be applied to a union definition; " + "attribute ignored">; +def warn_transparent_union_attribute_floating : Warning< + "first field of a transparent union cannot have floating point or vector " + "type; transparent_union attribute ignored">; +def warn_transparent_union_attribute_zero_fields : Warning< + "transparent union definition must contain at least one field; " + "transparent_union attribute ignored">; +def warn_attribute_type_not_supported : Warning< + "'%0' attribute argument not supported: %1">; +def warn_attribute_unknown_visibility : Warning<"unknown visibility '%1'">; +def err_unknown_machine_mode : Error<"unknown machine mode %0">; +def err_unsupported_machine_mode : Error<"unsupported machine mode %0">; +def err_mode_not_primitive : Error< + "mode attribute only supported for integer and floating-point types">; +def err_mode_wrong_type : Error< + "type of machine mode does not match type of base type">; +def err_attr_wrong_decl : Error< + "'%0' attribute invalid on this declaration, requires typedef or value">; +def warn_attribute_nonnull_no_pointers : Warning< + "'nonnull' attribute applied to function with no pointer arguments">; +def warn_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< + "'sentinel' attribute only supported for variadic %select{functions|blocks}0">; +def err_attribute_sentinel_less_than_zero : Error< + "'sentinel' parameter 1 less than zero">; +def err_attribute_sentinel_not_zero_or_one : Error< + "'sentinel' parameter 2 not 0 or 1">; +def err_attribute_cleanup_arg_not_found : Error< + "'cleanup' argument %0 not found">; +def err_attribute_cleanup_arg_not_function : Error< + "'cleanup' argument %0 is not a function">; +def err_attribute_cleanup_func_must_take_one_arg : Error< + "'cleanup' function %0 must take 1 parameter">; +def err_attribute_cleanup_func_arg_incompatible_type : Error< + "'cleanup' function %0 parameter has type %1 which is incompatible with " + "type %2">; +def err_attribute_regparm_wrong_platform : Error< + "'regparm' is not valid on this platform">; +def err_attribute_regparm_invalid_number : Error< + "'regparm' parameter must be between 0 and %0 inclusive">; + + +// Clang-Specific Attributes +def err_attribute_iboutlet : Error< + "'iboutlet' attribute can only be applied to instance variables or " + "properties">; +def err_attribute_overloadable_not_function : Error< + "'overloadable' attribute can only be applied to a function">; +def err_attribute_overloadable_missing : Error< + "%select{overloaded function|redeclaration of}0 %1 must have the " + "'overloadable' attribute">; +def note_attribute_overloadable_prev_overload : Note< + "previous overload of function is here">; +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">; + +// Function Parameter Semantic Analysis. +def err_param_with_void_type : Error<"argument may not have 'void' type">; +def err_void_only_param : Error< + "'void' must be the first and only parameter if specified">; +def err_void_param_qualified : Error< + "'void' as parameter must not have type qualifiers">; +def err_ident_list_in_fn_declaration : Error< + "a parameter list without types is only allowed in a function definition">; +def ext_param_not_declared : Extension< + "parameter %0 was not declared, defaulting to type 'int'">; +def err_param_typedef_of_void : Error< + "empty parameter list defined with a typedef of 'void' not allowed in C++">; +def err_param_default_argument : Error< + "C does not support default arguments">; +def err_param_default_argument_redefinition : Error< + "redefinition of default argument">; +def err_param_default_argument_missing : Error< + "missing default argument on parameter">; +def err_param_default_argument_missing_name : Error< + "missing default argument on parameter %0">; +def err_param_default_argument_references_param : Error< + "default argument references parameter %0">; +def err_param_default_argument_references_local : Error< + "default argument references local variable %0 of enclosing function">; +def err_param_default_argument_references_this : Error< + "default argument references 'this'">; +def err_param_default_argument_nonfunc : Error< + "default arguments can only be specified for parameters in a function " + "declaration">; + +def ext_param_promoted_not_compatible_with_prototype : ExtWarn< + "promoted type %0 of K&R function parameter is not compatible with the " + "parameter type %1 declared in a previous prototype">; + + +// C++ Overloading Semantic Analysis. +def err_ovl_diff_return_type : Error< + "functions that differ only in their return type cannot be overloaded">; +def err_ovl_static_nonstatic_member : Error< + "static and non-static member functions with the same parameter types " + "cannot be overloaded">; + +def err_ovl_no_viable_function_in_call : Error< + "no matching function for call to %0">; +def err_ovl_no_viable_member_function_in_call : Error< + "no matching member function for call to %0">; +def err_ovl_ambiguous_call : Error< + "call to %0 is ambiguous">; +def err_ovl_deleted_call : Error< + "call to %select{unavailable|deleted}0 function %1">; +def err_ovl_ambiguous_member_call : Error< + "call to member function %0 is ambiguous">; +def err_ovl_deleted_member_call : Error< + "call to %select{unavailable|deleted}0 member function %1">; +def err_ovl_candidate : Note<"candidate function">; +def err_ovl_candidate_deleted : Note< + "candidate function has been explicitly %select{made unavailable|deleted}0">; +def err_ovl_builtin_candidate : Note<"built-in candidate function %0">; +def err_ovl_no_viable_function_in_init : Error< + "no matching constructor for initialization of %0">; +def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; +def err_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_no_viable_oper : Error<"no viable overloaded '%0'">; +def err_ovl_deleted_oper : Error< + "overload resolution selected %select{unavailable|deleted}0 operator '%1'">; + +def err_ovl_no_viable_object_call : Error< + "no matching function for call to object of type %0">; +def err_ovl_ambiguous_object_call : Error< + "call to object of type %0 is ambiguous">; +def err_ovl_deleted_object_call : Error< + "call to %select{unavailable|deleted}0 function call operator in type %1">; +def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">; +def err_member_call_without_object : Error< + "call to non-static member function without an object argument">; + +// C++ Template Declarations +def err_template_param_shadow : Error< + "declaration of %0 shadows template parameter">; +def note_template_param_here : Note<"template parameter is declared here">; +def note_template_export_unsupported : Note< + "exported templates are unsupported">; +def err_template_outside_namespace_or_class_scope : Error< + "templates can only be declared in namespace or class scope">; +def err_template_linkage : Error<"templates must have C++ linkage">; +def err_template_unnamed_class : Error< + "cannot declare a class template with no name">; +def err_template_param_list_different_arity : Error< + "%select{too few|too many}0 template parameters in template " + "%select{|template parameter }1redeclaration">; +def note_template_param_list_different_arity : Note< + "%select{too few|too many}0 template parameters in template template " + "argument">; +def note_template_prev_declaration : Note< + "previous template %select{declaration|template parameter}0 is here">; +def err_template_param_different_kind : Error< + "template parameter has a different kind in template " + "%select{|template parameter }0redeclaration">; +def note_template_param_different_kind : Note< + "template parameter has a different kind in template argument">; +def err_template_nontype_parm_different_type : Error< + "template non-type parameter has a different type %0 in template " + "%select{|template parameter }1redeclaration">; + +def note_template_nontype_parm_different_type : Note< + "template non-type parameter has a different type %0 in template argument">; +def note_template_nontype_parm_prev_declaration : Note< + "previous non-type template parameter with type %0 is here">; +def err_template_nontype_parm_bad_type : Error< + "a non-type template parameter cannot have type %0">; +def err_template_param_default_arg_redefinition : Error< + "template parameter redefines default argument">; +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">; + +// C++ Template Argument Lists +def err_template_arg_list_different_arity : Error< + "%select{too few|too many}0 template arguments for " + "%select{class template|function template|template template parameter" + "|template}1 %2">; +def note_template_decl_here : Note<"template is declared here">; +def note_member_of_template_here : Note<"member is declared here">; +def err_template_arg_must_be_type : Error< + "template argument for template type parameter must be a type">; +def err_template_arg_must_be_expr : Error< + "template argument for non-type template parameter must be an expression">; +def err_template_arg_nontype_ambig : Error< + "template argument for non-type template parameter is treated as type %0">; +def err_template_arg_must_be_template : Error< + "template argument for template template parameter must be a template">; +def err_template_arg_local_type : Error<"template argument uses local type %0">; +def err_template_arg_unnamed_type : Error< + "template argument uses unnamed type">; +def note_template_unnamed_type_here : Note< + "unnamed type used in template argument was declared here">; +def err_template_arg_not_class_template : Error< + "template argument does not refer to a class template">; +def note_template_arg_refers_here_func : Note< + "template argument refers to function template %0, here">; +def err_template_arg_template_params_mismatch : Error< + "template template argument has different template parameters than its " + "corresponding template template parameter">; +def err_template_arg_not_integral_or_enumeral : Error< + "non-type template argument of type %0 must have an integral or enumeration" + " type">; +def err_template_arg_not_ice : Error< + "non-type template argument of type %0 is not an integral constant " + "expression">; +def err_template_arg_not_convertible : Error< + "non-type template argument of type %0 cannot be converted to a value " + "of type %1">; +def err_template_arg_negative : Error< + "non-type template argument provides negative value '%0' for unsigned " + "template parameter of type %1">; +def err_template_arg_too_large : Error< + "non-type template argument value '%0' is too large for template " + "parameter of type %1">; +def err_template_arg_no_ref_bind : Error< + "non-type template parameter of reference type %0 cannot bind to template " + "argument of type %1">; +def err_template_arg_ref_bind_ignores_quals : Error< + "reference binding of non-type template parameter of type %0 to template " + "argument of type %1 ignores qualifiers">; +def err_template_arg_not_object_or_func_form : Error< + "non-type template argument does not directly refer to an object or " + "function">; +def err_template_arg_field : Error< + "non-type template argument refers to non-static data member %0">; +def err_template_arg_method : Error< + "non-type template argument refers to non-static member function %0">; +def err_template_arg_function_not_extern : Error< + "non-template argument refers to function %0 with internal linkage">; +def err_template_arg_object_not_extern : Error< + "non-template argument refers to object %0 that does not have external " + "linkage">; +def note_template_arg_internal_object : Note< + "non-template argument refers to %select{function|object}0 here">; +def note_template_arg_refers_here : Note<"non-template argument refers here">; +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">; + +// C++ class template specialization +def err_template_spec_needs_header : Error< + "template specialization requires 'template<>'">; +def err_template_spec_extra_headers : Error< + "template specialization must have a single 'template<>' header">; +def unsup_template_partial_spec_ordering : Error< + "partial ordering of class template partial specializations is not yet " + "supported">; +def err_template_spec_decl_out_of_scope_global : Error< + "class template specialization of %0 must occur in the global scope">; +def err_template_spec_decl_out_of_scope : Error< + "class template specialization of %0 not in namespace %1">; +def err_template_spec_decl_function_scope : Error< + "%select{class template specialization|explicit instantiation}0 of %1 " + "in function scope">; +def err_template_spec_redecl_out_of_scope : Error< + "%select{class template specialization|explicit instantiation}0 of %1 " + "not in a namespace enclosing %2">; +def err_template_spec_redecl_global_scope : Error< + "%select{class template specialization|explicit instantiation}0 of %1 must " + "occur at global scope">; + +// C++ Template Instantiation +def err_template_recursion_depth_exceeded : Error< + "recursive template instantiation exceeded maximum depth of %0">,DefaultFatal; +def note_template_recursion_depth : Note< + "use -ftemplate-depth-N to increase recursive template instantiation depth">; + +def err_template_instantiate_undefined : Error< + "%select{implicit|explicit}0 instantiation of undefined template %1">; +def err_implicit_instantiate_member_undefined : Error< + "implicit instantiation of undefined member %0">; +def note_template_class_instantiation_here : Note< + "in instantiation of template class %0 requested here">; +def note_template_member_class_here : Note< + "in instantiation of member class %0 requested here">; +def note_template_member_function_here : Note< + "in instantiation of member function %q0 requested here">; +def note_default_arg_instantiation_here : Note< + "in instantiation of default argument for '%0' required here">; +def err_field_instantiates_to_function : Error< + "data member instantiated with function type %0">; +def err_nested_name_spec_non_tag : Error< + "type %0 cannot be used prior to '::' because it has no members">; + +// C++ Explicit Instantiation +def err_explicit_instantiation_duplicate : Error< + "duplicate explicit instantiation of %0">; +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)">; +def note_previous_template_specialization : Note< + "previous template specialization is here">; +def err_explicit_instantiation_enum : Error< + "explicit instantiation of enumeration type %0">; +def err_explicit_instantiation_nontemplate_type : Error< + "explicit instantiation of non-templated type %0">; +def note_nontemplate_decl_here : Note< + "non-templated declaration is here">; +def err_explicit_instantiation_out_of_scope : Error< + "explicit instantiation of %0 not in a namespace enclosing %1">; + +// C++ typename-specifiers +def err_typename_nested_not_found : Error<"no type named %0 in %1">; +def err_typename_nested_not_found_global : Error< + "no type named %0 in the global namespace">; +def err_typename_nested_not_type : Error< + "typename specifier refers to non-type member %0">; +def note_typename_refers_here : Note< + "referenced member %0 is declared here">; + +def err_template_kw_refers_to_non_template : Error< + "%0 following the 'template' keyword does not refer to a template">; +def err_template_kw_refers_to_function_template : Error< + "%0 following the 'template' keyword refers to a function template">; + +def err_unexpected_typedef : Error< + "unexpected type name %0: expected expression">; +def err_unexpected_namespace : Error< + "unexpected namespace name %0: expected expression">; +def err_undeclared_var_use : Error<"use of undeclared identifier %0">; +def err_undeclared_use : Error<"use of undeclared '%0'">; +def warn_deprecated : Warning<"%0 is deprecated">, + InGroup<DiagGroup<"deprecated-declarations">>; +def warn_unavailable : Warning<"%0 is unavailable">; +def note_unavailable_here : Note< + "function has been explicitly marked %select{unavailable|deleted}0 here">; +def warn_not_enough_argument : Warning< + "not enough variable arguments in %0 declaration to fit a sentinel">; +def warn_missing_sentinel : Warning < + "missing sentinel in %select{function call|method dispatch|block call}0">; +def note_sentinel_here : Note< + "%select{function|method|block}0 has been explicitly marked sentinel here">; +def warn_missing_prototype : Warning< + "no previous prototype for function %0">, + InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore; +def err_redefinition : Error<"redefinition of %0">; + +def warn_redefinition_of_typedef : Warning< + "redefinition of typedef %0 is invalid in C">, + InGroup<DiagGroup<"typedef-redefinition"> >, DefaultError; + +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_non_thread_thread : Error< + "non-thread-local declaration of %0 follows thread-local declaration">; +def err_thread_non_thread : Error< + "thread-local declaration of %0 follows non-thread-local declaration">; +def err_redefinition_different_type : Error< + "redefinition of %0 with a different type">; +def err_redefinition_different_kind : Error< + "redefinition of %0 as different kind of symbol">; +def err_redefinition_different_typedef : Error< + "typedef redefinition with different types (%0 vs %1)">; +def err_tag_definition_of_typedef : Error< + "definition of type %0 conflicts with typedef of the same name">; +def err_conflicting_types : Error<"conflicting types for %0">; +def err_nested_redefinition : Error<"nested redefinition of %0">; +def err_use_with_wrong_tag : Error< + "use of %0 with tag type that does not match previous declaration">; +def warn_struct_class_tag_mismatch : Warning< + "%select{struct|class}0 %select{|template}1 %2 was previously declared " + "as a %select{class|struct}0 %select{|template}1">, + InGroup<MismatchedTags>, DefaultIgnore; +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 err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; +def err_duplicate_member : Error<"duplicate member %0">; +def ext_enum_value_not_int : Extension< + "ISO C restricts enumerator values to range of 'int' (%0 is too large)">; +def warn_enum_too_large : Warning< + "enumeration values exceed range of largest integer">; +def warn_illegal_constant_array_size : Extension< + "size of static array must be an integer constant expression">; +def err_vla_decl_in_file_scope : Error< + "variable length array declaration not allowed at file scope">; +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">; +def err_vm_decl_in_file_scope : Error< + "variably modified type declaration not allowed at file scope">; +def err_vm_decl_has_extern_linkage : Error< + "variably modified type declaration can not have 'extern' linkage">; +def err_typecheck_field_variable_size : Error< + "fields must have a constant size: 'variable length array in structure' " + "extension will never be supported">; +def err_vm_func_decl : Error< + "function declaration cannot have variably modified type">; + +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">; +def err_typecheck_invalid_restrict_not_pointer : Error< + "restrict requires a pointer or reference (%0 is invalid)">; +def err_typecheck_invalid_restrict_invalid_pointee : Error< + "pointer to function type %0 may not be 'restrict' qualified">; +def ext_typecheck_zero_array_size : Extension< + "zero size arrays are an extension">; +def err_at_least_one_initializer_needed_to_size_array : Error< + "at least one initializer value required to size array">; +def err_array_size_non_int : Error<"size of array has non-integer type %0">; +def err_init_element_not_constant : Error< + "initializer element is not a compile-time constant">; +def err_block_extern_cant_init : Error< + "'extern' variable cannot have an initializer">; +def warn_extern_init : Warning<"'extern' variable has an initializer">; +def err_variable_object_no_init : Error< + "variable-sized object may not be initialized">; +def err_array_init_list_required : Error< + "initialization with '{...}' expected for array">; +def err_excess_initializers : Error< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def warn_excess_initializers : Warning< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def err_excess_initializers_in_char_array_initializer : Error< + "excess elements in char array initializer">; +def warn_excess_initializers_in_char_array_initializer : Warning< + "excess elements in char array initializer">; +def warn_initializer_string_for_char_array_too_long : Warning< + "initializer-string for char array is too long">; +def warn_braces_around_scalar_init : Warning< + "braces around scalar initializer">; +def err_many_braces_around_scalar_init : Error< + "too many braces around scalar initializer">; +def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; +def err_illegal_initializer : Error< + "illegal initializer (only variables can be initialized)">; +def err_illegal_initializer_type : Error<"illegal initializer type %0">; +def err_implicit_empty_initializer : Error< + "initializer for aggregate with no elements requires explicit braces">; +def err_bitfield_has_negative_width : Error< + "bit-field %0 has negative width (%1)">; +def err_anon_bitfield_has_negative_width : Error< + "anonymous bit-field has negative width (%0)">; +def err_bitfield_has_zero_width : Error<"bit-field %0 has zero width">; +def err_bitfield_width_exceeds_type_size : Error< + "size of bit-field %0 exceeds size of its type (%1 bits)">; +def err_anon_bitfield_width_exceeds_type_size : Error< + "size of anonymous bitfield exceeds size of its type (%0 bits)">; + +def err_redefinition_of_label : Error<"redefinition of label '%0'">; +def err_undeclared_label_use : Error<"use of undeclared label '%0'">; + +def err_goto_into_protected_scope : Error<"illegal goto into protected scope">; +def err_switch_into_protected_scope : Error< + "illegal switch case into protected scope">; +def err_indirect_goto_in_protected_scope : Error< + "illegal indirect goto in protected scope, unknown effect on scopes">; +def err_addr_of_label_in_protected_scope : Error< + "address taken of label in protected scope, jump to it would have " + "unknown effect on scope">; +def note_protected_by_vla_typedef : Note< + "jump bypasses initialization of VLA typedef">; +def note_protected_by_vla : Note< + "jump bypasses initialization of variable length array">; +def note_protected_by_cleanup : Note< + "jump bypasses initialization of declaration with __attribute__((cleanup))">; +def note_protected_by_objc_try : Note< + "jump bypasses initialization of @try block">; +def note_protected_by_objc_catch : Note< + "jump bypasses initialization of @catch block">; +def note_protected_by_objc_finally : Note< + "jump bypasses initialization of @finally block">; +def note_protected_by_objc_synchronized : Note< + "jump bypasses initialization of @synchronized block">; +def note_protected_by_cxx_try : Note< + "jump bypasses initialization of try block">; +def note_protected_by_cxx_catch : Note< + "jump bypasses initialization of catch block">; + +def err_func_returning_array_function : Error< + "function cannot return array or function type %0">; +def err_field_declared_as_function : Error<"field %0 declared as a function">; +def err_field_incomplete : Error<"field has incomplete type %0">; +def ext_variable_sized_type_in_struct : ExtWarn< + "field %0 with variable sized type %1 not at the end of a struct or class is" + " a GNU extension">; + +def err_flexible_array_empty_struct : Error< + "flexible array %0 not allowed in otherwise empty struct">; +def ext_flexible_array_in_struct : Extension< + "%0 may not be nested in a struct due to flexible array member">; +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 err_flexible_array_init_needs_braces : Error< + "flexible array requires brace-enclosed initializer">; +def err_illegal_decl_array_of_functions : Error< + "'%0' declared as array of functions">; +def err_illegal_decl_array_incomplete_type : Error< + "array has incomplete element type %0">; +def err_illegal_decl_array_of_references : Error< + "'%0' declared as array of references">; +def err_array_star_outside_prototype : Error< + "star modifier used outside of function prototype">; +def err_illegal_decl_pointer_to_reference : Error< + "'%0' declared as a pointer to a reference">; +def err_illegal_decl_mempointer_to_void : Error< + "'%0' declared as a member pointer to void">; +def err_illegal_decl_mempointer_in_nonclass : Error< + "'%0' does not point into a class">; +def err_reference_to_void : Error<"cannot form a reference to 'void'">; +def err_qualified_block_pointer_type : Error< + "qualifier specification on block pointer type not allowed">; +def err_nonfunction_block_type : Error< + "block pointer to non-function type is invalid">; +def err_return_block_has_expr : Error<"void block should not return a value">; +def err_block_return_missing_expr : Error< + "non-void block should return a value">; +def err_block_with_return_type_requires_args : Error< + "block with explicit return type requires argument list">; +def err_func_def_incomplete_result : Error< + "incomplete result type %0 in function definition">; + +// Expressions. +def ext_sizeof_function_type : Extension< + "invalid application of 'sizeof' to a function type">; +def ext_sizeof_void_type : Extension< + "invalid application of '%0' to a void type">; +// FIXME: merge with %select +def err_sizeof_incomplete_type : Error< + "invalid application of 'sizeof' to an incomplete type %0">; +def err_alignof_incomplete_type : Error< + "invalid application of '__alignof' to an incomplete type %0">; +def err_sizeof_alignof_bitfield : Error< + "invalid application of '%select{sizeof|__alignof}0' to bitfield">; +def err_offsetof_record_type : Error< + "offsetof requires struct, union, or class type, %0 invalid">; +def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; +def ext_offsetof_extended_field_designator : Extension< + "using extended field designator is an extension">; +def warn_offsetof_non_pod_type : Warning<"offset of on non-POD type %0">, + InGroup<InvalidOffsetof>; + +def warn_floatingpoint_eq : Warning< + "comparing floating point with == or != is unsafe">, + InGroup<DiagGroup<"float-equal">>, DefaultIgnore; + +def err_sizeof_nonfragile_interface : Error< + "invalid application of '%select{alignof|sizeof}1' to interface %0 in " + "non-fragile ABI">; +def err_atdef_nonfragile_interface : Error< + "invalid application of @defs in non-fragile ABI">; +def err_subscript_nonfragile_interface : Error< + "subscript requires size of interface %0, which is not constant in " + "non-fragile ABI">; + +def err_arithmetic_nonfragile_interface : Error< + "arithmetic on pointer to interface %0, which is not a constant size in " + "non-fragile ABI">; + + +def ext_subscript_non_lvalue : Extension< + "ISO C90 does not allow subscripting non-lvalue array">; +def err_typecheck_subscript_value : Error< + "subscripted value is not an array, pointer, or vector">; +def err_typecheck_subscript_not_integer : Error< + "array subscript is not an integer">; +def err_subscript_function_type : Error< + "subscript of pointer to function type %0">; +def err_subscript_incomplete_type : Error< + "subscript of pointer to incomplete type %0">; +def err_typecheck_member_reference_struct_union : Error< + "member reference base type %0 is not a structure or union">; +def err_typecheck_member_reference_ivar : Error< + "%0 does not have a member named %1">; +def err_typecheck_member_reference_arrow : Error< + "member reference type %0 is not a pointer">; +def err_typecheck_member_reference_type : Error< + "cannot refer to type member %0 with '%select{.|->}1'">; +def err_typecheck_member_reference_unknown : Error< + "cannot refer to member %0 with '%select{.|->}1'">; +def note_member_reference_needs_call : Note< + "perhaps you meant to call this function with '()'?">; + +def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; +def err_typecheck_no_member : Error<"no member named %0">; +def err_member_redeclared : Error<"class member cannot be redeclared">; +def err_member_def_does_not_match : Error< + "out-of-line definition does not match any declaration in %0">; +def err_nonstatic_member_out_of_line : Error< + "non-static data member defined out-of-line">; +def err_qualified_typedef_declarator : Error< + "typedef declarator cannot be qualified">; +def err_qualified_param_declarator : Error< + "parameter declarator cannot be qualified">; +def err_out_of_line_declaration : Error< + "out-of-line declaration of a member must be a definition">; +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">; +// FIXME: Improve with %select +def err_typecheck_illegal_increment_decrement : Error< + "cannot modify value of type %0">; +def err_typecheck_arithmetic_incomplete_type : Error< + "arithmetic on pointer to incomplete type %0">; +def err_typecheck_pointer_arith_function_type : Error< + "arithmetic on pointer to function type %0">; +def err_typecheck_pointer_arith_void_type : Error< + "arithmetic on pointer to void type">; +def err_typecheck_decl_incomplete_type : Error< + "variable has incomplete type %0">; +def err_tentative_def_incomplete_type : Error< + "tentative definition has type %0 that is never completed">; +def err_tentative_def_incomplete_type_arr : Error< + "tentative definition has array of type %0 that is never completed">; +def warn_tentative_incomplete_array : Warning< + "tentative array definition assumed to have one element">; + +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">; +def err_unsupported_global_register : Error< + "global register variables are not supported">; +def err_typecheck_sclass_func : Error<"illegal storage class on function">; +def err_static_block_func : Error< + "function declared in block scope cannot have 'static' storage class">; +def err_typecheck_address_of : Error<"address of %0 requested">; +def ext_typecheck_addrof_void : Extension< + "ISO C forbids taking the address of an expression of type 'void'">; +def err_typecheck_invalid_lvalue_addrof : Error< + "address expression must be an lvalue or a function designator">; +def err_typecheck_unary_expr : Error< + "invalid argument type %0 to unary expression">; +def err_typecheck_indirection_requires_pointer : Error< + "indirection requires pointer operand (%0 invalid)">; +def err_typecheck_invalid_operands : Error< + "invalid operands to binary expression (%0 and %1)">; +def err_typecheck_sub_ptr_object : Error< + "subtraction of pointer %0 requires pointee to be a complete object type">; +def err_typecheck_sub_ptr_compatible : Error< + "%0 and %1 are not pointers to compatible types">; +def ext_typecheck_comparison_of_pointer_integer : Warning< + "comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_comparison_of_distinct_pointers : Warning< + "comparison of distinct pointer types (%0 and %1)">; +def ext_typecheck_cond_incompatible_operands : Warning< + "incompatible operand types (%0 and %1)">; +def err_typecheck_comparison_of_distinct_pointers : Error< + "comparison of distinct pointer types (%0 and %1)">; +def err_typecheck_vector_comparison : Error< + "comparison of vector types (%0 and %1) not supported yet">; +def err_typecheck_assign_const : Error<"read-only variable is not assignable">; +def err_stmtexpr_file_scope : Error< + "statement expression not allowed at file scope">; + +def err_invalid_this_use : Error< + "invalid use of 'this' outside of a nonstatic member function">; +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_qualified_typedef_function_type_use : Error< + "a qualified function type cannot be used to declare a nonmember function " + "or a static member function">; + +def err_invalid_non_static_member_use : Error< + "invalid use of nonstatic data member %0">; +def err_invalid_incomplete_type_use : Error< + "invalid use of incomplete type %0">; +def err_builtin_func_cast_more_than_one_arg : Error< + "function-style cast to a builtin type can only take one argument">; +def err_builtin_direct_init_more_than_one_arg : Error< + "initializer of a builtin type can only take one argument">; +def err_value_init_for_array_type : Error< + "array types cannot be value-initialized">; +def warn_printf_nonliteral_noargs : Warning< + "format string is not a string literal (potentially insecure)">, + InGroup<FormatSecurity>; +def warn_printf_nonliteral : Warning< + "format string is not a string literal">, + InGroup<FormatNonLiteral>, DefaultIgnore; + +def err_unexpected_interface : Error< + "unexpected interface name %0: expected expression">; +def err_property_not_found : Error< + "property %0 not found on object of type %1">; +def ext_gnu_void_ptr : Extension< + "use of GNU void* extension">; +def ext_gnu_ptr_func_arith : Extension< + "arithmetic on pointer to function type %0 is a GNU extension">; +def error_readonly_property_assignment : Error< + "assigning to property with 'readonly' attribute not allowed">; +def ext_integer_increment_complex : Extension< + "ISO C does not support '++'/'--' on complex integer type %0">; +def ext_integer_complement_complex : Extension< + "ISO C does not support '~' for complex conjugation of %0">; +def error_nosetter_property_assignment : Error< + "setter method is needed to assign to object using property" " assignment syntax">; + +def ext_freestanding_complex : Extension< + "complex numbers are an extension in a freestanding C99 implementation">; + + +// Obj-c expressions +def warn_root_inst_method_not_found : Warning< + "instance method %0 is being used on 'Class' which is not in the root class">; +def warn_class_method_not_found : Warning< + "method %objcclass0 not found (return type defaults to 'id')">; +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 err_invalid_receiver_to_message : Error< + "invalid receiver to message expression">; +def warn_bad_receiver_type : Warning< + "receiver type %0 is not 'id' or interface pointer, consider " + "casting it to 'id'">; +def err_bad_receiver_type : Error<"bad receiver type %0">; +def error_objc_throw_expects_object : Error< + "@throw requires an Objective-C object type (%0 invalid)">; +def error_objc_synchronized_expects_object : Error< + "@synchronized requires an Objective-C object type (%0 invalid)">; +def error_rethrow_used_outside_catch : Error< + "@throw (rethrow) used outside of a @catch block">; +def err_attribute_multiple_objc_gc : Error< + "multiple garbage collection attributes specified for type">; +def err_catch_param_not_objc_type : Error< + "@catch parameter is not a pointer to an interface type">; +def err_illegal_qualifiers_on_catch_parm : Error< + "illegal qualifiers on @catch parameter">; +def err_illegal_super_cast : Error< + "cannot cast 'super' (it isn't an expression)">; +def warn_setter_getter_impl_required : Warning< + "property %0 requires method %1 to be defined - " + "use @synthesize, @dynamic or provide a method implementation">; +def note_property_impl_required : Note< + "implementation is here">; + + +// C++ casts +def err_bad_cxx_cast_generic : Error<"%0 from %2 to %1 is not allowed">; +def err_bad_cxx_cast_rvalue : Error<"%0 from rvalue to reference type %1">; +def err_bad_cxx_cast_const_away : Error< + "%0 from %2 to %1 casts away constness">; +def err_bad_const_cast_dest : Error< + "const_cast to %0, which is not a reference, pointer-to-object, " + "or pointer-to-data-member">; + +def err_bad_reinterpret_cast_same_type : Error< + "source and destination type of reinterpret_cast are not distinct">; +def ext_reinterpret_cast_fn_obj : Extension< + "reinterpret_cast between pointer-to-function and pointer-to-object is " + "an extension">; + +def err_bad_reinterpret_cast_small_int : Error< + "cast from pointer to smaller type %0 loses information">; +def err_bad_dynamic_cast_not_ref_or_ptr : Error< + "%0 is not a reference or pointer">; +def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; +def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; +def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; +def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; +// FIXME: Display the path somehow better. +def err_ambiguous_base_to_derived_cast : Error< + "ambiguous static_cast from base %0 to derived %1:%2">; +def err_static_downcast_via_virtual : Error< + "cannot cast %0 to %1 via virtual base %2">; +def err_bad_lvalue_to_rvalue_cast : Error< + "cannot cast from lvalue of type %0 to rvalue reference to %1; types are " + "not compatible">; + +// Other C++ expressions +def err_need_header_before_typeid : Error< + "you need to include <typeinfo> before using the 'typeid' operator">; +def err_static_illegal_in_new : Error< + "the 'static' modifier for the array size is not legal in new expressions">; +def err_array_new_needs_size : Error< + "array size must be specified in new expressions">; +def err_bad_new_type : Error< + "cannot allocate %select{function|reference}1 type %0 with new">; +def err_new_incomplete_type : Error< + "allocation of incomplete type %0">; +def err_new_array_nonconst : Error< + "only the first dimension of an allocated array may be non-const">; +def err_array_size_not_integral : Error< + "array size expression must have integral or enumerated type, not %0">; +def err_new_uninitialized_const : Error< + "must provide an initializer if the allocated object is 'const'">; +def err_delete_operand : Error<"cannot delete expression of type %0">; +def warn_delete_incomplete : Warning< + "deleting pointer to incomplete type %0 may cause undefined behaviour">; +def err_decrement_bool : Error<"cannot decrement expression of type bool">; +def warn_increment_bool : Warning< + "incrementing expression of type bool is deprecated">; +def err_catch_incomplete_ptr : Error< + "cannot catch pointer to incomplete type %0">; +def err_catch_incomplete_ref : Error< + "cannot catch reference to incomplete type %0">; +def err_catch_incomplete : Error<"cannot catch incomplete type %0">; +def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; +def err_qualified_catch_declarator : Error< + "exception declarator cannot be qualified">; +def err_early_catch_all : Error<"catch-all handler must come last">; +def err_bad_memptr_rhs : Error< + "right hand operand to %0 has non pointer-to-member type %1">; +def err_bad_memptr_lhs : Error< + "left hand operand to %0 must be a %select{|pointer to }1class " + "compatible with the right hand operand, but is %2">; + +def err_conditional_void_nonvoid : Error< + "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " + "is of type %0">; +def err_conditional_ambiguous : Error< + "conditional expression is ambiguous; %0 can be converted to %1 " + "and vice versa">; +def err_conditional_ambiguous_ovl : Error< + "conditional expression is ambiguous; %0 and %1 can be converted to several " + "common types">; + +def err_throw_incomplete : Error< + "cannot throw object of incomplete type %0">; +def err_throw_incomplete_ptr : Error< + "cannot throw pointer to object of incomplete type %0">; +def err_return_in_constructor_handler : Error< + "return in the catch of a function try block of a constructor is illegal">; + +def err_invalid_use_of_function_type : Error< + "a function type is not allowed here">; +def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; +def err_type_defined_in_condition : Error< + "types may not be defined in conditions">; +def err_typecheck_bool_condition : Error< + "value of type %0 is not contextually convertible to 'bool'">; +def err_expected_class_or_namespace : Error<"expected a class or namespace">; +def err_invalid_declarator_scope : Error< + "definition or redeclaration of %0 not in a namespace enclosing %1">; +def err_invalid_declarator_global_scope : Error< + "definition or redeclaration of %0 cannot name the global scope">; +def err_invalid_declarator_in_function : Error< + "definition or redeclaration of %0 not allowed inside a function">; +def err_not_tag_in_scope : Error< + "%0 does not name a tag member in the specified scope">; + +def warn_value_always_zero : Warning<"%0 is always zero in this context">; +def warn_value_always_false : Warning<"%0 is always false in this context">; + +// assignment related diagnostics (also for argument passing, returning, etc). +// FIXME: %2 is an english string here. +def err_typecheck_convert_incompatible : Error< + "incompatible type %2 %1, expected %0">; +def err_cannot_initialize_decl_noname : Error< + "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 " + "of type %2">; +def err_cannot_initialize_decl : Error< + "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">; +def warn_incompatible_qualified_id : Warning< + "incompatible type %2 %1, expected %0">; +def warn_incompatible_qualified_id_operands : Warning< + "invalid operands to binary expression (%0 and %1)">; +def ext_typecheck_convert_pointer_int : ExtWarn< + "incompatible pointer to integer conversion %2 %1, expected %0">; +def ext_typecheck_convert_int_pointer : ExtWarn< + "incompatible integer to pointer conversion %2 %1, expected %0">; +def ext_typecheck_convert_pointer_void_func : Extension< + "%2 %1 converts between void* and function pointer, expected %0">; +def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< + "pointer types point to integer types with different sign %2 %1, expected %0">, + InGroup<DiagGroup<"pointer-sign">>; +def ext_typecheck_convert_incompatible_pointer : ExtWarn< + "incompatible pointer types %2 %1, expected %0">; +def ext_typecheck_convert_discards_qualifiers : ExtWarn< + "%2 %1 discards qualifiers, expected %0">; +def warn_incompatible_vectors : Warning< + "incompatible vector types %2 %1, expected %0">, + InGroup<VectorConversions>, DefaultIgnore; +def err_int_to_block_pointer : Error< + "invalid conversion %2 integer %1, expected block pointer %0">; +def err_typecheck_comparison_of_distinct_blocks : Error< + "comparison of distinct block types (%0 and %1)">; +def err_typecheck_convert_incompatible_block_pointer : Error< + "incompatible block pointer types %2 %1, expected %0">; + +def err_typecheck_array_not_modifiable_lvalue : Error< + "array type %0 is not assignable">; +def err_typecheck_non_object_not_modifiable_lvalue : Error< + "non-object type %0 is not assignable">; +def err_typecheck_expression_not_modifiable_lvalue : Error< + "expression is not assignable">; +def err_typecheck_incomplete_type_not_modifiable_lvalue : Error< + "incomplete type %0 is not assignable">; +def err_typecheck_lvalue_casts_not_supported : Error< + "assignment to cast is illegal, lvalue casts are not supported">; + +def err_typecheck_duplicate_vector_components_not_mlvalue : Error< + "vector is not assignable (contains duplicate components)">; +def err_block_decl_ref_not_modifiable_lvalue : Error< + "variable is not assignable (missing __block type specifier)">; +def err_typecheck_call_not_function : Error< + "called object type %0 is not a function or function pointer">; +def err_call_incomplete_return : Error< + "return type of called function (%0) is incomplete">; +def err_call_incomplete_argument : Error< + "argument type %0 is incomplete">; +def err_typecheck_call_too_few_args : Error< + "too few arguments to %select{function|block|method}0 call">; +def err_typecheck_call_too_many_args : Error< + "too many arguments to %select{function|block|method}0 call">; +def warn_call_wrong_number_of_arguments : Warning< + "too %select{few|many}0 arguments in call to %1">; +def err_atomic_builtin_must_be_pointer : Error< + "first argument to atomic builtin must be a pointer (%0 invalid)">; +def err_atomic_builtin_must_be_pointer_intptr : Error< + "first argument to atomic builtin must be a pointer to integer or pointer" + " (%0 invalid)">; +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_cannot_pass_objc_interface_to_vararg : Error< + "cannot pass object with interface type %0 by-value through variadic " + "%select{function|block|method}1">; + +def warn_cannot_pass_non_pod_arg_to_vararg : Warning< + "cannot pass object of non-POD type %0 through variadic " + "%select{function|block|method}1; call will abort at runtime">; + +def err_typecheck_closure_too_many_args : Error< + "too many arguments to closure call">; +def err_typecheck_call_invalid_ordered_compare : Error< + "ordered compare requires two args of floating point type (%0 and %1)">; +def err_typecheck_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 ext_typecheck_cast_nonscalar : Extension< + "C99 forbids casting nonscalar type %0 to the same type">; +def ext_typecheck_cast_to_union : Extension<"C99 forbids casts to union type">; +def err_typecheck_cast_to_union_no_type : Error< + "cast to union type from type %0 not present in union">; +def err_cast_pointer_from_non_pointer_int : Error< + "operand of type %0 cannot be cast to a pointer type">; +def err_cast_pointer_to_non_pointer_int : Error< + "pointer cannot be cast to type %0">; +def err_typecheck_expect_scalar_operand : Error< + "operand of type %0 where arithmetic or pointer type is required">; +def err_typecheck_cond_incompatible_operands : Error< + "incompatible operand types (%0 and %1)">; +def err_cast_selector_expr : Error< + "cannot type cast @selector expression">; +def warn_typecheck_cond_incompatible_pointers : Warning< + "pointer type mismatch (%0 and %1)">; +def warn_typecheck_cond_pointer_integer_mismatch : Warning< + "pointer/integer type mismatch in conditional expression (%0 and %1)">; +def err_typecheck_choose_expr_requires_constant : Error< + "'__builtin_choose_expr' requires a constant expression">; +def ext_typecheck_expression_not_constant_but_accepted : Extension< + "expression is not a constant, but is accepted as one by GNU extensions">; +def warn_unused_expr : Warning<"expression result unused">, + InGroup<UnusedValue>; + +// inline asm. +def err_asm_wide_character : Error<"wide string is invalid in 'asm'">; +def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; +def err_asm_invalid_output_constraint : Error< + "invalid output constraint '%0' in asm">; +def err_asm_invalid_lvalue_in_input : Error< + "invalid lvalue in asm input for constraint '%0'">; +def err_asm_invalid_input_constraint : Error< + "invalid input constraint '%0' in asm">; +def err_asm_invalid_type_in_input : Error< + "invalid type %0 in asm input for constraint '%1'">; +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 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">; + +def warn_invalid_asm_cast_lvalue : Warning< + "invalid use of a cast in a inline asm context requiring an l-value: " + "accepted due to -fheinous-gnu-extensions, but clang may remove support " + "for this in the future">; + + + +def err_invalid_conversion_between_vectors : Error< + "invalid conversion between vector type %0 and %1 of different size">; +def err_invalid_conversion_between_vector_and_integer : Error< + "invalid conversion between vector type %0 and integer type %1 " + "of different size">; + +def err_invalid_conversion_between_vector_and_scalar : Error< + "invalid conversion between vector type %0 and scalar type %1">; +def err_overload_expr_requires_non_zero_constant : Error< + "overload requires a non-zero constant expression as first argument">; +def err_overload_incorrect_fntype : Error< + "argument is not a function, or has wrong number of parameters">; + +// FIXME: PASSING TYPES AS STRING. +def err_overload_no_match : Error< + "no matching overload found for arguments of type '%0'">; +def err_overload_multiple_match : Error< + "more than one matching function found in __builtin_overload">; + +// C++ member initializers. +def err_only_constructors_take_base_inits : Error< + "only constructors take base initializers">; + +def err_mem_init_not_member_or_class : Error< + "member initializer %0 does not name a non-static data member or base " + "class">; + +def err_base_init_does_not_name_class : Error< + "constructor initializer %0 does not name a class">; +def err_base_init_direct_and_virtual : Error< + "base class initializer %0 names both a direct base class and an " + "inherited virtual base class">; + +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_constant : Error< + "in-class initializer is not an integral constant expression">; + +// C++ anonymous unions and GNU anonymous structs/unions +def ext_anonymous_union : Extension< + "anonymous unions are a GNU extension in C">; +def ext_anonymous_struct : Extension< + "anonymous structs are a GNU extension">; +def err_anonymous_union_not_static : Error< + "anonymous unions at namespace or global scope must be declared 'static'">; +def err_anonymous_union_with_storage_spec : Error< + "anonymous union at class scope must not have a storage specifier">; +def err_anonymous_struct_not_member : Error< + "anonymous %select{structs|structs and classes}0 must be " + "%select{struct or union|class}0 members">; +def err_anonymous_union_member_redecl : Error< + "member of anonymous union redeclares %0">; +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 err_anonymous_record_with_function : Error< + "functions cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_with_static : Error< + "static members cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_bad_member : Error< + "anonymous %select{struct|union}0 can only contain non-static data members">; +def err_anonymous_record_nonpublic_member : Error< + "anonymous %select{struct|union}0 cannot contain a " + "%select{private|protected}1 data member">; + +// C++ derived classes +def err_base_clause_on_union : Error<"unions cannot have base classes">; +def err_base_must_be_class : Error<"base specifier must name a class">; +def err_union_as_base_class : Error<"unions cannot be base classes">; +def err_incomplete_base_class : Error<"base class has incomplete type">; +def err_duplicate_base_class : Error< + "base class %0 specified more than once as a direct base class">; +// FIXME: better way to display derivation? Pass entire thing into diagclient? +def err_ambiguous_derived_to_base_conv : Error< + "ambiguous conversion from derived class %0 to base class %1:%2">; +def err_ambiguous_memptr_conv : Error< + "ambiguous conversion from pointer to member of %select{base|derived}0 " + "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; + +def err_memptr_conv_via_virtual : Error< + "conversion from pointer to member of class %0 to pointer to member " + "of class %1 via virtual base %2 is not allowed">; + +// C++ access control +def err_conv_to_inaccessible_base : Error< + "conversion from %0 to inaccessible base class %1">; +def note_inheritance_specifier_here : Note< + "'%0' inheritance specifier here">; +def note_inheritance_implicitly_private_here : Note< + "inheritance is implicitly 'private'">; + +// C++ member name lookup +def err_ambiguous_member_multiple_subobjects : Error< + "non-static member %0 found in multiple base-class subobjects of type %1:%2">; +def err_ambiguous_member_multiple_subobject_types : Error< + "member %0 found in multiple base classes of different types">; +def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; +def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; +def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; + +// C++ operator overloading +def err_operator_overload_needs_class_or_enum : Error< + "overloaded %0 must have at least one parameter of class " + "or enumeration type">; + +def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; +def err_operator_overload_static : Error< + "overloaded %0 cannot be a static member function">; +def err_operator_overload_default_arg : Error< + "parameter of overloaded %0 cannot have a default argument">; +def err_operator_overload_must_be : Error< + "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator " + "(has %1 parameter%s1)">; + +def err_operator_overload_must_be_member : Error< + "overloaded %0 must be a non-static member function">; +def err_operator_overload_post_incdec_must_be_int : Error< + "parameter of overloaded post-%select{increment|decrement}1 operator must " + "have type 'int' (not %0)">; + + +// C++ conversion functions +def err_conv_function_not_member : Error< + "conversion function must be a non-static member function">; +def err_conv_function_return_type : Error< + "conversion function cannot have a return type">; +def err_conv_function_with_params : Error< + "conversion function cannot have any parameters">; +def err_conv_function_variadic : Error< + "conversion function cannot be variadic">; +def err_conv_function_to_array : Error< + "conversion function cannot convert to an array type">; +def err_conv_function_to_function : Error< + "conversion function cannot convert to a function type">; +def err_conv_function_redeclared : Error< + "conversion function cannot be redeclared">; +def warn_conv_to_self_not_used : Warning< + "conversion function converting %0 to itself will never be used">; +def warn_conv_to_base_not_used : Warning< + "conversion function converting %0 to its base class %1 will never be used">; +def warn_conv_to_void_not_used : Warning< + "conversion function converting %0 to %1 will never be used">; + +def warn_not_compound_assign : Warning< + "use of unary operator that may be intended as compound assignment (%0=)">; + +// C++0x explicit conversion operators +def warn_explicit_conversion_functions : Warning< + "explicit conversion functions are a C++0x extension">; + +def warn_printf_write_back : Warning< + "use of '%%n' in format string discouraged (potentially insecure)">, + InGroup<FormatSecurity>; +def warn_printf_insufficient_data_args : Warning< + "more '%%' conversions than data arguments">, InGroup<Format>; +def warn_printf_too_many_data_args : Warning< + "more data arguments than '%%' conversions">, InGroup<FormatExtraArgs>; +def warn_printf_invalid_conversion : Warning< + "invalid conversion '%0'">, InGroup<Format>; +def warn_printf_missing_format_string : Warning< + "format string missing">, InGroup<Format>; +def warn_null_arg : Warning< + "null passed to a callee which requires a non-null argument">, + InGroup<NonNull>; +def warn_printf_empty_format_string : Warning< + "format string is empty">, InGroup<FormatZeroLength>; +def warn_printf_format_string_is_wide_literal : Warning< + "format string should not be a wide string">, InGroup<Format>; +def warn_printf_format_string_contains_null_char : Warning< + "format string contains '\\0' within the string body">, InGroup<Format>; +def warn_printf_asterisk_width_missing_arg : Warning< + "'*' specified field width is missing a matching 'int' argument">; +def warn_printf_asterisk_precision_missing_arg : Warning< + "'.*' specified field precision is missing a matching 'int' argument">; +def warn_printf_asterisk_width_wrong_type : Warning< + "field width should have type 'int', but argument has type %0">, + InGroup<Format>; +def warn_printf_asterisk_precision_wrong_type : Warning< + "field precision should have type 'int', but argument has type %0">, + InGroup<Format>; + +// CHECK: returning address/reference of stack memory +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">; + + +// For non-floating point, expressions of the form x == x or x != x +// should result in a warning, since these always evaluate to a constant. +def warn_selfcomparison : Warning< + "self-comparison always results in a constant value">; +def warn_stringcompare : Warning< + "result of comparison against %select{a string literal|@encode}0 is " + "unspecified (use strcmp instead)">; + + + +// Blocks +def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" + " or pick a deployment target that supports them">; +def err_expected_block_lbrace : Error<"expected '{' in block literal">; +def err_goto_in_block : Error< + "goto not allowed 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_ret_local_block : Error< + "returning block that lives on the local stack">; + +// CFString checking +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">; + +// Statements. +def err_continue_not_in_loop : Error< + "'continue' statement not in loop statement">; +def err_break_not_in_loop_or_switch : Error< + "'break' statement not in loop or switch statement">; +def err_default_not_in_switch : Error< + "'default' statement not in switch statement">; +def err_case_not_in_switch : Error<"'case' statement not in switch statement">; +def warn_case_value_overflow : Warning< + "overflow converting case value to switch condition type (%0 to %1)">; +def err_duplicate_case : Error<"duplicate case value '%0'">; +def warn_case_empty_range : Warning<"empty case range specified">; +def err_typecheck_statement_requires_scalar : Error< + "statement requires expression of scalar type (%0 invalid)">; +def err_typecheck_statement_requires_integer : Error< + "statement requires expression of integer type (%0 invalid)">; +def err_multiple_default_labels_defined : Error< + "multiple default labels in one switch">; +def warn_empty_if_body : Warning< + "if statement has empty body">; +def err_va_start_used_in_non_variadic_function : Error< + "'va_start' used in function with fixed args">; +def warn_second_parameter_of_va_start_not_last_named_argument : Warning< + "second parameter of 'va_start' not last named argument">; +def err_first_argument_to_va_arg_not_of_type_va_list : Error< + "first argument to 'va_arg' is of type %0 and not 'va_list'">; + +def warn_return_missing_expr : Warning< + "non-void %select{function|method}1 %0 should return a value">, + InGroup<ReturnType>; +def ext_return_missing_expr : ExtWarn< + "non-void %select{function|method}1 %0 should return a value">, + InGroup<ReturnType>; +def ext_return_has_expr : ExtWarn< + "void %select{function|method}1 %0 should not return a value">, + InGroup<ReturnType>; +def ext_return_has_void_expr : Extension< + "void %select{function|method}1 %0 should not return void expression">; +def warn_noreturn_function_has_return_expr : Warning< + "function %0 declared 'noreturn' should not return">, DefaultError, + InGroup<DiagGroup<"invalid-noreturn">>; +def err_noreturn_block_has_return_expr : Error< + "block declared 'noreturn' should not return">; +def err_block_on_nonlocal : Error< + "__block attribute not allowed, only allowed on local variables">; +def err_block_on_vm : Error< + "__block attribute not allowed on declaration with a variably modified type">; + +def err_shufflevector_non_vector : Error< + "first two arguments to __builtin_shufflevector must be vectors">; +def err_shufflevector_incompatible_vector : Error< + "first two arguments to __builtin_shufflevector must have the same type">; +def err_shufflevector_nonconstant_argument : Error< + "index for __builtin_shufflevector must be a constant integer">; +def err_shufflevector_argument_too_large : Error< + "index for __builtin_shufflevector must be less than the total number " + "of vector elements">; + + +def err_stack_const_level : Error< + "level argument for a stack address builtin must be constant">; + +def err_prefetch_invalid_argument : Error< + "argument to __builtin_prefetch must be a constant integer">; +def err_argument_invalid_range : Error< + "argument should be a value from %0 to %1">; + +def err_object_size_invalid_argument : Error< + "argument to __builtin_object_size must be a constant integer">; + +def err_builtin_longjmp_invalid_val : Error< + "argument to __builtin_longjmp must be a constant 1">; + +def ext_mixed_decls_code : Extension< + "ISO C90 forbids mixing declarations and code">; +def err_non_variable_decl_in_for : Error< + "declaration of non-local variable in 'for' loop">; +def err_toomany_element_decls : Error< + "only one element declaration is allowed">; +def err_selector_element_not_lvalue : Error< + "selector element is not a valid lvalue">; +def err_selector_element_type : Error< + "selector element type %0 is not a valid object">; +def err_collection_expr_type : Error< + "collection expression type %0 is not a valid object">; + +// Type +def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; +def warn_receiver_forward_class : Warning< + "receiver %0 is a forward class and corresponding @interface may not exist">; +def note_method_sent_forward_class : Note<"method %0 is used for the forward class">; +def warn_missing_declspec : Warning< + "declaration specifier missing, defaulting to 'int'">; +def warn_missing_type_specifier : Warning< + "type specifier missing, defaults to 'int'">, + InGroup<ImplicitInt>; +def err_decimal_unsupported : Error< + "GNU decimal type extension not supported">; +def err_missing_type_specifier : Error< + "C++ requires a type specifier for all declarations">; +def err_missing_param_declspec : Error< + "parameter requires a declaration specifier">; +def err_objc_array_of_interfaces : Error< + "array of interface %0 is invalid (probably should be an array of pointers)">; +def ext_c99_array_usage : Extension< + "use of C99-specific array features, accepted as an extension">; +def err_invalid_protocol_qualifiers : Error< + "invalid protocol qualifiers on non-ObjC type">; +def err_qualified_class_unsupported : Error< + "protocol qualified 'Class' is unsupported">; +def warn_ivar_use_hidden : Warning< + "local declaration of %0 hides instance variable">; +def error_ivar_use_in_class_method : Error< + "instance variable %0 accessed in class method">; +def error_private_ivar_access : Error<"instance variable %0 is private">; +def error_protected_ivar_access : Error<"instance variable %0 is protected">; +def warn_maynot_respond : Warning<"%0 may not respond to %1">; +def warn_attribute_method_def : Warning< + "method attribute can only be specified on method declarations">; + + +} diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h new file mode 100644 index 000000000000..d6a0cf34d9fa --- /dev/null +++ b/include/clang/Basic/FileManager.h @@ -0,0 +1,178 @@ +//===--- FileManager.h - File System Probing and Caching --------*- 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 FileManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FILEMANAGER_H +#define LLVM_CLANG_FILEMANAGER_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Config/config.h" // for mode_t +#include <map> +#include <set> +#include <string> +// FIXME: Enhance libsystem to support inode and other fields in stat. +#include <sys/types.h> +#include <sys/stat.h> + +namespace clang { +class FileManager; + +/// DirectoryEntry - Cached information about one directory on the disk. +/// +class DirectoryEntry { + const char *Name; // Name of the directory. + friend class FileManager; +public: + DirectoryEntry() : Name(0) {} + const char *getName() const { return Name; } +}; + +/// FileEntry - Cached information about one file on the disk. +/// +class FileEntry { + const char *Name; // Name of the file. + off_t Size; // File size in bytes. + time_t ModTime; // Modification time of file. + const DirectoryEntry *Dir; // Directory file lives in. + unsigned UID; // A unique (small) ID for the file. + 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'. + friend class FileManager; +public: + FileEntry(dev_t device, ino_t inode, mode_t m) + : Name(0), Device(device), Inode(inode), FileMode(m) {} + // Add a default constructor for use with llvm::StringMap + FileEntry() : Name(0), Device(0), Inode(0), FileMode(0) {} + + const char *getName() const { return Name; } + off_t getSize() const { return Size; } + unsigned getUID() const { return UID; } + ino_t getInode() const { return Inode; } + dev_t getDevice() const { return Device; } + time_t getModificationTime() const { return ModTime; } + mode_t getFileMode() const { return FileMode; } + + /// getDir - Return the directory the file lives in. + /// + const DirectoryEntry *getDir() const { return Dir; } + + bool operator<(const FileEntry& RHS) const { + return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode); + } +}; + +// FIXME: This is a lightweight shim that is used by FileManager to cache +// 'stat' system calls. We will use it with PTH to identify if caching +// stat calls in PTH files is a performance win. +class StatSysCallCache { +public: + virtual ~StatSysCallCache() {} + virtual int stat(const char *path, struct stat *buf) = 0; +}; + +/// \brief A stat listener 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 { + + class UniqueDirContainer; + class UniqueFileContainer; + + /// UniqueDirs/UniqueFiles - Cache for existing directories/files. + /// + UniqueDirContainer &UniqueDirs; + UniqueFileContainer &UniqueFiles; + + /// DirEntries/FileEntries - This is a cache of directory/file entries we have + /// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above. + /// + llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries; + llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries; + + /// NextFileUID - Each FileEntry we create is assigned a unique ID #. + /// + unsigned NextFileUID; + + // Statistics. + unsigned NumDirLookups, NumFileLookups; + unsigned NumDirCacheMisses, NumFileCacheMisses; + + // Caching. + llvm::OwningPtr<StatSysCallCache> StatCache; + + int stat_cached(const char* path, struct stat* buf) { + return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf); + } + +public: + FileManager(); + ~FileManager(); + + /// setStatCache - Installs the provided StatSysCallCache object within + /// the FileManager. Ownership of this object is transferred to the + /// FileManager. + void setStatCache(StatSysCallCache *statCache) { + StatCache.reset(statCache); + } + + /// getDirectory - Lookup, cache, and verify the specified directory. This + /// returns null if the directory doesn't exist. + /// + const DirectoryEntry *getDirectory(const std::string &Filename) { + return getDirectory(&Filename[0], &Filename[0] + Filename.size()); + } + const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd); + + /// getFile - Lookup, cache, and verify the specified file. This returns null + /// if the file doesn't exist. + /// + const FileEntry *getFile(const std::string &Filename) { + return getFile(&Filename[0], &Filename[0] + Filename.size()); + } + const FileEntry *getFile(const char *FilenameStart, + const char *FilenameEnd); + + void PrintStats() const; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h new file mode 100644 index 000000000000..57cd31163144 --- /dev/null +++ b/include/clang/Basic/IdentifierTable.h @@ -0,0 +1,561 @@ +//===--- IdentifierTable.h - Hash table for identifier lookup ---*- 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 IdentifierInfo, IdentifierTable, and Selector +// interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H +#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H + +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <string> +#include <cassert> + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class LangOptions; + class IdentifierInfo; + class IdentifierTable; + class SourceLocation; + class MultiKeywordSelector; // private class used by Selector + class DeclarationName; // AST class that stores declaration names + + /// IdentifierLocPair - A simple pair of identifier info and location. + typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair; + + +/// IdentifierInfo - One of these records is kept for each identifier that +/// is lexed. This contains information about whether the token was #define'd, +/// is a language keyword, or if it is a front-end token of some sort (e.g. a +/// variable or function name). The preprocessor keeps this information in a +/// set, and all tok::identifier tokens have a pointer to one of these. +class IdentifierInfo { + // Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a + // signed char and TokenKinds > 127 won't be handled correctly. + unsigned TokenID : 8; // Front-end token ID or tok::identifier. + // 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; + 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. + bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword. + bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier". + // 9 bits left in 32-bit word. + void *FETokenInfo; // Managed by the language front-end. + llvm::StringMapEntry<IdentifierInfo*> *Entry; + + IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE. + void operator=(const IdentifierInfo&); // NONASSIGNABLE. + + friend class IdentifierTable; + +public: + IdentifierInfo(); + + + /// isStr - Return true if this is the identifier for the specified string. + /// This is intended to be used for string literals only: II->isStr("foo"). + template <std::size_t StrLen> + bool isStr(const char (&Str)[StrLen]) const { + return getLength() == StrLen-1 && !memcmp(getName(), Str, StrLen-1); + } + + /// getName - Return the actual string for this identifier. The returned + /// string is properly null terminated. + /// + const char *getName() const { + if (Entry) return Entry->getKeyData(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + return ((std::pair<IdentifierInfo, const char*>*) this)->second; + } + + /// getLength - Efficiently return the length of this identifier info. + /// + unsigned getLength() const { + if (Entry) return Entry->getKeyLength(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + const char* p = ((std::pair<IdentifierInfo, const char*>*) this)->second-2; + return (((unsigned) p[0]) + | (((unsigned) p[1]) << 8)) - 1; + } + + /// hasMacroDefinition - Return true if this identifier is #defined to some + /// other value. + bool hasMacroDefinition() const { + return HasMacro; + } + void setHasMacroDefinition(bool Val) { + if (HasMacro == Val) return; + + HasMacro = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// get/setTokenID - If this is a source-language token (e.g. 'for'), this API + /// can be used to cause the lexer to map identifiers to source-language + /// tokens. + tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; } + void setTokenID(tok::TokenKind ID) { TokenID = ID; } + + /// getPPKeywordID - Return the preprocessor keyword ID for this identifier. + /// For example, "define" will return tok::pp_define. + tok::PPKeywordKind getPPKeywordID() const; + + /// getObjCKeywordID - Return the Objective-C keyword ID for the this + /// identifier. For example, 'class' will return tok::objc_class if ObjC is + /// enabled. + tok::ObjCKeywordKind getObjCKeywordID() const { + if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS) + return tok::ObjCKeywordKind(ObjCOrBuiltinID); + else + return tok::objc_not_keyword; + } + void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; } + + /// getBuiltinID - Return a value indicating whether this is a builtin + /// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target. + /// 2+ are specific builtin functions. + unsigned getBuiltinID() const { + if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS) + return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; + else + return 0; + } + void setBuiltinID(unsigned ID) { + ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS; + assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID + && "ID too large for field!"); + } + + unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; } + void setObjCOrBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID; } + + /// get/setExtension - Initialize information about whether or not this + /// language token is an extension. This controls extension warnings, and is + /// only valid if a custom token ID is set. + bool isExtensionToken() const { return IsExtension; } + void setIsExtensionToken(bool Val) { + IsExtension = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the + /// Preprocessor will emit an error every time this token is used. + void setIsPoisoned(bool Value = true) { + IsPoisoned = Value; + if (Value) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// isPoisoned - Return true if this token has been poisoned. + bool isPoisoned() const { return IsPoisoned; } + + /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether + /// this identifier is a C++ alternate representation of an operator. + void setIsCPlusPlusOperatorKeyword(bool Val = true) { + IsCPPOperatorKeyword = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } + + /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to + /// associate arbitrary metadata with this token. + template<typename T> + T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); } + void setFETokenInfo(void *T) { FETokenInfo = T; } + + /// isHandleIdentifierCase - Return true if the Preprocessor::HandleIdentifier + /// must be called on a token of this identifier. If this returns false, we + /// know that HandleIdentifier will not affect the token. + bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; } + +private: + /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does + /// several special (but rare) things to identifiers of various sorts. For + /// example, it changes the "for" keyword token from tok::identifier to + /// tok::for. + /// + /// This method is very tied to the definition of HandleIdentifier. Any + /// change to it should be reflected here. + void RecomputeNeedsHandleIdentifier() { + NeedsHandleIdentifier = + (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() | + isExtensionToken()); + } +}; + +/// IdentifierInfoLookup - An abstract class used by IdentifierTable that +/// provides an interface for performing lookups from strings +/// (const char *) to IdentiferInfo objects. +class IdentifierInfoLookup { +public: + virtual ~IdentifierInfoLookup(); + + /// get - Return the identifier token info for the specified named identifier. + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// be found. + virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0; +}; + +/// \brief An abstract class used to resolve numerical identifier +/// references (meaningful only to some external source) into +/// IdentifierInfo pointers. +class ExternalIdentifierLookup { +public: + virtual ~ExternalIdentifierLookup(); + + /// \brief Return the identifier associated with the given ID number. + /// + /// The ID 0 is associated with the NULL identifier. + virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0; +}; + +/// IdentifierTable - This table implements an efficient mapping from strings to +/// IdentifierInfo nodes. It has no other purpose, but this is an +/// extremely performance-critical piece of the code, as each occurrance of +/// every identifier goes through here when lexed. +class IdentifierTable { + // Shark shows that using MallocAllocator is *much* slower than using this + // BumpPtrAllocator! + typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy; + HashTableTy HashTable; + + IdentifierInfoLookup* ExternalLookup; + +public: + /// IdentifierTable ctor - Create the identifier table, populating it with + /// info about the language keywords for the language specified by LangOpts. + IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup* externalLookup = 0); + + /// \brief Set the external identifier lookup mechanism. + void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) { + ExternalLookup = IILookup; + } + + llvm::BumpPtrAllocator& getAllocator() { + return HashTable.getAllocator(); + } + + /// get - Return the identifier token info for the specified named identifier. + /// + IdentifierInfo &get(const char *NameStart, const char *NameEnd) { + llvm::StringMapEntry<IdentifierInfo*> &Entry = + HashTable.GetOrCreateValue(NameStart, NameEnd); + + IdentifierInfo *II = Entry.getValue(); + if (II) return *II; + + // No entry; if we have an external lookup, look there first. + if (ExternalLookup) { + II = ExternalLookup->get(NameStart, NameEnd); + if (II) { + // Cache in the StringMap for subsequent lookups. + Entry.setValue(II); + return *II; + } + } + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + Entry.setValue(II); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + return *II; + } + + /// \brief Creates a new IdentifierInfo from the given string. + /// + /// This is a lower-level version of get() that requires that this + /// identifier not be known previously and that does not consult an + /// external source for identifiers. In particular, external + /// identifier sources can use this routine to build IdentifierInfo + /// nodes and then introduce additional information about those + /// identifiers. + IdentifierInfo &CreateIdentifierInfo(const char *NameStart, + const char *NameEnd) { + llvm::StringMapEntry<IdentifierInfo*> &Entry = + HashTable.GetOrCreateValue(NameStart, NameEnd); + + IdentifierInfo *II = Entry.getValue(); + assert(!II && "IdentifierInfo already exists"); + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + Entry.setValue(II); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + return *II; + } + + IdentifierInfo &get(const char *Name) { + return get(Name, Name+strlen(Name)); + } + IdentifierInfo &get(const std::string &Name) { + // Don't use c_str() here: no need to be null terminated. + const char *NameBytes = Name.data(); + return get(NameBytes, NameBytes+Name.size()); + } + + typedef HashTableTy::const_iterator iterator; + typedef HashTableTy::const_iterator const_iterator; + + iterator begin() const { return HashTable.begin(); } + iterator end() const { return HashTable.end(); } + unsigned size() const { return HashTable.size(); } + + /// PrintStats - Print some statistics to stderr that indicate how well the + /// hashing is doing. + void PrintStats() const; + + void AddKeywords(const LangOptions &LangOpts); +}; + +/// Selector - This smart pointer class efficiently represents Objective-C +/// method names. This class will either point to an IdentifierInfo or a +/// MultiKeywordSelector (which is private). This enables us to optimize +/// selectors that take no arguments and selectors that take 1 argument, which +/// accounts for 78% of all selectors in Cocoa.h. +class Selector { + friend class DiagnosticInfo; + + enum IdentifierInfoFlag { + // MultiKeywordSelector = 0. + ZeroArg = 0x1, + OneArg = 0x2, + ArgFlags = ZeroArg|OneArg + }; + uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. + + Selector(IdentifierInfo *II, unsigned nArgs) { + InfoPtr = reinterpret_cast<uintptr_t>(II); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + assert(nArgs < 2 && "nArgs not equal to 0/1"); + InfoPtr |= nArgs+1; + } + Selector(MultiKeywordSelector *SI) { + InfoPtr = reinterpret_cast<uintptr_t>(SI); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + } + + IdentifierInfo *getAsIdentifierInfo() const { + if (getIdentifierInfoFlag()) + return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags); + return 0; + } + unsigned getIdentifierInfoFlag() const { + return InfoPtr & ArgFlags; + } + +public: + friend class SelectorTable; // only the SelectorTable can create these + friend class DeclarationName; // and the AST's DeclarationName. + + /// The default ctor should only be used when creating data structures that + /// will contain selectors. + Selector() : InfoPtr(0) {} + Selector(uintptr_t V) : InfoPtr(V) {} + + /// operator==/!= - Indicate whether the specified selectors are identical. + bool operator==(Selector RHS) const { + return InfoPtr == RHS.InfoPtr; + } + bool operator!=(Selector RHS) const { + return InfoPtr != RHS.InfoPtr; + } + void *getAsOpaquePtr() const { + return reinterpret_cast<void*>(InfoPtr); + } + + /// \brief Determine whether this is the empty selector. + bool isNull() const { return InfoPtr == 0; } + + // Predicates to identify the selector type. + bool isKeywordSelector() const { + return getIdentifierInfoFlag() != ZeroArg; + } + bool isUnarySelector() const { + return getIdentifierInfoFlag() == ZeroArg; + } + unsigned getNumArgs() const; + IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; + + /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return + /// it as an std::string. + std::string getAsString() const; + + static Selector getEmptyMarker() { + return Selector(uintptr_t(-1)); + } + static Selector getTombstoneMarker() { + return Selector(uintptr_t(-2)); + } +}; + +/// SelectorTable - This table allows us to fully hide how we implement +/// multi-keyword caching. +class SelectorTable { + void *Impl; // Actually a SelectorTableImpl + SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT + void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT +public: + SelectorTable(); + ~SelectorTable(); + + /// getSelector - This can create any sort of selector. NumArgs indicates + /// whether this is a no argument selector "foo", a single argument selector + /// "foo:" or multi-argument "foo:bar:". + Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); + + Selector getUnarySelector(IdentifierInfo *ID) { + return Selector(ID, 1); + } + Selector getNullarySelector(IdentifierInfo *ID) { + return Selector(ID, 0); + } + + /// constructSetterName - Return the setter name for the given + /// identifier, i.e. "set" + Name where the initial character of Name + /// has been capitalized. + static Selector constructSetterName(IdentifierTable &Idents, + SelectorTable &SelTable, + const IdentifierInfo *Name) { + llvm::SmallString<100> SelectorName; + SelectorName = "set"; + SelectorName.append(Name->getName(), Name->getName()+Name->getLength()); + SelectorName[3] = toupper(SelectorName[3]); + IdentifierInfo *SetterName = + &Idents.get(SelectorName.data(), + SelectorName.data() + SelectorName.size()); + return SelTable.getUnarySelector(SetterName); + } +}; + +/// DeclarationNameExtra - Common base of the MultiKeywordSelector, +/// CXXSpecialName, and CXXOperatorIdName classes, all of which are +/// private classes that describe different kinds of names. +class DeclarationNameExtra { +public: + /// ExtraKind - The kind of "extra" information stored in the + /// DeclarationName. See @c ExtraKindOrNumArgs for an explanation of + /// how these enumerator values are used. + enum ExtraKind { + CXXConstructor = 0, + CXXDestructor, + CXXConversionFunction, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + CXXOperator##Name, +#include "clang/Basic/OperatorKinds.def" + CXXUsingDirective, + NUM_EXTRA_KINDS + }; + + /// ExtraKindOrNumArgs - Either the kind of C++ special name or + /// operator-id (if the value is one of the CXX* enumerators of + /// ExtraKind), in which case the DeclarationNameExtra is also a + /// CXXSpecialName (for CXXConstructor, CXXDestructor, or + /// CXXConversionFunction) or CXXOperatorIdName, it may be also + /// name common to C++ using-directives (CXXUsingDirective), otherwise + /// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// arguments in the Objective-C selector, in which case the + /// DeclarationNameExtra is also a MultiKeywordSelector. + unsigned ExtraKindOrNumArgs; +}; + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that Selectors can be used as keys in DenseMap and +/// DenseSets. +template <> +struct DenseMapInfo<clang::Selector> { + static inline clang::Selector getEmptyKey() { + return clang::Selector::getEmptyMarker(); + } + static inline clang::Selector getTombstoneKey() { + return clang::Selector::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::Selector S); + + static bool isEqual(clang::Selector LHS, clang::Selector RHS) { + return LHS == RHS; + } + + static bool isPod() { return true; } +}; + +// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which +// are not guaranteed to be 8-byte aligned. +template<> +class PointerLikeTypeTraits<clang::IdentifierInfo*> { +public: + static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { + return P; + } + static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { + return static_cast<clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +template<> +class PointerLikeTypeTraits<const clang::IdentifierInfo*> { +public: + static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { + return P; + } + static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) { + return static_cast<const clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +} // end namespace llvm +#endif diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h new file mode 100644 index 000000000000..92370cdd9efc --- /dev/null +++ b/include/clang/Basic/LangOptions.h @@ -0,0 +1,157 @@ +//===--- LangOptions.h - C Language Family Language 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 LangOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LANGOPTIONS_H +#define LLVM_CLANG_LANGOPTIONS_H + +namespace clang { + +/// LangOptions - This class keeps track of the various options that can be +/// enabled, which controls the dialect of C that is accepted. +class LangOptions { +public: + unsigned Trigraphs : 1; // Trigraphs in source files. + unsigned BCPLComment : 1; // BCPL-style '//' comments. + unsigned DollarIdents : 1; // '$' allowed in identifiers. + unsigned AsmPreprocessor : 1; // Preprocessor in asm mode. + unsigned GNUMode : 1; // True in gnu99 mode false in c99 mode (etc) + unsigned ImplicitInt : 1; // C89 implicit 'int'. + unsigned Digraphs : 1; // C94, C99 and C++ + unsigned HexFloats : 1; // C99 Hexadecimal float constants. + unsigned C99 : 1; // C99 Support + unsigned Microsoft : 1; // Microsoft extensions. + unsigned CPlusPlus : 1; // C++ Support + unsigned CPlusPlus0x : 1; // C++0x Support + unsigned CXXOperatorNames : 1; // Treat C++ operator names as keywords. + + unsigned ObjC1 : 1; // Objective-C 1 support enabled. + unsigned ObjC2 : 1; // Objective-C 2 support enabled. + unsigned ObjCSenderDispatch: 1; // Objective-C 2 three-dimensional dispatch + // enabled. + unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled + + unsigned PascalStrings : 1; // Allow Pascal strings + unsigned WritableStrings : 1; // Allow writable strings + unsigned LaxVectorConversions : 1; + unsigned Exceptions : 1; // Support exception handling. + + unsigned NeXTRuntime : 1; // Use NeXT runtime. + unsigned Freestanding : 1; // Freestanding implementation + unsigned NoBuiltin : 1; // Do not use builtin functions (-fno-builtin) + + unsigned ThreadsafeStatics : 1; // Whether static initializers are protected + // by locks. + unsigned Blocks : 1; // block extension to C + unsigned EmitAllDecls : 1; // Emit all declarations, even if + // they are unused. + unsigned MathErrno : 1; // Math functions must respect errno + // (modulo the platform support). + + unsigned OverflowChecking : 1; // Extension to call a handler function when + // signed integer arithmetic overflows. + + unsigned HeinousExtensions : 1; // Extensions that we really don't like and + // may be ripped out at any time. + + unsigned Optimize : 1; // Whether __OPTIMIZE__ should be defined. + unsigned OptimizeSize : 1; // Whether __OPTIMIZE_SIZE__ should be + // defined. + unsigned Static : 1; // Should __STATIC__ be defined (as + // opposed to __DYNAMIC__). + unsigned PICLevel : 2; // The value for __PIC__, if non-zero. + + unsigned GNUInline : 1; // Should GNU inline semantics be + // used (instead of C99 semantics). + unsigned NoInline : 1; // Should __NO_INLINE__ be defined. + + unsigned ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout + // for __weak/__strong ivars. + + unsigned AccessControl : 1; // Whether C++ access control should + // be enabled. +private: + unsigned GC : 2; // Objective-C Garbage Collection modes. We declare + // this enum as unsigned because MSVC insists on making enums + // signed. Set/Query this value using accessors. + unsigned SymbolVisibility : 3; // Symbol's visibility. + + /// The user provided name for the "main file", if non-null. This is + /// useful in situations where the input file name does not match + /// the original input file, for example with -save-temps. + const char *MainFileName; + +public: + unsigned InstantiationDepth; // Maximum template instantiation depth. + + enum GCMode { NonGC, GCOnly, HybridGC }; + enum VisibilityMode { + Default, + Protected, + Hidden + }; + + LangOptions() { + Trigraphs = BCPLComment = DollarIdents = AsmPreprocessor = 0; + GNUMode = ImplicitInt = Digraphs = 0; + HexFloats = 0; + GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0; + C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; + CXXOperatorNames = PascalStrings = WritableStrings = 0; + Exceptions = NeXTRuntime = Freestanding = NoBuiltin = 0; + LaxVectorConversions = 1; + HeinousExtensions = 0; + + SymbolVisibility = (unsigned) Default; + + // FIXME: The default should be 1. + ThreadsafeStatics = 0; + Blocks = 0; + EmitAllDecls = 0; + MathErrno = 1; + + // FIXME: The default should be 1. + AccessControl = 0; + + OverflowChecking = 0; + ObjCGCBitmapPrint = 0; + ObjCSenderDispatch = 0; + + InstantiationDepth = 99; + + Optimize = 0; + OptimizeSize = 0; + + Static = 0; + PICLevel = 0; + + GNUInline = 0; + NoInline = 0; + + MainFileName = 0; + } + + GCMode getGCMode() const { return (GCMode) GC; } + void setGCMode(GCMode m) { GC = (unsigned) m; } + + const char *getMainFileName() const { return MainFileName; } + void setMainFileName(const char *Name) { MainFileName = Name; } + + VisibilityMode getVisibilityMode() const { + return (VisibilityMode) SymbolVisibility; + } + void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile new file mode 100644 index 000000000000..b08d61457b75 --- /dev/null +++ b/include/clang/Basic/Makefile @@ -0,0 +1,22 @@ +LEVEL = ../../../../.. +BUILT_SOURCES = DiagnosticAnalysisKinds.inc DiagnosticASTKinds.inc \ + DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \ + DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \ + DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \ + DiagnosticGroups.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(LEVEL)/Makefile.common + +$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td DiagnosticGroups.td Diagnostic%Kinds.td $(TBLGEN) + $(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen" + $(Verb) -$(MKDIR) $(@D) + $(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $< + +$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td $(wildcard Diagnostic*.td) $(TBLGEN) + $(Echo) "Building Clang diagnostic groups with tblgen" + $(Verb) -$(MKDIR) $(@D) + $(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $< + + diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h new file mode 100644 index 000000000000..f54d67042c47 --- /dev/null +++ b/include/clang/Basic/OnDiskHashTable.h @@ -0,0 +1,362 @@ +//===--- OnDiskHashTable.h - On-Disk Hash Table Implementation --*- 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 facilities for reading and writing on-disk hash +// tables. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H +#define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include <cassert> +#include <cstdlib> + +namespace clang { + +// Bernstein hash function: +// This is basically copy-and-paste from StringMap. This likely won't +// stay here, which is why I didn't both to expose this function from +// String Map. +inline unsigned BernsteinHash(const char* x) { + unsigned int R = 0; + for ( ; *x != '\0' ; ++x) R = R * 33 + *x; + return R + (R >> 5); +} + +inline unsigned BernsteinHash(const char* x, unsigned n) { + unsigned int R = 0; + for (unsigned i = 0 ; i < n ; ++i, ++x) R = R * 33 + *x; + return R + (R >> 5); +} + +inline unsigned BernsteinHashPartial(const char* x, unsigned n, unsigned R) { + for (unsigned i = 0 ; i < n ; ++i, ++x) R = R * 33 + *x; + return R + (R >> 5); +} + +namespace io { + +typedef uint32_t Offset; + +inline void Emit8(llvm::raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); +} + +inline void Emit16(llvm::raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + assert((V >> 16) == 0); +} + +inline void Emit32(llvm::raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + Out << (unsigned char)(V >> 16); + Out << (unsigned char)(V >> 24); +} + +inline void Emit64(llvm::raw_ostream& Out, uint64_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + Out << (unsigned char)(V >> 16); + Out << (unsigned char)(V >> 24); + Out << (unsigned char)(V >> 32); + Out << (unsigned char)(V >> 40); + Out << (unsigned char)(V >> 48); + Out << (unsigned char)(V >> 56); +} + +inline void Pad(llvm::raw_ostream& Out, unsigned A) { + Offset off = (Offset) Out.tell(); + uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off; + for (; n ; --n) + Emit8(Out, 0); +} + +inline uint16_t ReadUnalignedLE16(const unsigned char *&Data) { + uint16_t V = ((uint16_t)Data[0]) | + ((uint16_t)Data[1] << 8); + Data += 2; + return V; +} + +inline uint32_t ReadUnalignedLE32(const unsigned char *&Data) { + uint32_t V = ((uint32_t)Data[0]) | + ((uint32_t)Data[1] << 8) | + ((uint32_t)Data[2] << 16) | + ((uint32_t)Data[3] << 24); + Data += 4; + return V; +} + +inline uint64_t ReadUnalignedLE64(const unsigned char *&Data) { + uint64_t V = ((uint64_t)Data[0]) | + ((uint64_t)Data[1] << 8) | + ((uint64_t)Data[2] << 16) | + ((uint64_t)Data[3] << 24) | + ((uint64_t)Data[4] << 32) | + ((uint64_t)Data[5] << 40) | + ((uint64_t)Data[6] << 48) | + ((uint64_t)Data[7] << 56); + Data += 8; + return V; +} + +inline uint32_t ReadLE32(const unsigned char *&Data) { + // Hosts that directly support little-endian 32-bit loads can just + // use them. Big-endian hosts need a bswap. + uint32_t V = *((uint32_t*)Data); + if (llvm::sys::isBigEndianHost()) + V = llvm::ByteSwap_32(V); + Data += 4; + return V; +} + +} // end namespace io + +template<typename Info> +class OnDiskChainedHashTableGenerator { + unsigned NumBuckets; + unsigned NumEntries; + llvm::BumpPtrAllocator BA; + + class Item { + public: + typename Info::key_type key; + typename Info::data_type data; + Item *next; + const uint32_t hash; + + Item(typename Info::key_type_ref k, typename Info::data_type_ref d) + : key(k), data(d), next(0), hash(Info::ComputeHash(k)) {} + }; + + class Bucket { + public: + io::Offset off; + Item* head; + unsigned length; + + Bucket() {} + }; + + Bucket* Buckets; + +private: + void insert(Bucket* b, size_t size, Item* E) { + unsigned idx = E->hash & (size - 1); + Bucket& B = b[idx]; + E->next = B.head; + ++B.length; + B.head = E; + } + + void resize(size_t newsize) { + Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket)); + // Populate newBuckets with the old entries. + for (unsigned i = 0; i < NumBuckets; ++i) + for (Item* E = Buckets[i].head; E ; ) { + Item* N = E->next; + E->next = 0; + insert(newBuckets, newsize, E); + E = N; + } + + free(Buckets); + NumBuckets = newsize; + Buckets = newBuckets; + } + +public: + + void insert(typename Info::key_type_ref key, + typename Info::data_type_ref data) { + + ++NumEntries; + if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2); + insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data)); + } + + io::Offset Emit(llvm::raw_ostream &out) { + Info InfoObj; + return Emit(out, InfoObj); + } + + io::Offset Emit(llvm::raw_ostream &out, Info &InfoObj) { + using namespace clang::io; + + // Emit the payload of the table. + for (unsigned i = 0; i < NumBuckets; ++i) { + Bucket& B = Buckets[i]; + if (!B.head) continue; + + // Store the offset for the data of this bucket. + B.off = out.tell(); + assert(B.off && "Cannot write a bucket at offset 0. Please add padding."); + + // Write out the number of items in the bucket. + Emit16(out, B.length); + + // Write out the entries in the bucket. + for (Item *I = B.head; I ; I = I->next) { + Emit32(out, I->hash); + const std::pair<unsigned, unsigned>& Len = + InfoObj.EmitKeyDataLength(out, I->key, I->data); + InfoObj.EmitKey(out, I->key, Len.first); + InfoObj.EmitData(out, I->key, I->data, Len.second); + } + } + + // Emit the hashtable itself. + Pad(out, 4); + io::Offset TableOff = out.tell(); + Emit32(out, NumBuckets); + Emit32(out, NumEntries); + for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off); + + return TableOff; + } + + OnDiskChainedHashTableGenerator() { + NumEntries = 0; + NumBuckets = 64; + // Note that we do not need to run the constructors of the individual + // Bucket objects since 'calloc' returns bytes that are all 0. + Buckets = (Bucket*) std::calloc(NumBuckets, sizeof(Bucket)); + } + + ~OnDiskChainedHashTableGenerator() { + std::free(Buckets); + } +}; + +template<typename Info> +class OnDiskChainedHashTable { + const unsigned NumBuckets; + const unsigned NumEntries; + const unsigned char* const Buckets; + const unsigned char* const Base; + Info InfoObj; + +public: + typedef typename Info::internal_key_type internal_key_type; + typedef typename Info::external_key_type external_key_type; + typedef typename Info::data_type data_type; + + OnDiskChainedHashTable(unsigned numBuckets, unsigned numEntries, + const unsigned char* buckets, + const unsigned char* base, + const Info &InfoObj = Info()) + : NumBuckets(numBuckets), NumEntries(numEntries), + Buckets(buckets), Base(base), InfoObj(InfoObj) { + assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 && + "'buckets' must have a 4-byte alignment"); + } + + unsigned getNumBuckets() const { return NumBuckets; } + unsigned getNumEntries() const { return NumEntries; } + const unsigned char* getBase() const { return Base; } + const unsigned char* getBuckets() const { return Buckets; } + + bool isEmpty() const { return NumEntries == 0; } + + class iterator { + internal_key_type key; + const unsigned char* const data; + const unsigned len; + Info *InfoObj; + public: + iterator() : data(0), len(0) {} + iterator(const internal_key_type k, const unsigned char* d, unsigned l, + Info *InfoObj) + : key(k), data(d), len(l), InfoObj(InfoObj) {} + + data_type operator*() const { return InfoObj->ReadData(key, data, len); } + bool operator==(const iterator& X) const { return X.data == data; } + bool operator!=(const iterator& X) const { return X.data != data; } + }; + + iterator find(const external_key_type& eKey, Info *InfoPtr = 0) { + if (!InfoPtr) + InfoPtr = &InfoObj; + + using namespace io; + const internal_key_type& iKey = Info::GetInternalKey(eKey); + unsigned key_hash = Info::ComputeHash(iKey); + + // Each bucket is just a 32-bit offset into the hash table file. + unsigned idx = key_hash & (NumBuckets - 1); + const unsigned char* Bucket = Buckets + sizeof(uint32_t)*idx; + + unsigned offset = ReadLE32(Bucket); + if (offset == 0) return iterator(); // Empty bucket. + const unsigned char* Items = Base + offset; + + // 'Items' starts with a 16-bit unsigned integer representing the + // number of items in this bucket. + unsigned len = ReadUnalignedLE16(Items); + + for (unsigned i = 0; i < len; ++i) { + // Read the hash. + uint32_t item_hash = ReadUnalignedLE32(Items); + + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items); + unsigned item_len = L.first + L.second; + + // Compare the hashes. If they are not the same, skip the entry entirely. + if (item_hash != key_hash) { + Items += item_len; + continue; + } + + // Read the key. + const internal_key_type& X = + 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)) { + Items += item_len; + continue; + } + + // The key matches! + return iterator(X, Items + L.first, L.second, InfoPtr); + } + + return iterator(); + } + + iterator end() const { return iterator(); } + + + static OnDiskChainedHashTable* Create(const unsigned char* buckets, + const unsigned char* const base, + const Info &InfoObj = Info()) { + using namespace io; + assert(buckets > base); + assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 && + "buckets should be 4-byte aligned."); + + unsigned numBuckets = ReadLE32(buckets); + unsigned numEntries = ReadLE32(buckets); + return new OnDiskChainedHashTable<Info>(numBuckets, numEntries, buckets, + base, InfoObj); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/OperatorKinds.def b/include/clang/Basic/OperatorKinds.def new file mode 100644 index 000000000000..d011e9d39ff8 --- /dev/null +++ b/include/clang/Basic/OperatorKinds.def @@ -0,0 +1,106 @@ +//===--- OperatorKinds.def - C++ Overloaded Operator Database ---*- 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 OverloadedOperator database, which includes +// all of the overloadable C++ operators. +// +//===----------------------------------------------------------------------===// +// +/// @file OperatorKinds.def +/// +/// In this file, each of the overloadable C++ operators is enumerated +/// with either the OVERLOADED_OPERATOR or OVERLOADED_OPERATOR_MULTI +/// macro, each of which can be specified by the code including this +/// file. OVERLOADED_OPERATOR is used for single-token operators +/// (e.g., "+"), and has six arguments: +/// +/// Name: The name of the token. OO_Name will be the name of the +/// corresponding enumerator in OverloadedOperatorKind in +/// OperatorKinds.h. +/// +/// Spelling: A string that provides a canonical spelling for the +/// operator, e.g., "operator+". +/// +/// Token: The name of the token that specifies the operator, e.g., +/// "plus" for operator+ or "greatergreaterequal" for +/// "operator>>=". With a "kw_" prefix, the token name can be used as +/// an enumerator into the TokenKind enumeration. +/// +/// Unary: True if the operator can be declared as a unary operator. +/// +/// Binary: True if the operator can be declared as a binary +/// operator. Note that some operators (e.g., "operator+" and +/// "operator*") can be both unary and binary. +/// +/// MemberOnly: True if this operator can only be declared as a +/// non-static member function. False if the operator can be both a +/// non-member function and a non-static member function. +/// +/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token +/// overloaded operator names, e.g., "operator delete []". The macro +/// has all of the parameters of OVERLOADED_OPERATOR except Token, +/// which is omitted. + +#ifndef OVERLOADED_OPERATOR +# define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) +#endif + +#ifndef OVERLOADED_OPERATOR_MULTI +# define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) \ + OVERLOADED_OPERATOR(Name,Spelling,unknown,Unary,Binary,MemberOnly) +#endif + +OVERLOADED_OPERATOR_MULTI(New , "new" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Delete , "delete" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_New , "new[]" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_Delete , "delete[]" , true , true , false) +OVERLOADED_OPERATOR(Plus , "+" , plus , true , true , false) +OVERLOADED_OPERATOR(Minus , "-" , minus , true , true , false) +OVERLOADED_OPERATOR(Star , "*" , star , true , true , false) +OVERLOADED_OPERATOR(Slash , "/" , slash , false, true , false) +OVERLOADED_OPERATOR(Percent , "%" , percent , false, true , false) +OVERLOADED_OPERATOR(Caret , "^" , caret , false, true , false) +OVERLOADED_OPERATOR(Amp , "&" , amp , true , true , false) +OVERLOADED_OPERATOR(Pipe , "|" , pipe , false, true , false) +OVERLOADED_OPERATOR(Tilde , "~" , tilde , true , false, false) +OVERLOADED_OPERATOR(Exclaim , "!" , exclaim , true , false, false) +OVERLOADED_OPERATOR(Equal , "=" , equal , false, true , true) +OVERLOADED_OPERATOR(Less , "<" , less , false, true , false) +OVERLOADED_OPERATOR(Greater , ">" , greater , false, true , false) +OVERLOADED_OPERATOR(PlusEqual , "+=" , plusequal , false, true , false) +OVERLOADED_OPERATOR(MinusEqual , "-=" , minusequal , false, true , false) +OVERLOADED_OPERATOR(StarEqual , "*=" , starequal , false, true , false) +OVERLOADED_OPERATOR(SlashEqual , "/=" , slashequal , false, true , false) +OVERLOADED_OPERATOR(PercentEqual , "%=" , percentequal , false, true , false) +OVERLOADED_OPERATOR(CaretEqual , "^=" , caretequal , false, true , false) +OVERLOADED_OPERATOR(AmpEqual , "&=" , ampequal , false, true , false) +OVERLOADED_OPERATOR(PipeEqual , "|=" , pipeequal , false, true , false) +OVERLOADED_OPERATOR(LessLess , "<<" , lessless , false, true , false) +OVERLOADED_OPERATOR(GreaterGreater , ">>" , greatergreater , false, true , false) +OVERLOADED_OPERATOR(LessLessEqual , "<<=" , lesslessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterGreaterEqual , ">>=" , greatergreaterequal, false, true , false) +OVERLOADED_OPERATOR(EqualEqual , "==" , equalequal , false, true , false) +OVERLOADED_OPERATOR(ExclaimEqual , "!=" , exclaimequal , false, true , false) +OVERLOADED_OPERATOR(LessEqual , "<=" , lessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterEqual , ">=" , greaterequal , false, true , false) +OVERLOADED_OPERATOR(AmpAmp , "&&" , ampamp , false, true , false) +OVERLOADED_OPERATOR(PipePipe , "||" , pipepipe , false, true , false) +OVERLOADED_OPERATOR(PlusPlus , "++" , plusplus , true , true , false) +OVERLOADED_OPERATOR(MinusMinus , "--" , minusminus , true , true , false) +OVERLOADED_OPERATOR(Comma , "," , comma , false, true , false) +OVERLOADED_OPERATOR(ArrowStar , "->*" , arrowstar , false, true , false) +OVERLOADED_OPERATOR(Arrow , "->" , arrow , true , false, true) +OVERLOADED_OPERATOR_MULTI(Call , "()" , true , true , true) +OVERLOADED_OPERATOR_MULTI(Subscript , "[]" , false, true , true) +// ?: can *not* be overloaded, but we need the overload +// resolution machinery for it. +OVERLOADED_OPERATOR_MULTI(Conditional , "?" , false, true , false) + +#undef OVERLOADED_OPERATOR_MULTI +#undef OVERLOADED_OPERATOR diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h new file mode 100644 index 000000000000..790b75ba3af3 --- /dev/null +++ b/include/clang/Basic/OperatorKinds.h @@ -0,0 +1,32 @@ +//===--- OperatorKinds.h - C++ Overloaded Operators -------------*- 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 C++ overloaded operators. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPERATOR_KINDS_H +#define LLVM_CLANG_BASIC_OPERATOR_KINDS_H + +namespace clang { + +/// OverloadedOperatorKind - Enumeration specifying the different kinds of +/// C++ overloaded operators. +enum OverloadedOperatorKind { + OO_None, //< Not an overloaded operator +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + OO_##Name, +#include "clang/Basic/OperatorKinds.def" + NUM_OVERLOADED_OPERATORS +}; + + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/PrettyStackTrace.h b/include/clang/Basic/PrettyStackTrace.h new file mode 100644 index 000000000000..5a5d55192b69 --- /dev/null +++ b/include/clang/Basic/PrettyStackTrace.h @@ -0,0 +1,37 @@ +//===- clang/Basic/PrettyStackTrace.h - Pretty Crash 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 PrettyStackTraceEntry class, which is used to make +// crashes give more contextual information about what the program was doing +// when it crashed. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_PRETTYSTACKTRACE_H +#define CLANG_BASIC_PRETTYSTACKTRACE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + + /// PrettyStackTraceLoc - If a crash happens while one of these objects are + /// live, the message is printed out along with the specified source location. + class PrettyStackTraceLoc : public llvm::PrettyStackTraceEntry { + SourceManager &SM; + SourceLocation Loc; + const char *Message; + public: + PrettyStackTraceLoc(SourceManager &sm, SourceLocation L, const char *Msg) + : SM(sm), Loc(L), Message(Msg) {} + virtual void print(llvm::raw_ostream &OS) const; + }; +} + +#endif diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h new file mode 100644 index 000000000000..2405c2fe7db7 --- /dev/null +++ b/include/clang/Basic/SourceLocation.h @@ -0,0 +1,305 @@ +//===--- SourceLocation.h - Compact identifier for Source Files -*- 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 SourceLocation class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCELOCATION_H +#define LLVM_CLANG_SOURCELOCATION_H + +#include <utility> +#include <cassert> + +namespace llvm { + class MemoryBuffer; + class raw_ostream; + template <typename T> struct DenseMapInfo; +} + +namespace clang { + +class SourceManager; +class FileEntry; + +/// FileID - This is an opaque identifier used by SourceManager which refers to +/// a source file (MemoryBuffer) along with its #include path and #line data. +/// +class FileID { + /// ID - Opaque identifier, 0 is "invalid". + unsigned ID; +public: + FileID() : ID(0) {} + + bool isInvalid() const { return ID == 0; } + + bool operator==(const FileID &RHS) const { return ID == RHS.ID; } + bool operator<(const FileID &RHS) const { return ID < RHS.ID; } + bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } + bool operator!=(const FileID &RHS) const { return !(*this == RHS); } + bool operator>(const FileID &RHS) const { return RHS < *this; } + bool operator>=(const FileID &RHS) const { return RHS <= *this; } + + static FileID getSentinel() { return get(~0U); } + unsigned getHashValue() const { return ID; } + +private: + friend class SourceManager; + static FileID get(unsigned V) { + FileID F; + F.ID = V; + return F; + } + unsigned getOpaqueValue() const { return ID; } +}; + + +/// SourceLocation - This is a carefully crafted 32-bit identifier that encodes +/// a full include stack, line and column number information for a position in +/// an input translation unit. +class SourceLocation { + unsigned ID; + friend class SourceManager; + enum { + MacroIDBit = 1U << 31 + }; +public: + + SourceLocation() : ID(0) {} // 0 is an invalid FileID. + + bool isFileID() const { return (ID & MacroIDBit) == 0; } + bool isMacroID() const { return (ID & MacroIDBit) != 0; } + + /// isValid - Return true if this is a valid SourceLocation object. Invalid + /// SourceLocations are often used when events have no corresponding location + /// in the source (e.g. a diagnostic is required for a command line option). + /// + bool isValid() const { return ID != 0; } + bool isInvalid() const { return ID == 0; } + +private: + /// getOffset - Return the index for SourceManager's SLocEntryTable table, + /// note that this is not an index *into* it though. + unsigned getOffset() const { + return ID & ~MacroIDBit; + } + + static SourceLocation getFileLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = ID; + return L; + } + + static SourceLocation getMacroLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = MacroIDBit | ID; + return L; + } +public: + + /// getFileLocWithOffset - Return a source location with the specified offset + /// from this file SourceLocation. + SourceLocation getFileLocWithOffset(int Offset) const { + assert(((getOffset()+Offset) & MacroIDBit) == 0 && "invalid location"); + SourceLocation L; + L.ID = ID+Offset; + return L; + } + + /// getRawEncoding - When a SourceLocation itself cannot be used, this returns + /// an (opaque) 32-bit integer encoding for it. This should only be passed + /// to SourceLocation::getFromRawEncoding, it should not be inspected + /// directly. + unsigned getRawEncoding() const { return ID; } + + + /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into + /// a real SourceLocation. + static SourceLocation getFromRawEncoding(unsigned Encoding) { + SourceLocation X; + X.ID = Encoding; + return X; + } + + void print(llvm::raw_ostream &OS, const SourceManager &SM) const; + void dump(const SourceManager &SM) const; +}; + +inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding(); +} + +inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { + return !(LHS == RHS); +} + +inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() < RHS.getRawEncoding(); +} + +/// SourceRange - a trival tuple used to represent a source range. +class SourceRange { + SourceLocation B; + SourceLocation E; +public: + SourceRange(): B(SourceLocation()), E(SourceLocation()) {} + SourceRange(SourceLocation loc) : B(loc), E(loc) {} + SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} + + SourceLocation getBegin() const { return B; } + SourceLocation getEnd() const { return E; } + + void setBegin(SourceLocation b) { B = b; } + void setEnd(SourceLocation e) { E = e; } + + bool isValid() const { return B.isValid() && E.isValid(); } + + bool operator==(const SourceRange &X) const { + return B == X.B && E == X.E; + } + + bool operator!=(const SourceRange &X) const { + return B != X.B || E != X.E; + } +}; + +/// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful +/// for argument passing to functions that expect both objects. +class FullSourceLoc : public SourceLocation { + SourceManager* SrcMgr; +public: + /// Creates a FullSourceLoc where isValid() returns false. + explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {} + + explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM) + : SourceLocation(Loc), SrcMgr(&SM) {} + + SourceManager &getManager() { + assert(SrcMgr && "SourceManager is NULL."); + return *SrcMgr; + } + + const SourceManager &getManager() const { + assert(SrcMgr && "SourceManager is NULL."); + return *SrcMgr; + } + + FileID getFileID() const; + + FullSourceLoc getInstantiationLoc() const; + FullSourceLoc getSpellingLoc() const; + + unsigned getInstantiationLineNumber() const; + unsigned getInstantiationColumnNumber() const; + + unsigned getSpellingLineNumber() const; + unsigned getSpellingColumnNumber() const; + + const char *getCharacterData() const; + + const llvm::MemoryBuffer* getBuffer() const; + + /// getBufferData - Return a pointer to the start and end of the source buffer + /// data for the specified FileID. + std::pair<const char*, const char*> getBufferData() const; + + /// getDecomposedLoc - Decompose the specified location into a raw FileID + + /// Offset pair. The first element is the FileID, the second is the + /// offset from the start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc() const; + + bool isInSystemHeader() const; + + /// Prints information about this FullSourceLoc to stderr. Useful for + /// debugging. + void dump() const { SourceLocation::dump(*SrcMgr); } + + friend inline bool + operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding() && + LHS.SrcMgr == RHS.SrcMgr; + } + + friend inline bool + operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return !(LHS == RHS); + } + +}; + +/// PresumedLoc - This class represents an unpacked "presumed" location which +/// can be presented to the user. A 'presumed' location can be modified by +/// #line and GNU line marker directives and is always the instantiation point +/// of a normal location. +/// +/// You can get a PresumedLoc from a SourceLocation with SourceManager. +class PresumedLoc { + const char *Filename; + unsigned Line, Col; + SourceLocation IncludeLoc; +public: + PresumedLoc() : Filename(0) {} + PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) + : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { + } + + /// isInvalid - Return true if this object is invalid or uninitialized. This + /// occurs when created with invalid source locations or when walking off + /// the top of a #include stack. + bool isInvalid() const { return Filename == 0; } + bool isValid() const { return Filename != 0; } + + /// getFilename - Return the presumed filename of this location. This can be + /// affected by #line etc. + const char *getFilename() const { return Filename; } + + /// getLine - Return the presumed line number of this location. This can be + /// affected by #line etc. + unsigned getLine() const { return Line; } + + /// getColumn - Return the presumed column number of this location. This can + /// not be affected by #line, but is packaged here for convenience. + unsigned getColumn() const { return Col; } + + /// getIncludeLoc - Return the presumed include location of this location. + /// This can be affected by GNU linemarker directives. + SourceLocation getIncludeLoc() const { return IncludeLoc; } +}; + + +} // end namespace clang + +namespace llvm { + /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and + /// DenseSets. + template <> + struct DenseMapInfo<clang::FileID> { + static inline clang::FileID getEmptyKey() { + return clang::FileID(); + } + static inline clang::FileID getTombstoneKey() { + return clang::FileID::getSentinel(); + } + + static unsigned getHashValue(clang::FileID S) { + return S.getHashValue(); + } + + static bool isEqual(clang::FileID LHS, clang::FileID RHS) { + return LHS == RHS; + } + + static bool isPod() { return true; } + }; + +} // end namespace llvm + +#endif diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h new file mode 100644 index 000000000000..43369829387d --- /dev/null +++ b/include/clang/Basic/SourceManager.h @@ -0,0 +1,714 @@ +//===--- SourceManager.h - Track and cache source files ---------*- 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 SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCEMANAGER_H +#define LLVM_CLANG_SOURCEMANAGER_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" +#include <vector> +#include <cassert> + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { + +class SourceManager; +class FileManager; +class FileEntry; +class IdentifierTokenInfo; +class LineTableInfo; + +/// SrcMgr - Public enums and private classes that are part of the +/// SourceManager implementation. +/// +namespace SrcMgr { + /// CharacteristicKind - This is used to represent whether a file or directory + /// holds normal user code, system code, or system code which is implicitly + /// 'extern "C"' in C++ mode. Entire directories can be tagged with this + /// (this is maintained by DirectoryLookup and friends) as can specific + /// FileIDInfos when a #pragma system_header is seen or various other cases. + /// + enum CharacteristicKind { + C_User, C_System, C_ExternCSystem + }; + + /// ContentCache - Once instance of this struct is kept for every file + /// loaded or used. This object owns the MemoryBuffer object. + class ContentCache { + /// Buffer - The actual buffer containing the characters from the input + /// file. This is owned by the ContentCache object. + mutable const llvm::MemoryBuffer *Buffer; + + public: + /// Reference to the file entry. This reference does not own + /// the FileEntry object. It is possible for this to be NULL if + /// the ContentCache encapsulates an imaginary text buffer. + const FileEntry *Entry; + + /// SourceLineCache - A bump pointer allocated array of offsets for each + /// source line. This is lazily computed. This is owned by the + /// SourceManager BumpPointerAllocator object. + unsigned *SourceLineCache; + + /// NumLines - The number of lines in this ContentCache. This is only valid + /// if SourceLineCache is non-null. + unsigned NumLines; + + /// getBuffer - Returns the memory buffer for the associated content. + const llvm::MemoryBuffer *getBuffer() const; + + /// getSize - Returns the size of the content encapsulated by this + /// ContentCache. This can be the size of the source file or the size of an + /// arbitrary scratch buffer. If the ContentCache encapsulates a source + /// file this size is retrieved from the file's FileEntry. + unsigned getSize() const; + + /// getSizeBytesMapped - Returns the number of bytes actually mapped for + /// this ContentCache. This can be 0 if the MemBuffer was not actually + /// instantiated. + unsigned getSizeBytesMapped() const; + + void setBuffer(const llvm::MemoryBuffer *B) { + assert(!Buffer && "MemoryBuffer already set."); + Buffer = B; + } + + ContentCache(const FileEntry *Ent = 0) + : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {} + + ~ContentCache(); + + /// The copy ctor does not allow copies where source object has either + /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory + /// is not transfered, so this is a logical error. + ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) { + Entry = RHS.Entry; + + assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0 + && "Passed ContentCache object cannot own a buffer."); + + NumLines = RHS.NumLines; + } + + private: + // Disable assignments. + ContentCache &operator=(const ContentCache& RHS); + }; + + /// FileInfo - Information about a FileID, basically just the logical file + /// that it represents and include stack information. + /// + /// Each FileInfo has include stack information, indicating where it came + /// from. This information encodes the #include chain that a token was + /// instantiated from. The main include file has an invalid IncludeLoc. + /// + /// FileInfos contain a "ContentCache *", with the contents of the file. + /// + class FileInfo { + /// IncludeLoc - The location of the #include that brought in this file. + /// This is an invalid SLOC for the main file (top of the #include chain). + unsigned IncludeLoc; // Really a SourceLocation + + /// Data - This contains the ContentCache* and the bits indicating the + /// characteristic of the file and whether it has #line info, all bitmangled + /// together. + uintptr_t Data; + public: + /// get - Return a FileInfo object. + static FileInfo get(SourceLocation IL, const ContentCache *Con, + CharacteristicKind FileCharacter) { + FileInfo X; + X.IncludeLoc = IL.getRawEncoding(); + X.Data = (uintptr_t)Con; + assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); + assert((unsigned)FileCharacter < 4 && "invalid file character"); + X.Data |= (unsigned)FileCharacter; + return X; + } + + SourceLocation getIncludeLoc() const { + return SourceLocation::getFromRawEncoding(IncludeLoc); + } + const ContentCache* getContentCache() const { + return reinterpret_cast<const ContentCache*>(Data & ~7UL); + } + + /// getCharacteristic - Return whether this is a system header or not. + CharacteristicKind getFileCharacteristic() const { + return (CharacteristicKind)(Data & 3); + } + + /// hasLineDirectives - Return true if this FileID has #line directives in + /// it. + bool hasLineDirectives() const { return (Data & 4) != 0; } + + /// setHasLineDirectives - Set the flag that indicates that this FileID has + /// line table entries associated with it. + void setHasLineDirectives() { + Data |= 4; + } + }; + + /// InstantiationInfo - Each InstantiationInfo encodes the Instantiation + /// location - where the token was ultimately instantiated, and the + /// SpellingLoc - where the actual character data for the token came from. + class InstantiationInfo { + // Really these are all SourceLocations. + + /// SpellingLoc - Where the spelling for the token can be found. + unsigned SpellingLoc; + + /// InstantiationLocStart/InstantiationLocEnd - In a macro expansion, these + /// indicate the start and end of the instantiation. In object-like macros, + /// these will be the same. In a function-like macro instantiation, the + /// start will be the identifier and the end will be the ')'. + unsigned InstantiationLocStart, InstantiationLocEnd; + public: + SourceLocation getSpellingLoc() const { + return SourceLocation::getFromRawEncoding(SpellingLoc); + } + SourceLocation getInstantiationLocStart() const { + return SourceLocation::getFromRawEncoding(InstantiationLocStart); + } + SourceLocation getInstantiationLocEnd() const { + return SourceLocation::getFromRawEncoding(InstantiationLocEnd); + } + + std::pair<SourceLocation,SourceLocation> getInstantiationLocRange() const { + return std::make_pair(getInstantiationLocStart(), + getInstantiationLocEnd()); + } + + /// get - Return a InstantiationInfo for an expansion. IL specifies + /// the instantiation location (where the macro is expanded), and SL + /// specifies the spelling location (where the characters from the token + /// come from). IL and PL can both refer to normal File SLocs or + /// instantiation locations. + static InstantiationInfo get(SourceLocation ILStart, SourceLocation ILEnd, + SourceLocation SL) { + InstantiationInfo X; + X.SpellingLoc = SL.getRawEncoding(); + X.InstantiationLocStart = ILStart.getRawEncoding(); + X.InstantiationLocEnd = ILEnd.getRawEncoding(); + return X; + } + }; + + /// SLocEntry - This is a discriminated union of FileInfo and + /// InstantiationInfo. SourceManager keeps an array of these objects, and + /// they are uniquely identified by the FileID datatype. + class SLocEntry { + unsigned Offset; // low bit is set for instantiation info. + union { + FileInfo File; + InstantiationInfo Instantiation; + }; + public: + unsigned getOffset() const { return Offset >> 1; } + + bool isInstantiation() const { return Offset & 1; } + bool isFile() const { return !isInstantiation(); } + + const FileInfo &getFile() const { + assert(isFile() && "Not a file SLocEntry!"); + return File; + } + + const InstantiationInfo &getInstantiation() const { + assert(isInstantiation() && "Not an instantiation SLocEntry!"); + return Instantiation; + } + + static SLocEntry get(unsigned Offset, const FileInfo &FI) { + SLocEntry E; + E.Offset = Offset << 1; + E.File = FI; + return E; + } + + static SLocEntry get(unsigned Offset, const InstantiationInfo &II) { + SLocEntry E; + E.Offset = (Offset << 1) | 1; + E.Instantiation = II; + return E; + } + }; +} // end SrcMgr namespace. + +/// \brief External source of source location entries. +class ExternalSLocEntrySource { +public: + virtual ~ExternalSLocEntrySource(); + + /// \brief Read the source location entry with index ID. + virtual void ReadSLocEntry(unsigned ID) = 0; +}; + +/// SourceManager - This file handles loading and caching of source files into +/// memory. This object owns the MemoryBuffer objects for all of the loaded +/// files and assigns unique FileID's for each unique #include chain. +/// +/// The SourceManager can be queried for information about SourceLocation +/// objects, turning them into either spelling or instantiation locations. +/// Spelling locations represent where the bytes corresponding to a token came +/// from and instantiation locations represent where the location is in the +/// user's view. In the case of a macro expansion, for example, the spelling +/// location indicates where the expanded token came from and the instantiation +/// location specifies where it was expanded. +class SourceManager { + mutable llvm::BumpPtrAllocator ContentCacheAlloc; + + /// FileInfos - Memoized information about all of the files tracked by this + /// SourceManager. This set allows us to merge ContentCache entries based + /// on their FileEntry*. All ContentCache objects will thus have unique, + /// non-null, FileEntry pointers. + llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos; + + /// MemBufferInfos - Information about various memory buffers that we have + /// read in. All FileEntry* within the stored ContentCache objects are NULL, + /// as they do not refer to a file. + std::vector<SrcMgr::ContentCache*> MemBufferInfos; + + /// SLocEntryTable - This is an array of SLocEntry's that we have created. + /// FileID is an index into this vector. This array is sorted by the offset. + std::vector<SrcMgr::SLocEntry> SLocEntryTable; + /// NextOffset - This is the next available offset that a new SLocEntry can + /// start at. It is SLocEntryTable.back().getOffset()+size of back() entry. + unsigned NextOffset; + + /// \brief If source location entries are being lazily loaded from + /// an external source, this vector indicates whether the Ith source + /// location entry has already been loaded from the external storage. + std::vector<bool> SLocEntryLoaded; + + /// \brief An external source for source location entries. + ExternalSLocEntrySource *ExternalSLocEntries; + + /// LastFileIDLookup - This is a one-entry cache to speed up getFileID. + /// LastFileIDLookup records the last FileID looked up or created, because it + /// is very common to look up many tokens from the same file. + mutable FileID LastFileIDLookup; + + /// LineTable - This holds information for #line directives. It is referenced + /// by indices from SLocEntryTable. + LineTableInfo *LineTable; + + /// LastLineNo - These ivars serve as a cache used in the getLineNumber + /// method which is used to speedup getLineNumber calls to nearby locations. + mutable FileID LastLineNoFileIDQuery; + mutable SrcMgr::ContentCache *LastLineNoContentCache; + mutable unsigned LastLineNoFilePos; + mutable unsigned LastLineNoResult; + + /// MainFileID - The file ID for the main source file of the translation unit. + FileID MainFileID; + + // Statistics for -print-stats. + mutable unsigned NumLinearScans, NumBinaryProbes; + + // SourceManager doesn't support copy construction. + explicit SourceManager(const SourceManager&); + void operator=(const SourceManager&); +public: + SourceManager() + : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), + NumBinaryProbes(0) { + clearIDTables(); + } + ~SourceManager(); + + void clearIDTables(); + + //===--------------------------------------------------------------------===// + // MainFileID creation and querying methods. + //===--------------------------------------------------------------------===// + + /// getMainFileID - Returns the FileID of the main source file. + FileID getMainFileID() const { return MainFileID; } + + /// createMainFileID - Create the FileID for the main source file. + FileID createMainFileID(const FileEntry *SourceFile, + SourceLocation IncludePos) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = createFileID(SourceFile, IncludePos, SrcMgr::C_User); + return MainFileID; + } + + //===--------------------------------------------------------------------===// + // Methods to create new FileID's and instantiations. + //===--------------------------------------------------------------------===// + + /// createFileID - Create a new FileID that represents the specified file + /// being #included from the specified IncludePosition. This returns 0 on + /// error and translates NULL into standard input. + /// PreallocateID should be non-zero to specify which a pre-allocated, + /// lazily computed source location is being filled in by this operation. + FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + unsigned PreallocatedID = 0, + unsigned Offset = 0) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + if (IR == 0) return FileID(); // Error opening file? + return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset); + } + + /// createFileIDForMemBuffer - Create a new FileID that represents the + /// specified memory buffer. This does no caching of the buffer and takes + /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once. + FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer, + unsigned PreallocatedID = 0, + unsigned Offset = 0) { + return createFileID(createMemBufferContentCache(Buffer), SourceLocation(), + SrcMgr::C_User, PreallocatedID, Offset); + } + + /// createMainFileIDForMembuffer - Create the FileID for a memory buffer + /// that will represent the FileID for the main source. One example + /// of when this would be used is when the main source is read from STDIN. + FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = createFileIDForMemBuffer(Buffer); + return MainFileID; + } + + /// createInstantiationLoc - Return a new SourceLocation that encodes the fact + /// that a token at Loc should actually be referenced from InstantiationLoc. + /// TokLength is the length of the token being instantiated. + SourceLocation createInstantiationLoc(SourceLocation Loc, + SourceLocation InstantiationLocStart, + SourceLocation InstantiationLocEnd, + unsigned TokLength, + unsigned PreallocatedID = 0, + unsigned Offset = 0); + + //===--------------------------------------------------------------------===// + // FileID manipulation methods. + //===--------------------------------------------------------------------===// + + /// getBuffer - Return the buffer for the specified FileID. + /// + const llvm::MemoryBuffer *getBuffer(FileID FID) const { + return getSLocEntry(FID).getFile().getContentCache()->getBuffer(); + } + + /// getFileEntryForID - Returns the FileEntry record for the provided FileID. + const FileEntry *getFileEntryForID(FileID FID) const { + return getSLocEntry(FID).getFile().getContentCache()->Entry; + } + + /// getBufferData - Return a pointer to the start and end of the source buffer + /// data for the specified FileID. + std::pair<const char*, const char*> getBufferData(FileID FID) const; + + + //===--------------------------------------------------------------------===// + // SourceLocation manipulation methods. + //===--------------------------------------------------------------------===// + + /// getFileID - Return the FileID for a SourceLocation. This is a very + /// hot method that is used for all SourceManager queries that start with a + /// SourceLocation object. It is responsible for finding the entry in + /// SLocEntryTable which contains the specified location. + /// + FileID getFileID(SourceLocation SpellingLoc) const { + unsigned SLocOffset = SpellingLoc.getOffset(); + + // If our one-entry cache covers this offset, just return it. + if (isOffsetInFileID(LastFileIDLookup, SLocOffset)) + return LastFileIDLookup; + + return getFileIDSlow(SLocOffset); + } + + /// getLocForStartOfFile - Return the source location corresponding to the + /// first byte of the specified file. + SourceLocation getLocForStartOfFile(FileID FID) const { + assert(FID.ID < SLocEntryTable.size() && "FileID out of range"); + assert(getSLocEntry(FID).isFile() && "FileID is not a file"); + unsigned FileOffset = getSLocEntry(FID).getOffset(); + return SourceLocation::getFileLoc(FileOffset); + } + + /// getInstantiationLoc - Given a SourceLocation object, return the + /// instantiation location referenced by the ID. + SourceLocation getInstantiationLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // instantiations. + if (Loc.isFileID()) return Loc; + return getInstantiationLocSlowCase(Loc); + } + + /// getImmediateInstantiationRange - Loc is required to be an instantiation + /// location. Return the start/end of the instantiation information. + std::pair<SourceLocation,SourceLocation> + getImmediateInstantiationRange(SourceLocation Loc) const; + + /// getInstantiationRange - Given a SourceLocation object, return the + /// range of tokens covered by the instantiation in the ultimate file. + std::pair<SourceLocation,SourceLocation> + getInstantiationRange(SourceLocation Loc) const; + + + /// getSpellingLoc - Given a SourceLocation object, return the spelling + /// location referenced by the ID. This is the place where the characters + /// that make up the lexed token can be found. + SourceLocation getSpellingLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // instantiations. + if (Loc.isFileID()) return Loc; + return getSpellingLocSlowCase(Loc); + } + + /// getImmediateSpellingLoc - Given a SourceLocation object, return the + /// spelling location referenced by the ID. This is the first level down + /// towards the place where the characters that make up the lexed token can be + /// found. This should not generally be used by clients. + SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; + + /// getDecomposedLoc - Decompose the specified location into a raw FileID + + /// Offset pair. The first element is the FileID, the second is the + /// offset from the start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + return std::make_pair(FID, Loc.getOffset()-getSLocEntry(FID).getOffset()); + } + + /// getDecomposedInstantiationLoc - Decompose the specified location into a + /// raw FileID + Offset pair. If the location is an instantiation record, + /// walk through it until we find the final location instantiated. + std::pair<FileID, unsigned> + getDecomposedInstantiationLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + const SrcMgr::SLocEntry *E = &getSLocEntry(FID); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + + return getDecomposedInstantiationLocSlowCase(E, Offset); + } + + /// getDecomposedSpellingLoc - Decompose the specified location into a raw + /// FileID + Offset pair. If the location is an instantiation record, walk + /// through it until we find its spelling record. + std::pair<FileID, unsigned> + getDecomposedSpellingLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + const SrcMgr::SLocEntry *E = &getSLocEntry(FID); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + return getDecomposedSpellingLocSlowCase(E, Offset); + } + + /// getFileOffset - This method returns the offset from the start + /// of the file that the specified SourceLocation represents. This is not very + /// meaningful for a macro ID. + unsigned getFileOffset(SourceLocation SpellingLoc) const { + return getDecomposedLoc(SpellingLoc).second; + } + + + //===--------------------------------------------------------------------===// + // Queries about the code at a SourceLocation. + //===--------------------------------------------------------------------===// + + /// getCharacterData - Return a pointer to the start of the specified location + /// in the appropriate spelling MemoryBuffer. + const char *getCharacterData(SourceLocation SL) const; + + /// getColumnNumber - Return the column # for the specified file position. + /// This is significantly cheaper to compute than the line number. This + /// returns zero if the column number isn't known. This may only be called on + /// a file sloc, so you must choose a spelling or instantiation location + /// before calling this method. + unsigned getColumnNumber(FileID FID, unsigned FilePos) const; + unsigned getSpellingColumnNumber(SourceLocation Loc) const; + unsigned getInstantiationColumnNumber(SourceLocation Loc) const; + + + /// getLineNumber - Given a SourceLocation, return the spelling line number + /// for the position indicated. This requires building and caching a table of + /// line offsets for the MemoryBuffer, so this is not cheap: use only when + /// about to emit a diagnostic. + unsigned getLineNumber(FileID FID, unsigned FilePos) const; + + unsigned getInstantiationLineNumber(SourceLocation Loc) const; + unsigned getSpellingLineNumber(SourceLocation Loc) const; + + /// Return the filename or buffer identifier of the buffer the location is in. + /// Note that this name does not respect #line directives. Use getPresumedLoc + /// for normal clients. + const char *getBufferName(SourceLocation Loc) const; + + /// getFileCharacteristic - return the file characteristic of the specified + /// source location, indicating whether this is a normal file, a system + /// header, or an "implicit extern C" system header. + /// + /// This state can be modified with flags on GNU linemarker directives like: + /// # 4 "foo.h" 3 + /// which changes all source locations in the current file after that to be + /// considered to be from a system header. + SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const; + + /// getPresumedLoc - This method returns the "presumed" location of a + /// SourceLocation specifies. A "presumed location" can be modified by #line + /// or GNU line marker directives. This provides a view on the data that a + /// user should see in diagnostics, for example. + /// + /// Note that a presumed location is always given as the instantiation point + /// of an instantiation location, not at the spelling location. + PresumedLoc getPresumedLoc(SourceLocation Loc) const; + + /// isFromSameFile - Returns true if both SourceLocations correspond to + /// the same file. + bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const { + return getFileID(Loc1) == getFileID(Loc2); + } + + /// isFromMainFile - Returns true if the file of provided SourceLocation is + /// the main file. + bool isFromMainFile(SourceLocation Loc) const { + return getFileID(Loc) == getMainFileID(); + } + + /// isInSystemHeader - Returns if a SourceLocation is in a system header. + bool isInSystemHeader(SourceLocation Loc) const { + return getFileCharacteristic(Loc) != SrcMgr::C_User; + } + + //===--------------------------------------------------------------------===// + // Line Table Manipulation Routines + //===--------------------------------------------------------------------===// + + /// getLineTableFilenameID - Return the uniqued ID for the specified filename. + /// + unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); + + /// AddLineNote - Add a line note to the line table for the FileID and offset + /// specified by Loc. If FilenameID is -1, it is considered to be + /// unspecified. + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, + bool IsFileEntry, bool IsFileExit, + bool IsSystemHeader, bool IsExternCHeader); + + /// \brief Determine if the source manager has a line table. + bool hasLineTable() const { return LineTable != 0; } + + /// \brief Retrieve the stored line table. + LineTableInfo &getLineTable(); + + //===--------------------------------------------------------------------===// + // Other miscellaneous methods. + //===--------------------------------------------------------------------===// + + // Iterators over FileInfos. + typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> + ::const_iterator fileinfo_iterator; + fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } + fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } + + /// PrintStats - Print statistics to stderr. + /// + void PrintStats() const; + + // Iteration over the source location entry table. + typedef std::vector<SrcMgr::SLocEntry>::const_iterator sloc_entry_iterator; + + sloc_entry_iterator sloc_entry_begin() const { + return SLocEntryTable.begin(); + } + + sloc_entry_iterator sloc_entry_end() const { + return SLocEntryTable.end(); + } + + unsigned sloc_entry_size() const { return SLocEntryTable.size(); } + + const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { + assert(FID.ID < SLocEntryTable.size() && "Invalid id"); + if (ExternalSLocEntries && + FID.ID < SLocEntryLoaded.size() && + !SLocEntryLoaded[FID.ID]) + ExternalSLocEntries->ReadSLocEntry(FID.ID); + return SLocEntryTable[FID.ID]; + } + + unsigned getNextOffset() const { return NextOffset; } + + /// \brief Preallocate some number of source location entries, which + /// will be loaded as needed from the given external source. + void PreallocateSLocEntries(ExternalSLocEntrySource *Source, + unsigned NumSLocEntries, + unsigned NextOffset); + + /// \brief Clear out any preallocated source location entries that + /// haven't already been loaded. + void ClearPreallocatedSLocEntries(); + +private: + /// isOffsetInFileID - Return true if the specified FileID contains the + /// specified SourceLocation offset. This is a very hot method. + inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const { + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); + // If the entry is after the offset, it can't contain it. + if (SLocOffset < Entry.getOffset()) return false; + + // If this is the last entry than it does. Otherwise, the entry after it + // has to not include it. + if (FID.ID+1 == SLocEntryTable.size()) return true; + + return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset(); + } + + /// createFileID - Create a new fileID for the specified ContentCache and + /// include position. This works regardless of whether the ContentCache + /// corresponds to a file or some other input source. + FileID createFileID(const SrcMgr::ContentCache* File, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind DirCharacter, + unsigned PreallocatedID = 0, + unsigned Offset = 0); + + const SrcMgr::ContentCache * + getOrCreateContentCache(const FileEntry *SourceFile); + + /// createMemBufferContentCache - Create a new ContentCache for the specified + /// memory buffer. + const SrcMgr::ContentCache* + createMemBufferContentCache(const llvm::MemoryBuffer *Buf); + + FileID getFileIDSlow(unsigned SLocOffset) const; + + SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const; + SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const; + + std::pair<FileID, unsigned> + getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const; + std::pair<FileID, unsigned> + getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const; +}; + + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h new file mode 100644 index 000000000000..0bcb68e4601d --- /dev/null +++ b/include/clang/Basic/SourceManagerInternals.h @@ -0,0 +1,130 @@ +//===--- SourceManagerInternals.h - SourceManager Internals -----*- 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 implementation details of the SourceManager +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCEMANAGER_INTERNALS_H +#define LLVM_CLANG_SOURCEMANAGER_INTERNALS_H + +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringMap.h" +#include <map> + +namespace clang { + +//===----------------------------------------------------------------------===// +// Line Table Implementation +//===----------------------------------------------------------------------===// + +struct LineEntry { + /// FileOffset - The offset in this file that the line entry occurs at. + unsigned FileOffset; + + /// LineNo - The presumed line number of this line entry: #line 4. + unsigned LineNo; + + /// FilenameID - The ID of the filename identified by this line entry: + /// #line 4 "foo.c". This is -1 if not specified. + int FilenameID; + + /// Flags - Set the 0 if no flags, 1 if a system header, + SrcMgr::CharacteristicKind FileKind; + + /// IncludeOffset - This is the offset of the virtual include stack location, + /// which is manipulated by GNU linemarker directives. If this is 0 then + /// there is no virtual #includer. + unsigned IncludeOffset; + + static LineEntry get(unsigned Offs, unsigned Line, int Filename, + SrcMgr::CharacteristicKind FileKind, + unsigned IncludeOffset) { + LineEntry E; + E.FileOffset = Offs; + E.LineNo = Line; + E.FilenameID = Filename; + E.FileKind = FileKind; + E.IncludeOffset = IncludeOffset; + return E; + } +}; + +// needed for FindNearestLineEntry (upper_bound of LineEntry) +inline bool operator<(const LineEntry &lhs, const LineEntry &rhs) { + // FIXME: should check the other field? + return lhs.FileOffset < rhs.FileOffset; +} + +inline bool operator<(const LineEntry &E, unsigned Offset) { + return E.FileOffset < Offset; +} + +inline bool operator<(unsigned Offset, const LineEntry &E) { + return Offset < E.FileOffset; +} + +/// LineTableInfo - This class is used to hold and unique data used to +/// represent #line information. +class LineTableInfo { + /// FilenameIDs - This map is used to assign unique IDs to filenames in + /// #line directives. This allows us to unique the filenames that + /// frequently reoccur and reference them with indices. FilenameIDs holds + /// the mapping from string -> ID, and FilenamesByID holds the mapping of ID + /// to string. + llvm::StringMap<unsigned, llvm::BumpPtrAllocator> FilenameIDs; + std::vector<llvm::StringMapEntry<unsigned>*> FilenamesByID; + + /// LineEntries - This is a map from FileIDs to a list of line entries (sorted + /// by the offset they occur in the file. + std::map<unsigned, std::vector<LineEntry> > LineEntries; +public: + LineTableInfo() { + } + + void clear() { + FilenameIDs.clear(); + FilenamesByID.clear(); + LineEntries.clear(); + } + + ~LineTableInfo() {} + + unsigned getLineTableFilenameID(const char *Ptr, unsigned Len); + const char *getFilename(unsigned ID) const { + assert(ID < FilenamesByID.size() && "Invalid FilenameID"); + return FilenamesByID[ID]->getKeyData(); + } + unsigned getNumFilenames() const { return FilenamesByID.size(); } + + void AddLineNote(unsigned FID, unsigned Offset, + unsigned LineNo, int FilenameID); + void AddLineNote(unsigned FID, unsigned Offset, + unsigned LineNo, int FilenameID, + unsigned EntryExit, SrcMgr::CharacteristicKind FileKind); + + + /// FindNearestLineEntry - Find the line entry nearest to FID that is before + /// it. If there is no line entry before Offset in FID, return null. + const LineEntry *FindNearestLineEntry(unsigned FID, unsigned Offset); + + // Low-level access + typedef std::map<unsigned, std::vector<LineEntry> >::iterator iterator; + iterator begin() { return LineEntries.begin(); } + iterator end() { return LineEntries.end(); } + + /// \brief Add a new line entry that has already been encoded into + /// the internal representation of the line table. + void AddEntry(unsigned FID, const std::vector<LineEntry> &Entries); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h new file mode 100644 index 000000000000..f577d6b32287 --- /dev/null +++ b/include/clang/Basic/TargetInfo.h @@ -0,0 +1,391 @@ +//===--- TargetInfo.h - Expose information about the target -----*- 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 TargetInfo interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETINFO_H +#define LLVM_CLANG_BASIC_TARGETINFO_H + +// FIXME: Daniel isn't smart enough to use a prototype for this. +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <vector> +#include <string> + +namespace llvm { struct fltSemantics; } + +namespace clang { + +class Diagnostic; +class SourceManager; +class LangOptions; + +namespace Builtin { struct Info; } + +/// TargetInfo - This class exposes information about the current target. +/// +class TargetInfo { + std::string Triple; +protected: + // Target values set by the ctor of the actual target implementation. Default + // values are specified by the TargetInfo constructor. + bool CharIsSigned; + bool TLSSupported; + unsigned char PointerWidth, PointerAlign; + unsigned char WCharWidth, WCharAlign; + unsigned char IntWidth, IntAlign; + unsigned char FloatWidth, FloatAlign; + unsigned char DoubleWidth, DoubleAlign; + unsigned char LongDoubleWidth, LongDoubleAlign; + unsigned char LongWidth, LongAlign; + unsigned char LongLongWidth, LongLongAlign; + unsigned char IntMaxTWidth; + const char *DescriptionString; + const char *UserLabelPrefix; + const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat; + unsigned char RegParmMax, SSERegParmMax; + + // TargetInfo Constructor. Default initializes all fields. + TargetInfo(const std::string &T); + +public: + /// CreateTargetInfo - Return the target info object for the specified target + /// triple. + static TargetInfo* CreateTargetInfo(const std::string &Triple); + + virtual ~TargetInfo(); + + ///===---- Target Data Type Query Methods -------------------------------===// + enum IntType { + NoInt = 0, + SignedShort, + UnsignedShort, + SignedInt, + UnsignedInt, + SignedLong, + UnsignedLong, + SignedLongLong, + UnsignedLongLong + }; +protected: + IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType; +public: + IntType getSizeType() const { return SizeType; } + IntType getIntMaxType() const { return IntMaxType; } + IntType getUIntMaxType() const { return UIntMaxType; } + IntType getPtrDiffType(unsigned AddrSpace) const { + return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace); + } + IntType getIntPtrType() const { return IntPtrType; } + IntType getWCharType() const { return WCharType; } + + /// isCharSigned - Return true if 'char' is 'signed char' or false if it is + /// treated as 'unsigned char'. This is implementation defined according to + /// C99 6.2.5p15. In our implementation, this is target-specific. + bool isCharSigned() const { return CharIsSigned; } + + /// getPointerWidth - Return the width of pointers on this target, for the + /// specified address space. + uint64_t getPointerWidth(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerWidth : getPointerWidthV(AddrSpace); + } + uint64_t getPointerAlign(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace); + } + + /// getBoolWidth/Align - Return the size of '_Bool' and C++ 'bool' for this + /// target, in bits. + unsigned getBoolWidth(bool isWide = false) const { return 8; } // FIXME + unsigned getBoolAlign(bool isWide = false) const { return 8; } // FIXME + + unsigned getCharWidth(bool isWide = false) const { + return isWide ? getWCharWidth() : 8; // FIXME + } + unsigned getCharAlign(bool isWide = false) const { + return isWide ? getWCharAlign() : 8; // FIXME + } + + /// getShortWidth/Align - Return the size of 'signed short' and + /// 'unsigned short' for this target, in bits. + unsigned getShortWidth() const { return 16; } // FIXME + unsigned getShortAlign() const { return 16; } // FIXME + + /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for + /// this target, in bits. + unsigned getIntWidth() const { return IntWidth; } + unsigned getIntAlign() const { return IntAlign; } + + /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' + /// for this target, in bits. + unsigned getLongWidth() const { return LongWidth; } + unsigned getLongAlign() const { return LongAlign; } + + /// getLongLongWidth/Align - Return the size of 'signed long long' and + /// 'unsigned long long' for this target, in bits. + unsigned getLongLongWidth() const { return LongLongWidth; } + unsigned getLongLongAlign() const { return LongLongAlign; } + + /// getWcharWidth/Align - Return the size of 'wchar_t' for this target, in + /// bits. + unsigned getWCharWidth() const { return WCharWidth; } + unsigned getWCharAlign() const { return WCharAlign; } + + /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. + unsigned getFloatWidth() const { return FloatWidth; } + unsigned getFloatAlign() const { return FloatAlign; } + const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; } + + /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'. + unsigned getDoubleWidth() const { return DoubleWidth; } + unsigned getDoubleAlign() const { return DoubleAlign; } + const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; } + + /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long + /// double'. + unsigned getLongDoubleWidth() const { return LongDoubleWidth; } + unsigned getLongDoubleAlign() const { return LongDoubleAlign; } + const llvm::fltSemantics &getLongDoubleFormat() const { + return *LongDoubleFormat; + } + + /// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this + /// target, in bits. + unsigned getIntMaxTWidth() const { + return IntMaxTWidth; + } + + /// getUserLabelPrefix - This returns the default value of the + /// __USER_LABEL_PREFIX__ macro, which is the prefix given to user symbols by + /// default. On most platforms this is "_", but it is "" on some, and "." on + /// others. + const char *getUserLabelPrefix() const { + return UserLabelPrefix; + } + + /// getTypeName - Return the user string for the specified integer type enum. + /// For example, SignedShort -> "short". + static const char *getTypeName(IntType T); + + ///===---- Other target property query methods --------------------------===// + + /// getTargetDefines - Appends the target-specific #define values for this + /// target set to the specified buffer. + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &DefineBuffer) const = 0; + + /// getTargetBuiltins - Return information about target-specific builtins for + /// the current primary target, and info about which builtins are non-portable + /// across the current set of primary and secondary targets. + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const = 0; + + /// getVAListDeclaration - Return the declaration to use for + /// __builtin_va_list, which is target-specific. + virtual const char *getVAListDeclaration() const = 0; + + /// isValidGCCRegisterName - Returns whether the passed in string + /// is a valid register name according to GCC. This is used by Sema for + /// inline asm statements. + bool isValidGCCRegisterName(const char *Name) const; + + // getNormalizedGCCRegisterName - Returns the "normalized" GCC register name. + // For example, on x86 it will return "ax" when "eax" is passed in. + const char *getNormalizedGCCRegisterName(const char *Name) const; + + struct ConstraintInfo { + enum { + CI_None = 0x00, + CI_AllowsMemory = 0x01, + CI_AllowsRegister = 0x02, + CI_ReadWrite = 0x04, // "+r" output constraint (read and write). + CI_HasMatchingInput = 0x08 // This output operand has a matching input. + }; + unsigned Flags; + int TiedOperand; + + std::string ConstraintStr; // constraint: "=rm" + std::string Name; // Operand name: [foo] with no []'s. + public: + ConstraintInfo(const char *str, unsigned strlen, const std::string &name) + : Flags(0), TiedOperand(-1), ConstraintStr(str, str+strlen), Name(name) {} + explicit ConstraintInfo(const std::string &Str, const std::string &name) + : Flags(0), TiedOperand(-1), ConstraintStr(Str), Name(name) {} + + const std::string &getConstraintStr() const { return ConstraintStr; } + const std::string &getName() const { return Name; } + bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } + bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } + bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } + + /// hasMatchingInput - Return true if this output operand has a matching + /// (tied) input operand. + bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } + + /// hasTiedOperand() - Return true if this input operand is a matching + /// constraint that ties it to an output operand. If this returns true, + /// then getTiedOperand will indicate which output operand this is tied to. + bool hasTiedOperand() const { return TiedOperand != -1; } + unsigned getTiedOperand() const { + assert(hasTiedOperand() && "Has no tied operand!"); + return (unsigned)TiedOperand; + } + + void setIsReadWrite() { Flags |= CI_ReadWrite; } + void setAllowsMemory() { Flags |= CI_AllowsMemory; } + void setAllowsRegister() { Flags |= CI_AllowsRegister; } + void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } + + /// setTiedOperand - Indicate that this is an input operand that is tied to + /// the specified output operand. Copy over the various constraint + /// information from the output. + void setTiedOperand(unsigned N, ConstraintInfo &Output) { + Output.setHasMatchingInput(); + Flags = Output.Flags; + TiedOperand = N; + // Don't copy Name or constraint string. + } + }; + + // validateOutputConstraint, validateInputConstraint - Checks that + // a constraint is valid and provides information about it. + // FIXME: These should return a real error instead of just true/false. + bool validateOutputConstraint(ConstraintInfo &Info) const; + bool validateInputConstraint(ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + ConstraintInfo &info) const; + bool resolveSymbolicName(const char *&Name, + ConstraintInfo *OutputConstraints, + unsigned NumOutputs, unsigned &Index) const; + + virtual std::string convertConstraint(const char Constraint) const { + return std::string(1, Constraint); + } + + // Returns a string of target-specific clobbers, in LLVM format. + virtual const char *getClobbers() const = 0; + + + /// getTargetPrefix - Return the target prefix used for identifying + /// llvm intrinsics. + virtual const char *getTargetPrefix() const = 0; + + /// getTargetTriple - Return the target triple of the primary target. + const char *getTargetTriple() const { + return Triple.c_str(); + } + + const char *getTargetDescription() const { + return DescriptionString; + } + + struct GCCRegAlias { + const char * const Aliases[5]; + const char * const Register; + }; + + virtual bool useGlobalsForAutomaticVariables() const { return false; } + + /// getStringSymbolPrefix - Get the default symbol prefix to + /// use for string literals. + virtual const char *getStringSymbolPrefix(bool IsConstant) const { + return ".str"; + } + + /// getCFStringSymbolPrefix - Get the default symbol prefix + /// to use for CFString literals. + virtual const char *getCFStringSymbolPrefix() const { + return ""; + } + + /// getUnicodeStringSymbolPrefix - Get the default symbol prefix to + /// use for string literals. + virtual const char *getUnicodeStringSymbolPrefix() const { + return ".str"; + } + + /// getUnicodeStringSection - Return the section to use for unicode + /// string literals, or 0 if no special section is used. + virtual const char *getUnicodeStringSection() const { + return 0; + } + + /// getCFStringSection - Return the section to use for CFString + /// literals, or 0 if no special section is used. + virtual const char *getCFStringSection() const { + return "__DATA,__cfstring"; + } + + /// getCFStringDataSection - Return the section to use for the + /// constant string data associated with a CFString literal, or 0 if + /// no special section is used. + virtual const char *getCFStringDataSection() const { + return "__TEXT,__cstring,cstring_literals"; + } + + /// getDefaultLangOptions - Allow the target to specify default settings for + /// various language options. These may be overridden by command line + /// options. + virtual void getDefaultLangOptions(LangOptions &Opts) {} + + /// getDefaultFeatures - Get the default set of target features for + /// the \args CPU; this should include all legal feature strings on + /// the target. + virtual void getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const { + } + + /// setFeatureEnabled - Enable or disable a specific target feature, + /// the feature name must be valid. + /// + /// \return - False on error (invalid feature name). + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const { + return false; + } + + /// HandleTargetOptions - Perform initialization based on the user + /// configured set of features. + virtual void HandleTargetFeatures(const llvm::StringMap<bool> &Features) { + } + + // getRegParmMax - Returns maximal number of args passed in registers. + unsigned getRegParmMax() const { + return RegParmMax; + } + + // isTLSSupported - Whether the target supports thread-local storage + unsigned isTLSSupported() const { + return TLSSupported; + } + +protected: + virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { + return PointerWidth; + } + virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { + return PointerAlign; + } + virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const { + return PtrDiffType; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const = 0; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const = 0; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const= 0; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h new file mode 100644 index 000000000000..c6ea05bb1396 --- /dev/null +++ b/include/clang/Basic/TemplateKinds.h @@ -0,0 +1,39 @@ +//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- 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 TemplateNameKind enum. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_TEMPLATEKINDS_H +#define LLVM_CLANG_TEMPLATEKINDS_H + +namespace clang { + +/// \brief Specifies the kind of template name that an identifier refers to. +enum TemplateNameKind { + /// The name does not refer to a template. + TNK_Non_template = 0, + /// The name refers to a function template or a set of overloaded + /// functions that includes at least one function template. + TNK_Function_template, + /// The name refers to a template whose specialization produces a + /// type. The template itself could be a class template, template + /// template parameter, or C++0x template alias. + TNK_Type_template, + /// The name refers to a dependent template name. Whether the + /// template name is assumed to refer to a type template or a + /// function template depends on the context in which the template + /// name occurs. + TNK_Dependent_template_name +}; + +} +#endif + + diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def new file mode 100644 index 000000000000..9b65288f68e1 --- /dev/null +++ b/include/clang/Basic/TokenKinds.def @@ -0,0 +1,413 @@ +//===--- TokenKinds.def - C Family Token Kind Database ----------*- 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 TokenKind database. This includes normal tokens like +// tok::ampamp (corresponding to the && token) as well as keywords for various +// languages. Users of this file must optionally #define the TOK, KEYWORD, +// ALIAS, or PPKEYWORD macros to make use of this file. +// +//===----------------------------------------------------------------------===// + +#ifndef TOK +#define TOK(X) +#endif +#ifndef KEYWORD +#define KEYWORD(X,Y) TOK(kw_ ## X) +#endif +#ifndef ALIAS +#define ALIAS(X,Y,Z) +#endif +#ifndef PPKEYWORD +#define PPKEYWORD(X) +#endif +#ifndef CXX_KEYWORD_OPERATOR +#define CXX_KEYWORD_OPERATOR(X,Y) +#endif +#ifndef OBJC1_AT_KEYWORD +#define OBJC1_AT_KEYWORD(X) +#endif +#ifndef OBJC2_AT_KEYWORD +#define OBJC2_AT_KEYWORD(X) +#endif +#ifndef ANNOTATION +#define ANNOTATION(X) TOK(annot_ ## X) +#endif + +//===----------------------------------------------------------------------===// +// Preprocessor keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after a '#' at the start of a line. These define enums in +// the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be +// manually updated if something is added here. +PPKEYWORD(not_keyword) + +// C99 6.10.1 - Conditional Inclusion. +PPKEYWORD(if) +PPKEYWORD(ifdef) +PPKEYWORD(ifndef) +PPKEYWORD(elif) +PPKEYWORD(else) +PPKEYWORD(endif) +PPKEYWORD(defined) + +// C99 6.10.2 - Source File Inclusion. +PPKEYWORD(include) +PPKEYWORD(__include_macros) + +// C99 6.10.3 - Macro Replacement. +PPKEYWORD(define) +PPKEYWORD(undef) + +// C99 6.10.4 - Line Control. +PPKEYWORD(line) + +// C99 6.10.5 - Error Directive. +PPKEYWORD(error) + +// C99 6.10.6 - Pragma Directive. +PPKEYWORD(pragma) + +// GNU Extensions. +PPKEYWORD(import) +PPKEYWORD(include_next) +PPKEYWORD(warning) +PPKEYWORD(ident) +PPKEYWORD(sccs) +PPKEYWORD(assert) +PPKEYWORD(unassert) + +//===----------------------------------------------------------------------===// +// Language keywords. +//===----------------------------------------------------------------------===// + +// These define members of the tok::* namespace. + +TOK(unknown) // Not a token. +TOK(eof) // End of file. +TOK(eom) // End of macro (end of line inside a macro). + +// C99 6.4.9: Comments. +TOK(comment) // Comment (only in -E -C[C] mode) + +// C99 6.4.2: Identifiers. +TOK(identifier) // abcde123 + +// C99 6.4.4.1: Integer Constants +// C99 6.4.4.2: Floating Constants +TOK(numeric_constant) // 0x123 + +// C99 6.4.4: Character Constants +TOK(char_constant) // 'a' L'b' + +// C99 6.4.5: String Literals. +TOK(string_literal) // "foo" +TOK(wide_string_literal) // L"foo" +TOK(angle_string_literal)// <foo> + +// C99 6.4.6: Punctuators. +TOK(l_square) // [ +TOK(r_square) // ] +TOK(l_paren) // ( +TOK(r_paren) // ) +TOK(l_brace) // { +TOK(r_brace) // } +TOK(period) // . +TOK(ellipsis) // ... +TOK(amp) // & +TOK(ampamp) // && +TOK(ampequal) // &= +TOK(star) // * +TOK(starequal) // *= +TOK(plus) // + +TOK(plusplus) // ++ +TOK(plusequal) // += +TOK(minus) // - +TOK(arrow) // -> +TOK(minusminus) // -- +TOK(minusequal) // -= +TOK(tilde) // ~ +TOK(exclaim) // ! +TOK(exclaimequal) // != +TOK(slash) // / +TOK(slashequal) // /= +TOK(percent) // % +TOK(percentequal) // %= +TOK(less) // < +TOK(lessless) // << +TOK(lessequal) // <= +TOK(lesslessequal) // <<= +TOK(greater) // > +TOK(greatergreater) // >> +TOK(greaterequal) // >= +TOK(greatergreaterequal) // >>= +TOK(caret) // ^ +TOK(caretequal) // ^= +TOK(pipe) // | +TOK(pipepipe) // || +TOK(pipeequal) // |= +TOK(question) // ? +TOK(colon) // : +TOK(semi) // ; +TOK(equal) // = +TOK(equalequal) // == +TOK(comma) // , +TOK(hash) // # +TOK(hashhash) // ## +TOK(hashat) // #@ + +// C++ Support +TOK(periodstar) // .* +TOK(arrowstar) // ->* +TOK(coloncolon) // :: + +// Objective C support. +TOK(at) // @ + + +// 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 +// is a keyword in the implementation namespace that should +// always be treated as a keyword +// 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 +// 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 +// +KEYWORD(auto , KEYALL) +KEYWORD(break , KEYALL) +KEYWORD(case , KEYALL) +KEYWORD(char , KEYALL) +KEYWORD(const , KEYALL) +KEYWORD(continue , KEYALL) +KEYWORD(default , KEYALL) +KEYWORD(do , KEYALL) +KEYWORD(double , KEYALL) +KEYWORD(else , KEYALL) +KEYWORD(enum , KEYALL) +KEYWORD(extern , KEYALL) +KEYWORD(float , KEYALL) +KEYWORD(for , KEYALL) +KEYWORD(goto , KEYALL) +KEYWORD(if , KEYALL) +KEYWORD(inline , KEYC99|KEYCXX|KEYGNU) +KEYWORD(int , KEYALL) +KEYWORD(long , KEYALL) +KEYWORD(register , KEYALL) +KEYWORD(restrict , KEYC99) +KEYWORD(return , KEYALL) +KEYWORD(short , KEYALL) +KEYWORD(signed , KEYALL) +KEYWORD(sizeof , KEYALL) +KEYWORD(static , KEYALL) +KEYWORD(struct , KEYALL) +KEYWORD(switch , KEYALL) +KEYWORD(typedef , KEYALL) +KEYWORD(union , KEYALL) +KEYWORD(unsigned , KEYALL) +KEYWORD(void , KEYALL) +KEYWORD(volatile , KEYALL) +KEYWORD(while , KEYALL) +KEYWORD(_Bool , KEYALL) +KEYWORD(_Complex , KEYALL) +KEYWORD(_Imaginary , KEYALL) +KEYWORD(__func__ , KEYALL) + +// C++ 2.11p1: Keywords. +KEYWORD(asm , KEYCXX|KEYGNU) +KEYWORD(bool , KEYCXX) +KEYWORD(catch , KEYCXX) +KEYWORD(class , KEYCXX) +KEYWORD(const_cast , KEYCXX) +KEYWORD(delete , KEYCXX) +KEYWORD(dynamic_cast , KEYCXX) +KEYWORD(explicit , KEYCXX) +KEYWORD(export , KEYCXX) +KEYWORD(false , KEYCXX) +KEYWORD(friend , KEYCXX) +KEYWORD(mutable , KEYCXX) +KEYWORD(namespace , KEYCXX) +KEYWORD(new , KEYCXX) +KEYWORD(operator , KEYCXX) +KEYWORD(private , KEYCXX) +KEYWORD(protected , KEYCXX) +KEYWORD(public , KEYCXX) +KEYWORD(reinterpret_cast , KEYCXX) +KEYWORD(static_cast , KEYCXX) +KEYWORD(template , KEYCXX) +KEYWORD(this , KEYCXX) +KEYWORD(throw , KEYCXX) +KEYWORD(true , KEYCXX) +KEYWORD(try , KEYCXX) +KEYWORD(typename , KEYCXX) +KEYWORD(typeid , KEYCXX) +KEYWORD(using , KEYCXX) +KEYWORD(virtual , KEYCXX) +KEYWORD(wchar_t , KEYCXX) + +// C++ 2.5p2: Alternative Representations. +CXX_KEYWORD_OPERATOR(and , ampamp) +CXX_KEYWORD_OPERATOR(and_eq , ampequal) +CXX_KEYWORD_OPERATOR(bitand , amp) +CXX_KEYWORD_OPERATOR(bitor , pipe) +CXX_KEYWORD_OPERATOR(compl , tilde) +CXX_KEYWORD_OPERATOR(not , exclaim) +CXX_KEYWORD_OPERATOR(not_eq , exclaimequal) +CXX_KEYWORD_OPERATOR(or , pipepipe) +CXX_KEYWORD_OPERATOR(or_eq , pipeequal) +CXX_KEYWORD_OPERATOR(xor , caret) +CXX_KEYWORD_OPERATOR(xor_eq , caretequal) + +// C++0x keywords +KEYWORD(alignof , KEYCXX0X) +KEYWORD(axiom , KEYCXX0X) +KEYWORD(char16_t , KEYCXX0X) +KEYWORD(char32_t , KEYCXX0X) +KEYWORD(concept , KEYCXX0X) +KEYWORD(concept_map , KEYCXX0X) +KEYWORD(constexpr , KEYCXX0X) +KEYWORD(decltype , KEYCXX0X) +KEYWORD(late_check , KEYCXX0X) +KEYWORD(nullptr , KEYCXX0X) +KEYWORD(requires , KEYCXX0X) +KEYWORD(static_assert , KEYCXX0X) +KEYWORD(thread_local , KEYCXX0X) + +// GNU Extensions (in impl-reserved namespace) +KEYWORD(_Decimal32 , KEYALL) +KEYWORD(_Decimal64 , KEYALL) +KEYWORD(_Decimal128 , KEYALL) +KEYWORD(__null , KEYCXX) +KEYWORD(__alignof , KEYALL) +KEYWORD(__attribute , KEYALL) +KEYWORD(__builtin_choose_expr , KEYALL) +KEYWORD(__builtin_offsetof , KEYALL) +KEYWORD(__builtin_types_compatible_p, KEYALL) +KEYWORD(__builtin_va_arg , KEYALL) +KEYWORD(__extension__ , KEYALL) +KEYWORD(__imag , KEYALL) +KEYWORD(__label__ , KEYALL) +KEYWORD(__real , KEYALL) +KEYWORD(__thread , KEYALL) +KEYWORD(__FUNCTION__ , KEYALL) +KEYWORD(__PRETTY_FUNCTION__ , KEYALL) + +// GNU Extensions (outside impl-reserved namespace) +KEYWORD(typeof , KEYGNU) + +// GNU and MS Type Traits +KEYWORD(__has_nothrow_assign , KEYCXX) +KEYWORD(__has_nothrow_copy , KEYCXX) +KEYWORD(__has_nothrow_constructor , KEYCXX) +KEYWORD(__has_trivial_assign , KEYCXX) +KEYWORD(__has_trivial_copy , KEYCXX) +KEYWORD(__has_trivial_constructor , KEYCXX) +KEYWORD(__has_trivial_destructor , KEYCXX) +KEYWORD(__has_virtual_destructor , KEYCXX) +KEYWORD(__is_abstract , KEYCXX) +KEYWORD(__is_base_of , KEYCXX) +KEYWORD(__is_class , KEYCXX) +KEYWORD(__is_empty , KEYCXX) +KEYWORD(__is_enum , KEYCXX) +KEYWORD(__is_pod , KEYCXX) +KEYWORD(__is_polymorphic , KEYCXX) +KEYWORD(__is_union , KEYCXX) +// FIXME: Add MS's traits, too. + +// Apple Extension. +KEYWORD(__private_extern__ , KEYALL) + +// Microsoft Extension. +KEYWORD(__declspec , KEYALL) +KEYWORD(__cdecl , KEYALL) +KEYWORD(__stdcall , KEYALL) +KEYWORD(__fastcall , KEYALL) +KEYWORD(__ptr64 , KEYALL) +KEYWORD(__w64 , KEYALL) +KEYWORD(__forceinline , KEYALL) + +// Alternate spelling for various tokens. There are GCC extensions in all +// languages, but should not be disabled in strict conformance mode. +ALIAS("__attribute__", __attribute, KEYALL) +ALIAS("__const" , const , KEYALL) +ALIAS("__const__" , const , KEYALL) +ALIAS("__alignof__" , __alignof , KEYALL) +ALIAS("_asm" , asm , KEYMS) +ALIAS("__asm" , asm , KEYALL) +ALIAS("__asm__" , asm , KEYALL) +ALIAS("__complex" , _Complex , KEYALL) +ALIAS("__complex__" , _Complex , KEYALL) +ALIAS("__imag__" , __imag , KEYALL) +ALIAS("__inline" , inline , KEYALL) +ALIAS("__inline__" , inline , KEYALL) +ALIAS("__real__" , __real , KEYALL) +ALIAS("__restrict" , restrict , KEYALL) +ALIAS("__restrict__" , restrict , KEYALL) +ALIAS("__signed" , signed , KEYALL) +ALIAS("__signed__" , signed , KEYALL) +ALIAS("__typeof" , typeof , KEYALL) +ALIAS("__typeof__" , typeof , KEYALL) +ALIAS("__volatile" , volatile , KEYALL) +ALIAS("__volatile__" , volatile , KEYALL) + + +//===----------------------------------------------------------------------===// +// Objective-C @-preceeded keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after an '@' in Objective-C mode. These define enums in +// the tok::objc_* namespace. + +OBJC1_AT_KEYWORD(not_keyword) +OBJC1_AT_KEYWORD(class) +OBJC1_AT_KEYWORD(compatibility_alias) +OBJC1_AT_KEYWORD(defs) +OBJC1_AT_KEYWORD(encode) +OBJC1_AT_KEYWORD(end) +OBJC1_AT_KEYWORD(implementation) +OBJC1_AT_KEYWORD(interface) +OBJC1_AT_KEYWORD(private) +OBJC1_AT_KEYWORD(protected) +OBJC1_AT_KEYWORD(protocol) +OBJC1_AT_KEYWORD(public) +OBJC1_AT_KEYWORD(selector) +OBJC1_AT_KEYWORD(throw) +OBJC1_AT_KEYWORD(try) +OBJC1_AT_KEYWORD(catch) +OBJC1_AT_KEYWORD(finally) +OBJC1_AT_KEYWORD(synchronized) + +OBJC2_AT_KEYWORD(property) +OBJC2_AT_KEYWORD(package) +OBJC2_AT_KEYWORD(required) +OBJC2_AT_KEYWORD(optional) +OBJC2_AT_KEYWORD(synthesize) +OBJC2_AT_KEYWORD(dynamic) + +// TODO: What to do about context-sensitive keywords like: +// bycopy/byref/in/inout/oneway/out? + +ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::" +ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly + // qualified) typename, e.g. "foo::MyClass", or + // template-id that names a type ("std::vector<int>") +ANNOTATION(template_id) // annotation for a C++ template-id that names a + // function template specialization (not a type), + // e.g., "std::swap<int>" +#undef ANNOTATION +#undef OBJC2_AT_KEYWORD +#undef OBJC1_AT_KEYWORD +#undef CXX_KEYWORD_OPERATOR +#undef PPKEYWORD +#undef ALIAS +#undef KEYWORD +#undef TOK diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h new file mode 100644 index 000000000000..62a9e428bf21 --- /dev/null +++ b/include/clang/Basic/TokenKinds.h @@ -0,0 +1,64 @@ +//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- 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 TokenKind enum and support functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENKINDS_H +#define LLVM_CLANG_TOKENKINDS_H + +namespace clang { + +namespace tok { + +/// TokenKind - This provides a simple uniform namespace for tokens from all C +/// languages. +enum TokenKind { +#define TOK(X) X, +#include "clang/Basic/TokenKinds.def" + NUM_TOKENS +}; + +/// PPKeywordKind - This provides a namespace for preprocessor keywords which +/// start with a '#' at the beginning of the line. +enum PPKeywordKind { +#define PPKEYWORD(X) pp_##X, +#include "clang/Basic/TokenKinds.def" + NUM_PP_KEYWORDS +}; + +/// ObjCKeywordKind - This provides a namespace for Objective-C keywords which +/// start with an '@'. +enum ObjCKeywordKind { +#define OBJC1_AT_KEYWORD(X) objc_##X, +#define OBJC2_AT_KEYWORD(X) objc_##X, +#include "clang/Basic/TokenKinds.def" + NUM_OBJC_KEYWORDS +}; + +/// \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") +/// and should not be used as part of diagnostic messages. +const char *getTokenName(enum TokenKind Kind); + +/// \brief Determines the spelling of simple punctuation tokens like +/// '!' or '%', and returns NULL for literal and annotation tokens. +/// +/// This routine only retrieves the "simple" spelling of the token, +/// and will not produce any alternative spellings (e.g., a +/// digraph). For the actual spelling of a given Token, use +/// Preprocessor::getSpelling(). +const char *getTokenSimpleSpelling(enum TokenKind Kind); + +} // end namespace tok +} // end namespace clang + +#endif diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h new file mode 100644 index 000000000000..2a2eacc4caac --- /dev/null +++ b/include/clang/Basic/TypeTraits.h @@ -0,0 +1,40 @@ +//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- 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 enumerations for the type traits support. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TYPETRAITS_H +#define LLVM_CLANG_TYPETRAITS_H + +namespace clang { + + /// UnaryTypeTrait - Names for the unary type traits. + enum UnaryTypeTrait { + UTT_HasNothrowAssign, + UTT_HasNothrowCopy, + UTT_HasNothrowConstructor, + UTT_HasTrivialAssign, + UTT_HasTrivialCopy, + UTT_HasTrivialConstructor, + UTT_HasTrivialDestructor, + UTT_HasVirtualDestructor, + UTT_IsAbstract, + UTT_IsClass, + UTT_IsEmpty, + UTT_IsEnum, + UTT_IsPOD, + UTT_IsPolymorphic, + UTT_IsUnion + }; + +} + +#endif diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h new file mode 100644 index 000000000000..f0e1aa7db233 --- /dev/null +++ b/include/clang/Basic/Version.h @@ -0,0 +1,35 @@ +//===- Version.h - Clang Version Number -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines version macros for Clang. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_VERSION_H +#define LLVM_CLANG_BASIC_VERSION_H + +/// \brief Clang major version +#define CLANG_VERSION_MAJOR 1 + +/// \brief Clang minor version +#define CLANG_VERSION_MINOR 0 + +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING2(X) #X + +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y) + +/// \brief A string that describes the Clang version number, e.g., +/// "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR) + + +#endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt new file mode 100644 index 000000000000..39e3698a1655 --- /dev/null +++ b/include/clang/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Basic) diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h new file mode 100644 index 000000000000..5812da1b562e --- /dev/null +++ b/include/clang/CodeGen/ModuleBuilder.h @@ -0,0 +1,40 @@ +//===--- CodeGen/ModuleBuilder.h - Build LLVM from ASTs ---------*- 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 ModuleBuilder interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_MODULEBUILDER_H +#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H + +#include "clang/AST/ASTConsumer.h" +#include <string> + +namespace llvm { + class Module; +} + +namespace clang { + class Diagnostic; + class LangOptions; + class CompileOptions; + + class CodeGenerator : public ASTConsumer { + public: + virtual llvm::Module* GetModule() = 0; + virtual llvm::Module* ReleaseModule() = 0; + }; + + CodeGenerator *CreateLLVMCodeGen(Diagnostic &Diags, + const std::string &ModuleName, + const CompileOptions &CO); +} + +#endif diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h new file mode 100644 index 000000000000..b9bf671db2bd --- /dev/null +++ b/include/clang/Driver/Action.h @@ -0,0 +1,209 @@ +//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ACTION_H_ +#define CLANG_DRIVER_ACTION_H_ + +#include "llvm/ADT/SmallVector.h" + +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" + +#include "llvm/Support/Casting.h" +using llvm::isa; +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; + +namespace clang { +namespace driver { + class Arg; + +/// Action - Represent an abstract compilation step to perform. +/// +/// An action represents an edge in the compilation graph; typically +/// it is a job to transform an input using some tool. +/// +/// The current driver is hard wired to expect actions which produce a +/// single primary output, at least in terms of controlling the +/// compilation. Actions can produce auxiliary files, but can only +/// produce a single output to feed into subsequent actions. +class Action { +public: + typedef ActionList::size_type size_type; + typedef ActionList::iterator iterator; + typedef ActionList::const_iterator const_iterator; + + enum ActionClass { + InputClass = 0, + BindArchClass, + PreprocessJobClass, + PrecompileJobClass, + AnalyzeJobClass, + CompileJobClass, + AssembleJobClass, + LinkJobClass, + LipoJobClass, + + JobClassFirst=PreprocessJobClass, + JobClassLast=LipoJobClass + }; + + static const char *getClassName(ActionClass AC); + +private: + ActionClass Kind; + + /// The output type of this action. + types::ID Type; + + ActionList Inputs; + +protected: + Action(ActionClass _Kind, types::ID _Type) : Kind(_Kind), Type(_Type) {} + Action(ActionClass _Kind, Action *Input, types::ID _Type) + : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1) {} + Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) + : Kind(_Kind), Type(_Type), Inputs(_Inputs) {} +public: + virtual ~Action(); + + ActionClass getKind() const { return Kind; } + types::ID getType() const { return Type; } + + ActionList &getInputs() { return Inputs; } + const ActionList &getInputs() const { return Inputs; } + + size_type size() const { return Inputs.size(); } + + iterator begin() { return Inputs.begin(); } + iterator end() { return Inputs.end(); } + const_iterator begin() const { return Inputs.begin(); } + const_iterator end() const { return Inputs.end(); } + + static bool classof(const Action *) { return true; } +}; + +class InputAction : public Action { + const Arg &Input; +public: + InputAction(const Arg &_Input, types::ID _Type); + + const Arg &getInputArg() const { return Input; } + + static bool classof(const Action *A) { + return A->getKind() == InputClass; + } + static bool classof(const InputAction *) { return true; } +}; + +class BindArchAction : public Action { + /// The architecture to bind, or 0 if the default architecture + /// should be bound. + const char *ArchName; + +public: + BindArchAction(Action *Input, const char *_ArchName); + + const char *getArchName() const { return ArchName; } + + static bool classof(const Action *A) { + return A->getKind() == BindArchClass; + } + static bool classof(const BindArchAction *) { return true; } +}; + +class JobAction : public Action { +protected: + JobAction(ActionClass Kind, Action *Input, types::ID Type); + JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); + +public: + static bool classof(const Action *A) { + return (A->getKind() >= JobClassFirst && + A->getKind() <= JobClassLast); + } + static bool classof(const JobAction *) { return true; } +}; + +class PreprocessJobAction : public JobAction { +public: + PreprocessJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PreprocessJobClass; + } + static bool classof(const PreprocessJobAction *) { return true; } +}; + +class PrecompileJobAction : public JobAction { +public: + PrecompileJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PrecompileJobClass; + } + static bool classof(const PrecompileJobAction *) { return true; } +}; + +class AnalyzeJobAction : public JobAction { +public: + AnalyzeJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AnalyzeJobClass; + } + static bool classof(const AnalyzeJobAction *) { return true; } +}; + +class CompileJobAction : public JobAction { +public: + CompileJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == CompileJobClass; + } + static bool classof(const CompileJobAction *) { return true; } +}; + +class AssembleJobAction : public JobAction { +public: + AssembleJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AssembleJobClass; + } + static bool classof(const AssembleJobAction *) { return true; } +}; + +class LinkJobAction : public JobAction { +public: + LinkJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LinkJobClass; + } + static bool classof(const LinkJobAction *) { return true; } +}; + +class LipoJobAction : public JobAction { +public: + LipoJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LipoJobClass; + } + static bool classof(const LipoJobAction *) { return true; } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h new file mode 100644 index 000000000000..6bed2b8cbdef --- /dev/null +++ b/include/clang/Driver/Arg.h @@ -0,0 +1,230 @@ +//===--- Arg.h - Parsed Argument Classes ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ARG_H_ +#define CLANG_DRIVER_ARG_H_ + +#include "llvm/Support/Casting.h" +using llvm::isa; +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; + +#include "Util.h" +#include <vector> +#include <string> + +namespace clang { +namespace driver { + class ArgList; + class Option; + + /// Arg - A concrete instance of a particular driver option. + /// + /// The Arg class encodes just enough information to be able to + /// derive the argument values efficiently. In addition, Arg + /// instances have an intrusive double linked list which is used by + /// ArgList to provide efficient iteration over all instances of a + /// particular option. + class Arg { + public: + enum ArgClass { + FlagClass = 0, + PositionalClass, + JoinedClass, + SeparateClass, + CommaJoinedClass, + JoinedAndSeparateClass + }; + + private: + ArgClass Kind; + + /// The option this argument is an instance of. + const Option *Opt; + + /// The argument this argument was derived from (during tool chain + /// argument translation), if any. + const Arg *BaseArg; + + /// The index at which this argument appears in the containing + /// ArgList. + unsigned Index; + + /// Flag indicating whether this argument was used to effect + /// compilation; used for generating "argument unused" + /// diagnostics. + mutable bool Claimed; + + protected: + Arg(ArgClass Kind, const Option *Opt, unsigned Index, + const Arg *BaseArg = 0); + + public: + Arg(const Arg &); + virtual ~Arg(); + + ArgClass getKind() const { return Kind; } + const Option &getOption() const { return *Opt; } + unsigned getIndex() const { return Index; } + + /// getBaseArg - Return the base argument which generated this + /// arg; this is either the argument itself or the argument it was + /// derived from during tool chain specific argument translation. + const Arg &getBaseArg() const { + return BaseArg ? *BaseArg : *this; + } + void setBaseArg(const Arg *_BaseArg) { + BaseArg = _BaseArg; + } + + bool isClaimed() const { return getBaseArg().Claimed; } + + /// claim - Set the Arg claimed bit. + + // FIXME: We need to deal with derived arguments and set the bit + // in the original argument; not the derived one. + void claim() const { getBaseArg().Claimed = true; } + + virtual unsigned getNumValues() const = 0; + virtual const char *getValue(const ArgList &Args, unsigned N=0) const = 0; + + /// render - Append the argument onto the given array as strings. + virtual void render(const ArgList &Args, ArgStringList &Output) const = 0; + + /// renderAsInput - Append the argument, render as an input, onto + /// the given array as strings. The distinction is that some + /// options only render their values when rendered as a input + /// (e.g., Xlinker). + void renderAsInput(const ArgList &Args, ArgStringList &Output) const; + + static bool classof(const Arg *) { return true; } + + void dump() const; + + /// getAsString - Return a formatted version of the argument and + /// its values, for debugging and diagnostics. + std::string getAsString(const ArgList &Args) const; + }; + + /// FlagArg - An argument with no value. + class FlagArg : public Arg { + public: + FlagArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return 0; } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::FlagClass; + } + static bool classof(const FlagArg *) { return true; } + }; + + /// PositionalArg - A simple positional argument. + class PositionalArg : public Arg { + public: + PositionalArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return 1; } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::PositionalClass; + } + static bool classof(const PositionalArg *) { return true; } + }; + + /// JoinedArg - A single value argument where the value is joined + /// (suffixed) to the option. + class JoinedArg : public Arg { + public: + JoinedArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return 1; } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::JoinedClass; + } + static bool classof(const JoinedArg *) { return true; } + }; + + /// SeparateArg - An argument where one or more values follow the + /// option specifier immediately in the argument vector. + class SeparateArg : public Arg { + unsigned NumValues; + + public: + SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues, + const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return NumValues; } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::SeparateClass; + } + static bool classof(const SeparateArg *) { return true; } + }; + + /// CommaJoinedArg - An argument with multiple values joined by + /// commas and joined (suffixed) to the option specifier. + /// + /// The key point of this arg is that it renders its values into + /// separate arguments, which allows it to be used as a generic + /// mechanism for passing arguments through to tools. + class CommaJoinedArg : public Arg { + std::vector<std::string> Values; + + public: + CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str, + const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return Values.size(); } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::CommaJoinedClass; + } + static bool classof(const CommaJoinedArg *) { return true; } + }; + + /// JoinedAndSeparateArg - An argument with both joined and separate + /// values. + class JoinedAndSeparateArg : public Arg { + public: + JoinedAndSeparateArg(const Option *Opt, unsigned Index, + const Arg *BaseArg = 0); + + virtual void render(const ArgList &Args, ArgStringList &Output) const; + + virtual unsigned getNumValues() const { return 2; } + virtual const char *getValue(const ArgList &Args, unsigned N=0) const; + + static bool classof(const Arg *A) { + return A->getKind() == Arg::JoinedAndSeparateClass; + } + static bool classof(const JoinedAndSeparateArg *) { return true; } + }; +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h new file mode 100644 index 000000000000..84e0329a375e --- /dev/null +++ b/include/clang/Driver/ArgList.h @@ -0,0 +1,245 @@ +//===--- ArgList.h - Argument List Management ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ARGLIST_H_ +#define CLANG_DRIVER_ARGLIST_H_ + +#include "clang/Driver/Options.h" + +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" + +#include <list> + +namespace clang { +namespace driver { + class Arg; + + /// ArgList - Ordered collection of driver arguments. + /// + /// The ArgList class manages a list of Arg instances as well as + /// auxiliary data and convenience methods to allow Tools to quickly + /// check for the presence of Arg instances for a particular Option + /// and to iterate over groups of arguments. + class ArgList { + public: + typedef llvm::SmallVector<Arg*, 16> arglist_type; + typedef arglist_type::iterator iterator; + typedef arglist_type::const_iterator const_iterator; + typedef arglist_type::reverse_iterator reverse_iterator; + typedef arglist_type::const_reverse_iterator const_reverse_iterator; + + private: + /// The full list of arguments. + arglist_type &Args; + + protected: + ArgList(arglist_type &Args); + + public: + virtual ~ArgList(); + + /// @name Arg Access + /// @{ + + /// append - Append \arg A to the arg list. + void append(Arg *A); + + arglist_type &getArgs() { return Args; } + const arglist_type &getArgs() const { return Args; } + + unsigned size() const { return Args.size(); } + + iterator begin() { return Args.begin(); } + iterator end() { return Args.end(); } + + reverse_iterator rbegin() { return Args.rbegin(); } + reverse_iterator rend() { return Args.rend(); } + + const_iterator begin() const { return Args.begin(); } + const_iterator end() const { return Args.end(); } + + const_reverse_iterator rbegin() const { return Args.rbegin(); } + const_reverse_iterator rend() const { return Args.rend(); } + + /// hasArg - Does the arg list contain any option matching \arg Id. + /// + /// \arg Claim Whether the argument should be claimed, if it exists. + bool hasArg(options::ID Id, bool Claim=true) const { + return getLastArg(Id, Claim) != 0; + } + bool hasArg(options::ID Id0, options::ID Id1, bool Claim=true) const { + return getLastArg(Id0, Id1, Claim) != 0; + } + + /// getLastArg - Return the last argument matching \arg Id, or null. + /// + /// \arg Claim Whether the argument should be claimed, if it exists. + Arg *getLastArg(options::ID Id, bool Claim=true) const; + Arg *getLastArg(options::ID Id0, options::ID Id1, bool Claim=true) const; + + /// getArgString - Return the input argument string at \arg Index. + virtual const char *getArgString(unsigned Index) const = 0; + /// @name Translation Utilities + /// @{ + + /// hasFlag - Given an option \arg Pos and its negative form \arg + /// Neg, return true if the option is present, false if the + /// negation is present, and \arg Default if neither option is + /// given. If both the option and its negation are present, the + /// last one wins. + bool hasFlag(options::ID Pos, options::ID Neg, bool Default=true) const; + + /// AddLastArg - Render only the last argument match \arg Id0, if + /// present. + void AddLastArg(ArgStringList &Output, options::ID Id0) const; + + /// AddAllArgs - Render all arguments matching the given ids. + void AddAllArgs(ArgStringList &Output, options::ID Id0) const; + void AddAllArgs(ArgStringList &Output, options::ID Id0, + options::ID Id1) const; + void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1, + options::ID Id2) const; + + /// AddAllArgValues - Render the argument values of all arguments + /// matching the given ids. + void AddAllArgValues(ArgStringList &Output, options::ID Id0) const; + void AddAllArgValues(ArgStringList &Output, options::ID Id0, + options::ID Id1) const; + + /// AddAllArgsTranslated - Render all the arguments matching the + /// given ids, but forced to separate args and using the provided + /// name instead of the first option value. + /// + /// \param Joined - If true, render the argument as joined with + /// the option specifier. + void AddAllArgsTranslated(ArgStringList &Output, options::ID Id0, + const char *Translation, + bool Joined = false) const; + + /// ClaimAllArgs - Claim all arguments which match the given + /// option id. + void ClaimAllArgs(options::ID Id0) const; + + /// @} + /// @name Arg Synthesis + /// @{ + + /// MakeArgString - Construct a constant string pointer whose + /// lifetime will match that of the ArgList. + virtual const char *MakeArgString(const char *Str) const = 0; + + /// @} + }; + + class InputArgList : public ArgList { + private: + /// The internal list of arguments. + arglist_type ActualArgs; + + /// List of argument strings used by the contained Args. + /// + /// This is mutable since we treat the ArgList as being the list + /// of Args, and allow routines to add new strings (to have a + /// convenient place to store the memory) via MakeIndex. + mutable ArgStringList ArgStrings; + + /// Strings for synthesized arguments. + /// + /// This is mutable since we treat the ArgList as being the list + /// of Args, and allow routines to add new strings (to have a + /// convenient place to store the memory) via MakeIndex. + mutable std::list<std::string> SynthesizedStrings; + + /// The number of original input argument strings. + unsigned NumInputArgStrings; + + public: + InputArgList(const char **ArgBegin, const char **ArgEnd); + InputArgList(const ArgList &); + ~InputArgList(); + + virtual const char *getArgString(unsigned Index) const { + return ArgStrings[Index]; + } + + /// getNumInputArgStrings - Return the number of original input + /// argument strings. + unsigned getNumInputArgStrings() const { return NumInputArgStrings; } + + /// @name Arg Synthesis + /// @{ + + public: + /// MakeIndex - Get an index for the given string(s). + unsigned MakeIndex(const char *String0) const; + unsigned MakeIndex(const char *String0, const char *String1) const; + + virtual const char *MakeArgString(const char *Str) const; + + /// @} + }; + + /// DerivedArgList - An ordered collection of driver arguments, + /// whose storage may be in another argument list. + class DerivedArgList : public ArgList { + InputArgList &BaseArgs; + + /// The internal list of arguments. + arglist_type ActualArgs; + + /// The list of arguments we synthesized. + arglist_type SynthesizedArgs; + + /// Is this only a proxy for the base ArgList? + bool OnlyProxy; + + public: + /// Construct a new derived arg list from \arg BaseArgs. + /// + /// \param OnlyProxy - If true, this is only a proxy for the base + /// list (to adapt the type), and it's Args list is unused. + DerivedArgList(InputArgList &BaseArgs, bool OnlyProxy); + ~DerivedArgList(); + + virtual const char *getArgString(unsigned Index) const { + return BaseArgs.getArgString(Index); + } + + /// @name Arg Synthesis + /// @{ + + virtual const char *MakeArgString(const char *Str) const; + + /// MakeFlagArg - Construct a new FlagArg for the given option + /// \arg Id. + Arg *MakeFlagArg(const Arg *BaseArg, const Option *Opt) const; + + /// MakePositionalArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt, + const char *Value) const; + + /// MakeSeparateArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt, + const char *Value) const; + + /// MakeJoinedArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt, + const char *Value) const; + + /// @} + }; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h new file mode 100644 index 000000000000..4985f30ad553 --- /dev/null +++ b/include/clang/Driver/Compilation.h @@ -0,0 +1,127 @@ +//===--- Compilation.h - Compilation Task Data Structure --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_COMPILATION_H_ +#define CLANG_DRIVER_COMPILATION_H_ + +#include "clang/Driver/Job.h" +#include "clang/Driver/Util.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { +namespace driver { + class DerivedArgList; + class Driver; + class InputArgList; + class JobList; + class ToolChain; + +/// Compilation - A set of tasks to perform for a single driver +/// invocation. +class Compilation { + /// The driver we were created by. + Driver &TheDriver; + + /// The default tool chain. + ToolChain &DefaultToolChain; + + /// The original (untranslated) input argument list. + InputArgList *Args; + + /// The list of actions. + ActionList Actions; + + /// The root list of jobs. + JobList Jobs; + + /// Cache of translated arguments for a particular tool chain. + llvm::DenseMap<const ToolChain*, DerivedArgList*> TCArgs; + + /// Temporary files which should be removed on exit. + ArgStringList TempFiles; + + /// Result files which should be removed on failure. + ArgStringList ResultFiles; + +public: + Compilation(Driver &D, ToolChain &DefaultToolChain, InputArgList *Args); + ~Compilation(); + + const Driver &getDriver() const { return TheDriver; } + + const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } + + const InputArgList &getArgs() const { return *Args; } + + ActionList &getActions() { return Actions; } + const ActionList &getActions() const { return Actions; } + + JobList &getJobs() { return Jobs; } + + /// getArgsForToolChain - Return the derived argument list for the + /// tool chain \arg TC (or the default tool chain, if TC is not + /// specified). + const DerivedArgList &getArgsForToolChain(const ToolChain *TC = 0); + + /// addTempFile - Add a file to remove on exit, and returns its + /// argument. + const char *addTempFile(const char *Name) { + TempFiles.push_back(Name); + return Name; + } + + /// addResultFile - Add a file to remove on failure, and returns its + /// argument. + const char *addResultFile(const char *Name) { + ResultFiles.push_back(Name); + return Name; + } + + /// Execute - Execute the compilation jobs and return an + /// appropriate exit code. + int Execute() const; + +private: + /// CleanupFileList - Remove the files in the given list. + /// + /// \param IssueErrors - Report failures as errors. + /// \return Whether all files were removed successfully. + bool CleanupFileList(const ArgStringList &Files, + bool IssueErrors=false) const; + + /// PrintJob - Print one job in -### format. + /// + /// OS - The stream to print on. + /// J - The job to print. + /// Terminator - A string to print at the end of the line. + /// Quote - Should separate arguments be quoted. + void PrintJob(llvm::raw_ostream &OS, const Job &J, + const char *Terminator, bool Quote) const; + + /// ExecuteCommand - Execute an actual command. + /// + /// \return The result code of the subprocess. + int ExecuteCommand(const Command &C) const; + + /// ExecuteJob - Execute a single job. + /// + /// \return The accumulated result code of the job. + int ExecuteJob(const Job &J) const; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h new file mode 100644 index 000000000000..66e3b9787594 --- /dev/null +++ b/include/clang/Driver/Driver.h @@ -0,0 +1,271 @@ +//===--- Driver.h - Clang GCC Compatible Driver -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_DRIVER_H_ +#define CLANG_DRIVER_DRIVER_H_ + +#include "clang/Basic/Diagnostic.h" + +#include "clang/Driver/Phases.h" +#include "clang/Driver/Util.h" + +#include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo + // lands. +#include <list> +#include <set> +#include <string> + +namespace clang { +namespace driver { + class Action; + class ArgList; + class Compilation; + class HostInfo; + class InputArgList; + class InputInfo; + class JobAction; + class OptTable; + class PipedJob; + class ToolChain; + +/// Driver - Encapsulate logic for constructing compilation processes +/// from a set of gcc-driver-like command line arguments. +class Driver { + OptTable *Opts; + + Diagnostic &Diags; + +public: + // Diag - Forwarding function for diagnostics. + DiagnosticBuilder Diag(unsigned DiagID) const { + return Diags.Report(FullSourceLoc(), DiagID); + } + + // FIXME: Privatize once interface is stable. +public: + /// The name the driver was invoked as. + std::string Name; + + /// The path the driver executable was in, as invoked from the + /// command line. + std::string Dir; + + /// Default host triple. + std::string DefaultHostTriple; + + /// Default name for linked images (e.g., "a.out"). + std::string DefaultImageName; + + /// Host information for the platform the driver is running as. This + /// will generally be the actual host platform, but not always. + const HostInfo *Host; + + /// Information about the host which can be overriden by the user. + std::string HostBits, HostMachine, HostSystem, HostRelease; + + /// Whether the driver should follow g++ like behavior. + bool CCCIsCXX : 1; + + /// Echo commands while executing (in -v style). + bool CCCEcho : 1; + + /// Only print tool bindings, don't build any jobs. + bool CCCPrintBindings : 1; + + /// Name to use when calling the generic gcc. + std::string CCCGenericGCCName; + +private: + /// Use the clang compiler where possible. + bool CCCUseClang : 1; + + /// Use clang for handling C++ and Objective-C++ inputs. + bool CCCUseClangCXX : 1; + + /// Use clang as a preprocessor (clang's preprocessor will still be + /// used where an integrated CPP would). + bool CCCUseClangCPP : 1; + +public: + /// Use lazy precompiled headers for PCH support. + bool CCCUsePCH; + +private: + /// Only use clang for the given architectures (only used when + /// non-empty). + std::set<std::string> CCCClangArchs; + + /// Certain options suppress the 'no input files' warning. + bool SuppressMissingInputWarning : 1; + + std::list<std::string> TempFiles; + std::list<std::string> ResultFiles; + +public: + Driver(const char *_Name, const char *_Dir, + const char *_DefaultHostTriple, + const char *_DefaultImageName, + Diagnostic &_Diags); + ~Driver(); + + /// @name Accessors + /// @{ + + const OptTable &getOpts() const { return *Opts; } + + const Diagnostic &getDiags() const { return Diags; } + + /// @} + /// @name Primary Functionality + /// @{ + + /// BuildCompilation - Construct a compilation object for a command + /// line argument vector. + /// + /// \return A compilation, or 0 if none was built for the given + /// argument vector. A null return value does not necessarily + /// indicate an error condition, the diagnostics should be queried + /// to determine if an error occurred. + Compilation *BuildCompilation(int argc, const char **argv); + + /// @name Driver Steps + /// @{ + + /// ParseArgStrings - Parse the given list of strings into an + /// ArgList. + InputArgList *ParseArgStrings(const char **ArgBegin, const char **ArgEnd); + + /// BuildActions - Construct the list of actions to perform for the + /// given arguments, which are only done for a single architecture. + /// + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildActions(const ArgList &Args, ActionList &Actions) const; + + /// BuildUniversalActions - Construct the list of actions to perform + /// for the given arguments, which may require a universal build. + /// + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildUniversalActions(const ArgList &Args, ActionList &Actions) const; + + /// BuildJobs - Bind actions to concrete tools and translate + /// arguments to form the list of jobs to run. + /// + /// \arg C - The compilation that is being built. + void BuildJobs(Compilation &C) const; + + /// @} + /// @name Helper Methods + /// @{ + + /// PrintActions - Print the list of actions. + void PrintActions(const Compilation &C) const; + + /// PrintHelp - Print the help text. + /// + /// \param ShowHidden - Show hidden options. + void PrintHelp(bool ShowHidden) const; + + /// PrintOptions - Print the list of arguments. + void PrintOptions(const ArgList &Args) const; + + /// PrintVersion - Print the driver version. + void PrintVersion(const Compilation &C) const; + + /// GetFilePath - Lookup \arg Name in the list of file search paths. + /// + /// \arg TC - The tool chain for additional information on + /// directories to search. + // FIXME: This should be in CompilationInfo. + llvm::sys::Path GetFilePath(const char *Name, const ToolChain &TC) const; + + /// GetProgramPath - Lookup \arg Name in the list of program search + /// paths. + /// + /// \arg TC - The provided tool chain for additional information on + /// directories to search. + /// + /// \arg WantFile - False when searching for an executable file, otherwise + /// true. Defaults to false. + // FIXME: This should be in CompilationInfo. + llvm::sys::Path GetProgramPath(const char *Name, const ToolChain &TC, + bool WantFile = false) const; + + /// HandleImmediateArgs - Handle any arguments which should be + /// treated before building actions or binding tools. + /// + /// \return Whether any compilation should be built for this + /// invocation. + bool HandleImmediateArgs(const Compilation &C); + + /// ConstructAction - Construct the appropriate action to do for + /// \arg Phase on the \arg Input, taking in to account arguments + /// like -fsyntax-only or --analyze. + Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase, + Action *Input) const; + + + /// BuildJobsForAction - Construct the jobs to perform for the + /// action \arg A. + void BuildJobsForAction(Compilation &C, + const Action *A, + const ToolChain *TC, + bool CanAcceptPipe, + bool AtTopLevel, + const char *LinkingOutput, + InputInfo &Result) const; + + /// GetNamedOutputPath - Return the name to use for the output of + /// the action \arg JA. The result is appended to the compilation's + /// list of temporary or result files, as appropriate. + /// + /// \param C - The compilation. + /// \param JA - The action of interest. + /// \param BaseInput - The original input file that this action was + /// triggered by. + /// \param AtTopLevel - Whether this is a "top-level" action. + const char *GetNamedOutputPath(Compilation &C, + const JobAction &JA, + const char *BaseInput, + bool AtTopLevel) const; + + /// GetTemporaryPath - Return the pathname of a temporary file to + /// use as part of compilation; the file will have the given suffix. + /// + /// GCC goes to extra lengths here to be a bit more robust. + std::string GetTemporaryPath(const char *Suffix) const; + + /// GetHostInfo - Construct a new host info object for the given + /// host triple. + const HostInfo *GetHostInfo(const char *HostTriple) const; + + /// ShouldUseClangCompilar - Should the clang compiler be used to + /// handle this action. + bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, + const std::string &ArchName) const; + + /// @} + + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and + /// return the grouped values as integers. Numbers which are not + /// provided are set to 0. + /// + /// \return True if the entire string was parsed (9.2), or all + /// groups were parsed (10.3.5extrastuff). HadExtra is true if all + /// groups were parsed but extra characters remain at the end. + static bool GetReleaseVersion(const char *Str, unsigned &Major, + unsigned &Minor, unsigned &Micro, + bool &HadExtra); +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h new file mode 100644 index 000000000000..2a4413c24e07 --- /dev/null +++ b/include/clang/Driver/DriverDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticDriver.h - Diagnostics for libdriver ---------*- 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_DRIVERDIAGNOSTIC_H +#define LLVM_CLANG_DRIVERDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DRIVERSTART +#include "clang/Basic/DiagnosticDriverKinds.inc" +#undef DIAG + NUM_BUILTIN_DRIVER_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h new file mode 100644 index 000000000000..020bb3ab5a82 --- /dev/null +++ b/include/clang/Driver/HostInfo.h @@ -0,0 +1,84 @@ +//===--- HostInfo.h - Host specific information -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_HOSTINFO_H_ +#define CLANG_DRIVER_HOSTINFO_H_ + +#include "clang/Driver/Types.h" +#include "llvm/ADT/Triple.h" +#include <string> + +namespace clang { +namespace driver { + class ArgList; + class Driver; + class ToolChain; + +/// HostInfo - Config information about a particular host which may +/// interact with driver behavior. +/// +/// The host information is used for controlling the parts of the +/// driver which interact with the platform the driver is ostensibly +/// being run from. For testing purposes, the HostInfo used by the +/// driver may differ from the actual host. +class HostInfo { + const Driver &TheDriver; + const llvm::Triple Triple; + +protected: + HostInfo(const Driver &D, const llvm::Triple &_Triple); + +public: + virtual ~HostInfo(); + + const Driver &getDriver() const { return TheDriver; } + + const llvm::Triple& getTriple() const { return Triple; } + std::string getArchName() const { return Triple.getArchName(); } + std::string getPlatformName() const { return Triple.getVendorName(); } + std::string getOSName() const { return Triple.getOSName(); } + + /// useDriverDriver - Whether the driver should act as a driver + /// driver for this host and support -arch, -Xarch, etc. + virtual bool useDriverDriver() const = 0; + + /// lookupTypeForExtension - Return the default language type to use + /// for the given extension. + virtual types::ID lookupTypeForExtension(const char *Ext) const = 0; + + /// getToolChain - Construct the toolchain to use for this host. + /// + /// \param Args - The argument list, which may be used to alter the + /// default toolchain, for example in the presence of -m32 or -m64. + /// + /// \param ArchName - The architecture to return a toolchain for, or + /// 0 if unspecified. This will only ever be non-zero for hosts + /// which support a driver driver. + + // FIXME: Pin down exactly what the HostInfo is allowed to use Args + // for here. Currently this is for -m32 / -m64 defaulting. + virtual ToolChain *getToolChain(const ArgList &Args, + const char *ArchName=0) const = 0; +}; + +const HostInfo *createDarwinHostInfo(const Driver &D, + const llvm::Triple& Triple); +const HostInfo *createFreeBSDHostInfo(const Driver &D, + const llvm::Triple& Triple); +const HostInfo *createDragonFlyHostInfo(const Driver &D, + const llvm::Triple& Triple); +const HostInfo *createLinuxHostInfo(const Driver &D, + const llvm::Triple& Triple); +const HostInfo *createUnknownHostInfo(const Driver &D, + const llvm::Triple& Triple); + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h new file mode 100644 index 000000000000..f60f5146414c --- /dev/null +++ b/include/clang/Driver/Job.h @@ -0,0 +1,138 @@ +//===--- Job.h - Commands to Execute ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_JOB_H_ +#define CLANG_DRIVER_JOB_H_ + +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" + +#include "llvm/Support/Casting.h" +using llvm::isa; +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; + +namespace clang { +namespace driver { + class Command; + +class Job { +public: + enum JobClass { + CommandClass, + PipedJobClass, + JobListClass + }; + +private: + JobClass Kind; + +protected: + Job(JobClass _Kind) : Kind(_Kind) {} +public: + virtual ~Job(); + + JobClass getKind() const { return Kind; } + + /// addCommand - Append a command to the current job, which must be + /// either a piped job or a job list. + void addCommand(Command *C); + + static bool classof(const Job *) { return true; } +}; + + /// Command - An executable path/name and argument vector to + /// execute. +class Command : public Job { + /// The executable to run. + const char *Executable; + + /// The list of program arguments (not including the implicit first + /// argument, which will be the executable). + ArgStringList Arguments; + +public: + Command(const char *_Executable, const ArgStringList &_Arguments); + + const char *getExecutable() const { return Executable; } + const ArgStringList &getArguments() const { return Arguments; } + + static bool classof(const Job *J) { + return J->getKind() == CommandClass; + } + static bool classof(const Command *) { return true; } +}; + + /// PipedJob - A list of Commands which should be executed together + /// with their standard inputs and outputs connected. +class PipedJob : public Job { +public: + typedef llvm::SmallVector<Command*, 4> list_type; + typedef list_type::size_type size_type; + typedef list_type::iterator iterator; + typedef list_type::const_iterator const_iterator; + +private: + list_type Commands; + +public: + PipedJob(); + + void addCommand(Command *C) { Commands.push_back(C); } + + const list_type &getCommands() const { return Commands; } + + size_type size() const { return Commands.size(); } + iterator begin() { return Commands.begin(); } + const_iterator begin() const { return Commands.begin(); } + iterator end() { return Commands.end(); } + const_iterator end() const { return Commands.end(); } + + static bool classof(const Job *J) { + return J->getKind() == PipedJobClass; + } + static bool classof(const PipedJob *) { return true; } +}; + + /// JobList - A sequence of jobs to perform. +class JobList : public Job { +public: + typedef llvm::SmallVector<Job*, 4> list_type; + typedef list_type::size_type size_type; + typedef list_type::iterator iterator; + typedef list_type::const_iterator const_iterator; + +private: + list_type Jobs; + +public: + JobList(); + + void addJob(Job *J) { Jobs.push_back(J); } + + const list_type &getJobs() const { return Jobs; } + + size_type size() const { return Jobs.size(); } + iterator begin() { return Jobs.begin(); } + const_iterator begin() const { return Jobs.begin(); } + iterator end() { return Jobs.end(); } + const_iterator end() const { return Jobs.end(); } + + static bool classof(const Job *J) { + return J->getKind() == JobListClass; + } + static bool classof(const JobList *) { return true; } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h new file mode 100644 index 000000000000..c59faef897ae --- /dev/null +++ b/include/clang/Driver/Option.h @@ -0,0 +1,308 @@ +//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTION_H_ +#define CLANG_DRIVER_OPTION_H_ + +#include "Options.h" + +#include "llvm/Support/Casting.h" +using llvm::isa; +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; + +namespace clang { +namespace driver { + class Arg; + class InputArgList; + class OptionGroup; + + /// Option - Abstract representation for a single form of driver + /// argument. + /// + /// An Option class represents a form of option that the driver + /// takes, for example how many arguments the option has and how + /// they can be provided. Individual option instances store + /// additional information about what group the option is a member + /// of (if any), if the option is an alias, and a number of + /// flags. At runtime the driver parses the command line into + /// concrete Arg instances, each of which corresponds to a + /// particular Option instance. + class Option { + public: + enum OptionClass { + GroupClass = 0, + InputClass, + UnknownClass, + FlagClass, + JoinedClass, + SeparateClass, + CommaJoinedClass, + MultiArgClass, + JoinedOrSeparateClass, + JoinedAndSeparateClass + }; + + private: + OptionClass Kind; + + options::ID ID; + + /// The option name. + const char *Name; + + /// Group this option is a member of, if any. + const OptionGroup *Group; + + /// Option that this is an alias for, if any. + const Option *Alias; + + /// Unsupported options will not be rejected. + bool Unsupported : 1; + + /// Treat this option like a linker input? + bool LinkerInput : 1; + + /// When rendering as an input, don't render the option. + + // FIXME: We should ditch the render/renderAsInput distinction. + bool NoOptAsInput : 1; + + /// Always render this option as separate form its value. + bool ForceSeparateRender : 1; + + /// Always render this option joined with its value. + bool ForceJoinedRender : 1; + + /// This option is only consumed by the driver. + bool DriverOption : 1; + + /// This option should not report argument unused errors. + bool NoArgumentUnused : 1; + + protected: + Option(OptionClass Kind, options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + public: + virtual ~Option(); + + options::ID getId() const { return ID; } + OptionClass getKind() const { return Kind; } + const char *getName() const { return Name; } + const OptionGroup *getGroup() const { return Group; } + const Option *getAlias() const { return Alias; } + + bool isUnsupported() const { return Unsupported; } + void setUnsupported(bool Value) { Unsupported = Value; } + + bool isLinkerInput() const { return LinkerInput; } + void setLinkerInput(bool Value) { LinkerInput = Value; } + + bool hasNoOptAsInput() const { return NoOptAsInput; } + void setNoOptAsInput(bool Value) { NoOptAsInput = Value; } + + bool hasForceSeparateRender() const { return ForceSeparateRender; } + void setForceSeparateRender(bool Value) { ForceSeparateRender = Value; } + + bool hasForceJoinedRender() const { return ForceJoinedRender; } + void setForceJoinedRender(bool Value) { ForceJoinedRender = Value; } + + bool isDriverOption() const { return DriverOption; } + void setDriverOption(bool Value) { DriverOption = Value; } + + bool hasNoArgumentUnused() const { return NoArgumentUnused; } + void setNoArgumentUnused(bool Value) { NoArgumentUnused = Value; } + + bool hasForwardToGCC() const { return !DriverOption && !LinkerInput; } + + /// getUnaliasedOption - Return the final option this option + /// aliases (itself, if the option has no alias). + const Option *getUnaliasedOption() const { + if (Alias) return Alias->getUnaliasedOption(); + return this; + } + + /// getRenderName - Return the name to use when rendering this + /// option. + const char *getRenderName() const { + return getUnaliasedOption()->getName(); + } + + /// matches - Predicate for whether this option is part of the + /// given option (which may be a group). + bool matches(const Option *Opt) const; + bool matches(options::ID Id) const; + + /// accept - Potentially accept the current argument, returning a + /// new Arg instance, or 0 if the option does not accept this + /// argument (or the argument is missing values). + /// + /// If the option accepts the current argument, accept() sets + /// Index to the position where argument parsing should resume + /// (even if the argument is missing values). + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const = 0; + + void dump() const; + + static bool classof(const Option *) { return true; } + }; + + /// OptionGroup - A set of options which are can be handled uniformly + /// by the driver. + class OptionGroup : public Option { + public: + OptionGroup(options::ID ID, const char *Name, const OptionGroup *Group); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::GroupClass; + } + static bool classof(const OptionGroup *) { return true; } + }; + + // Dummy option classes. + + /// InputOption - Dummy option class for representing driver inputs. + class InputOption : public Option { + public: + InputOption(); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::InputClass; + } + static bool classof(const InputOption *) { return true; } + }; + + /// UnknownOption - Dummy option class for represent unknown arguments. + class UnknownOption : public Option { + public: + UnknownOption(); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::UnknownClass; + } + static bool classof(const UnknownOption *) { return true; } + }; + + // Normal options. + + class FlagOption : public Option { + public: + FlagOption(options::ID ID, const char *Name, const OptionGroup *Group, + const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::FlagClass; + } + static bool classof(const FlagOption *) { return true; } + }; + + class JoinedOption : public Option { + public: + JoinedOption(options::ID ID, const char *Name, const OptionGroup *Group, + const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedClass; + } + static bool classof(const JoinedOption *) { return true; } + }; + + class SeparateOption : public Option { + public: + SeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, + const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::SeparateClass; + } + static bool classof(const SeparateOption *) { return true; } + }; + + class CommaJoinedOption : public Option { + public: + CommaJoinedOption(options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::CommaJoinedClass; + } + static bool classof(const CommaJoinedOption *) { return true; } + }; + + // FIXME: Fold MultiArgOption into SeparateOption? + + /// MultiArgOption - An option which takes multiple arguments (these + /// are always separate arguments). + class MultiArgOption : public Option { + unsigned NumArgs; + + public: + MultiArgOption(options::ID ID, const char *Name, const OptionGroup *Group, + const Option *Alias, unsigned NumArgs); + + unsigned getNumArgs() const { return NumArgs; } + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::MultiArgClass; + } + static bool classof(const MultiArgOption *) { return true; } + }; + + /// JoinedOrSeparateOption - An option which either literally + /// prefixes its (non-empty) value, or is follwed by a value. + class JoinedOrSeparateOption : public Option { + public: + JoinedOrSeparateOption(options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedOrSeparateClass; + } + static bool classof(const JoinedOrSeparateOption *) { return true; } + }; + + /// JoinedAndSeparateOption - An option which literally prefixes its + /// value and is followed by another value. + class JoinedAndSeparateOption : public Option { + public: + JoinedAndSeparateOption(options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const InputArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedAndSeparateClass; + } + static bool classof(const JoinedAndSeparateOption *) { return true; } + }; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def new file mode 100644 index 000000000000..c2981b934fc9 --- /dev/null +++ b/include/clang/Driver/Options.def @@ -0,0 +1,624 @@ +//===--- Options.def - Driver option info -----------------------*- 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 driver option information. Users of this file +// must define the OPTION macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#ifndef OPTION +#error "Define OPTION prior to including this file!" +#endif + +// OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, +// HELPTEXT, METAVARNAME) + +// The NAME value is the option name as a string. + +// The ID is the internal option id, which must be a valid +// C++ identifier, and results in a clang::driver::options::OPT_XX +// enum constant for XX. +// +// We want to unambiguously be able to refer to options from the +// driver source code, for this reason the option name is mangled into +// an id. This mangling isn't guaranteed to have an inverse, but for +// practical purposes it does. +// +// The mangling scheme is to ignore the leading '-', and perform the +// following substitutions: +// _ => __ +// - => _ +// # => _HASH +// , => _COMMA +// = => _EQ +// C++ => CXX + +// The KIND value is the option type, one of Group, Flag, Joined, +// Separate, CommaJoined, JoinedOrSeparate, JoinedAndSeparate. + +// The GROUP value is the internal name of the option group, or +// INVALID if the option is not part of a group. + +// The ALIAS value is the internal name of an aliased option, or +// INVALID if the option is not an alias. + +// The PARAM value is a string containing option flags. Valid values: +// d: The option is a "driver" option, and should not be forwarded to +// gcc. +// +// i: The option should not render the name when rendered as an +// input (i.e., the option is rendered as values). +// +// l: The option is a linker input. +// +// q: Don't report argument unused warnings for this option; this is +// useful for options like -static or -dynamic which a user may +// always end up passing, even if the platform defaults to (or +// only supports) that option. +// +// u: The option is unsupported, and the driver will reject command +// lines that use it. +// +// S: The option should be rendered separately, even if joined (only +// sensible on joined options). +// +// J: The option should be rendered joined, even if separate (only +// sensible on single value separate options). + +// The PARAM value is an arbitrary integer parameter; currently +// this is only used for specifying the number of arguments for +// Separate options. + +// The HELPTEXT value is the string to print for this option in +// --help, or 0 if undocumented. + +// The METAVAR value is the name to use for this values arguments (if +// any) in the help text. This must be defined if the help text is +// specified and this option takes extra arguments. + +// + +// For now (pre-TableGen, that is) Options must be in order. The +// ordering is *almost* lexicographic, with two exceptions. First, +// '\0' comes at the end of the alphabet instead of the beginning +// (thus options preceed any other options which prefix them). Second, +// for options with the same name, the less permissive version should +// come first; a Flag option should preceed a Joined option, for +// example. + +///////// +// Groups + +OPTION("<I group>", I_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<M group>", M_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<T group>", T_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<O group>", O_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<W group>", W_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<X group>", X_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<a group>", a_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<d group>", d_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<f group>", f_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<g group>", g_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<i group>", i_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<clang i group>", clang_i_Group, Group, i_Group, INVALID, "", 0, 0, 0) +OPTION("<m group>", m_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<m x86 features group>", m_x86_Features_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("<u group>", u_Group, Group, INVALID, INVALID, "", 0, 0, 0) + +OPTION("<pedantic group>", pedantic_Group, Group, INVALID, INVALID, "", 0, 0, 0) + +// Temporary groups for clang options which we know we don't support, +// but don't want to verbosely warn the user about. +OPTION("<clang ignored f group>", clang_ignored_f_Group, Group, f_Group, + INVALID, "", 0, 0, 0) +OPTION("<clang ignored m group>", clang_ignored_m_Group, Group, m_Group, + INVALID, "", 0, 0, 0) + +////////// +// Options + +OPTION("-###", _HASH_HASH_HASH, Flag, INVALID, INVALID, "d", 0, + "Print the commands to run for this compilation", 0) +OPTION("--CLASSPATH=", _CLASSPATH_EQ, Joined, INVALID, fclasspath_EQ, "", 0, 0, 0) +OPTION("--CLASSPATH", _CLASSPATH, Separate, INVALID, fclasspath_EQ, "J", 0, 0, 0) +OPTION("--all-warnings", _all_warnings, Flag, INVALID, Wall, "", 0, 0, 0) +OPTION("--analyze-auto", _analyze_auto, Flag, INVALID, INVALID, "d", 0, 0, 0) +OPTION("--analyzer-no-default-checks", _analyzer_no_default_checks, Flag, INVALID, INVALID, "d", 0, 0, 0) +OPTION("--analyzer-output", _analyzer_output, JoinedOrSeparate, INVALID, INVALID, "d", 0, 0, 0) +OPTION("--analyze", _analyze, Flag, INVALID, INVALID, "d", 0, + "Run the static analyzer", 0) +OPTION("--ansi", _ansi, Flag, INVALID, ansi, "", 0, 0, 0) +OPTION("--assemble", _assemble, Flag, INVALID, S, "", 0, 0, 0) +OPTION("--assert=", _assert_EQ, Joined, INVALID, A, "S", 0, 0, 0) +OPTION("--assert", _assert, Separate, INVALID, A, "", 0, 0, 0) +OPTION("--bootclasspath=", _bootclasspath_EQ, Joined, INVALID, fbootclasspath_EQ, "", 0, 0, 0) +OPTION("--bootclasspath", _bootclasspath, Separate, INVALID, fbootclasspath_EQ, "J", 0, 0, 0) +OPTION("--classpath=", _classpath_EQ, Joined, INVALID, fclasspath_EQ, "", 0, 0, 0) +OPTION("--classpath", _classpath, Separate, INVALID, fclasspath_EQ, "J", 0, 0, 0) +OPTION("--combine", _combine, Flag, INVALID, combine, "u", 0, 0, 0) +OPTION("--comments-in-macros", _comments_in_macros, Flag, INVALID, CC, "", 0, 0, 0) +OPTION("--comments", _comments, Flag, INVALID, C, "", 0, 0, 0) +OPTION("--compile", _compile, Flag, INVALID, c, "", 0, 0, 0) +OPTION("--constant-cfstrings", _constant_cfstrings, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("--coverage", _coverage, Flag, INVALID, coverage, "", 0, 0, 0) +OPTION("--debug=", _debug_EQ, Joined, INVALID, g_Flag, "u", 0, 0, 0) +OPTION("--debug", _debug, Flag, INVALID, g_Flag, "u", 0, 0, 0) +OPTION("--define-macro=", _define_macro_EQ, Joined, INVALID, D, "", 0, 0, 0) +OPTION("--define-macro", _define_macro, Separate, INVALID, D, "J", 0, 0, 0) +OPTION("--dependencies", _dependencies, Flag, INVALID, M, "", 0, 0, 0) +OPTION("--encoding=", _encoding_EQ, Joined, INVALID, fencoding_EQ, "", 0, 0, 0) +OPTION("--encoding", _encoding, Separate, INVALID, fencoding_EQ, "J", 0, 0, 0) +OPTION("--entry", _entry, Flag, INVALID, e, "", 0, 0, 0) +OPTION("--extdirs=", _extdirs_EQ, Joined, INVALID, fextdirs_EQ, "", 0, 0, 0) +OPTION("--extdirs", _extdirs, Separate, INVALID, fextdirs_EQ, "J", 0, 0, 0) +OPTION("--extra-warnings", _extra_warnings, Flag, INVALID, W_Joined, "", 0, 0, 0) +OPTION("--for-linker=", _for_linker_EQ, Joined, INVALID, Xlinker, "liS", 0, 0, 0) +OPTION("--for-linker", _for_linker, Separate, INVALID, Xlinker, "li", 0, 0, 0) +OPTION("--force-link=", _force_link_EQ, Joined, INVALID, u, "S", 0, 0, 0) +OPTION("--force-link", _force_link, Separate, INVALID, u, "", 0, 0, 0) +OPTION("--help-hidden", _help_hidden, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("--help", _help, Flag, INVALID, INVALID, "", 0, + "Display available options", 0) +OPTION("--imacros=", _imacros_EQ, Joined, INVALID, imacros, "S", 0, 0, 0) +OPTION("--imacros", _imacros, Separate, INVALID, imacros, "", 0, 0, 0) +OPTION("--include-barrier", _include_barrier, Flag, INVALID, I_, "", 0, 0, 0) +OPTION("--include-directory-after=", _include_directory_after_EQ, Joined, INVALID, idirafter, "S", 0, 0, 0) +OPTION("--include-directory-after", _include_directory_after, Separate, INVALID, idirafter, "", 0, 0, 0) +OPTION("--include-directory=", _include_directory_EQ, Joined, INVALID, I, "", 0, 0, 0) +OPTION("--include-directory", _include_directory, Separate, INVALID, I, "J", 0, 0, 0) +OPTION("--include-prefix=", _include_prefix_EQ, Joined, INVALID, iprefix, "S", 0, 0, 0) +OPTION("--include-prefix", _include_prefix, Separate, INVALID, iprefix, "", 0, 0, 0) +OPTION("--include-with-prefix-after=", _include_with_prefix_after_EQ, Joined, INVALID, iwithprefix, "S", 0, 0, 0) +OPTION("--include-with-prefix-after", _include_with_prefix_after, Separate, INVALID, iwithprefix, "", 0, 0, 0) +OPTION("--include-with-prefix-before=", _include_with_prefix_before_EQ, Joined, INVALID, iwithprefixbefore, "S", 0, 0, 0) +OPTION("--include-with-prefix-before", _include_with_prefix_before, Separate, INVALID, iwithprefixbefore, "", 0, 0, 0) +OPTION("--include-with-prefix=", _include_with_prefix_EQ, Joined, INVALID, iwithprefix, "S", 0, 0, 0) +OPTION("--include-with-prefix", _include_with_prefix, Separate, INVALID, iwithprefix, "", 0, 0, 0) +OPTION("--include=", _include_EQ, Joined, INVALID, include, "S", 0, 0, 0) +OPTION("--include", _include, Separate, INVALID, include, "", 0, 0, 0) +OPTION("--language=", _language_EQ, Joined, INVALID, x, "S", 0, 0, 0) +OPTION("--language", _language, Separate, INVALID, x, "", 0, 0, 0) +OPTION("--library-directory=", _library_directory_EQ, Joined, INVALID, L, "S", 0, 0, 0) +OPTION("--library-directory", _library_directory, Separate, INVALID, L, "", 0, 0, 0) +OPTION("--machine-=", _machine__EQ, Joined, INVALID, m_Joined, "u", 0, 0, 0) +OPTION("--machine-", _machine_, Joined, INVALID, m_Joined, "u", 0, 0, 0) +OPTION("--machine=", _machine_EQ, Joined, INVALID, m_Joined, "", 0, 0, 0) +OPTION("--machine", _machine, Separate, INVALID, m_Joined, "J", 0, 0, 0) +OPTION("--no-integrated-cpp", _no_integrated_cpp, Flag, INVALID, no_integrated_cpp, "", 0, 0, 0) +OPTION("--no-line-commands", _no_line_commands, Flag, INVALID, P, "", 0, 0, 0) +OPTION("--no-standard-includes", _no_standard_includes, Flag, INVALID, nostdinc, "", 0, 0, 0) +OPTION("--no-standard-libraries", _no_standard_libraries, Flag, INVALID, nostdlib, "", 0, 0, 0) +OPTION("--no-warnings", _no_warnings, Flag, INVALID, w, "", 0, 0, 0) +OPTION("--optimize=", _optimize_EQ, Joined, INVALID, O, "u", 0, 0, 0) +OPTION("--optimize", _optimize, Flag, INVALID, O, "u", 0, 0, 0) +OPTION("--output-class-directory=", _output_class_directory_EQ, Joined, INVALID, foutput_class_dir_EQ, "", 0, 0, 0) +OPTION("--output-class-directory", _output_class_directory, Separate, INVALID, foutput_class_dir_EQ, "J", 0, 0, 0) +OPTION("--output=", _output_EQ, Joined, INVALID, o, "S", 0, 0, 0) +OPTION("--output", _output, Separate, INVALID, o, "", 0, 0, 0) +OPTION("--param=", _param_EQ, Joined, INVALID, _param, "S", 0, 0, 0) +OPTION("--param", _param, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("--pass-exit-codes", _pass_exit_codes, Flag, INVALID, pass_exit_codes, "", 0, 0, 0) +OPTION("--pedantic-errors", _pedantic_errors, Flag, INVALID, pedantic_errors, "", 0, 0, 0) +OPTION("--pedantic", _pedantic, Flag, INVALID, pedantic, "", 0, 0, 0) +OPTION("--pipe", _pipe, Flag, INVALID, pipe, "d", 0, 0, 0) +OPTION("--prefix=", _prefix_EQ, Joined, INVALID, B, "S", 0, 0, 0) +OPTION("--prefix", _prefix, Separate, INVALID, B, "", 0, 0, 0) +OPTION("--preprocess", _preprocess, Flag, INVALID, E, "", 0, 0, 0) +OPTION("--print-file-name=", _print_file_name_EQ, Joined, INVALID, print_file_name_EQ, "", 0, 0, 0) +OPTION("--print-file-name", _print_file_name, Separate, INVALID, print_file_name_EQ, "", 0, 0, 0) +OPTION("--print-libgcc-file-name", _print_libgcc_file_name, Flag, INVALID, print_libgcc_file_name, "", 0, 0, 0) +OPTION("--print-missing-file-dependencies", _print_missing_file_dependencies, Flag, INVALID, MG, "", 0, 0, 0) +OPTION("--print-multi-directory", _print_multi_directory, Flag, INVALID, print_multi_directory, "", 0, 0, 0) +OPTION("--print-multi-lib", _print_multi_lib, Flag, INVALID, print_multi_lib, "", 0, 0, 0) +OPTION("--print-multi-os-directory", _print_multi_os_directory, Flag, INVALID, print_multi_os_directory, "", 0, 0, 0) +OPTION("--print-prog-name=", _print_prog_name_EQ, Joined, INVALID, print_prog_name_EQ, "", 0, 0, 0) +OPTION("--print-prog-name", _print_prog_name, Separate, INVALID, print_prog_name_EQ, "", 0, 0, 0) +OPTION("--print-search-dirs", _print_search_dirs, Flag, INVALID, print_search_dirs, "", 0, 0, 0) +OPTION("--profile-blocks", _profile_blocks, Flag, INVALID, a, "", 0, 0, 0) +OPTION("--profile", _profile, Flag, INVALID, p, "", 0, 0, 0) +OPTION("--resource=", _resource_EQ, Joined, INVALID, fcompile_resource_EQ, "", 0, 0, 0) +OPTION("--resource", _resource, Separate, INVALID, fcompile_resource_EQ, "J", 0, 0, 0) +OPTION("--save-temps", _save_temps, Flag, INVALID, save_temps, "", 0, 0, 0) +OPTION("--shared", _shared, Flag, INVALID, shared, "", 0, 0, 0) +OPTION("--specs=", _specs_EQ, Joined, INVALID, specs_EQ, "u", 0, 0, 0) +OPTION("--specs", _specs, Separate, INVALID, specs_EQ, "uJ", 0, 0, 0) +OPTION("--static", _static, Flag, INVALID, static, "", 0, 0, 0) +OPTION("--std=", _std_EQ, Joined, INVALID, std_EQ, "", 0, 0, 0) +OPTION("--std", _std, Separate, INVALID, std_EQ, "J", 0, 0, 0) +OPTION("--sysroot=", _sysroot_EQ, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("--sysroot", _sysroot, Separate, INVALID, _sysroot_EQ, "J", 0, 0, 0) +OPTION("--target-help", _target_help, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("--trace-includes", _trace_includes, Flag, INVALID, H, "", 0, 0, 0) +OPTION("--traditional-cpp", _traditional_cpp, Flag, INVALID, traditional_cpp, "", 0, 0, 0) +OPTION("--traditional", _traditional, Flag, INVALID, traditional, "", 0, 0, 0) +OPTION("--trigraphs", _trigraphs, Flag, INVALID, trigraphs, "", 0, 0, 0) +OPTION("--undefine-macro=", _undefine_macro_EQ, Joined, INVALID, U, "", 0, 0, 0) +OPTION("--undefine-macro", _undefine_macro, Separate, INVALID, U, "J", 0, 0, 0) +OPTION("--user-dependencies", _user_dependencies, Flag, INVALID, MM, "", 0, 0, 0) +OPTION("--verbose", _verbose, Flag, INVALID, v, "", 0, 0, 0) +OPTION("--version", _version, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("--warn-=", _warn__EQ, Joined, INVALID, W_Joined, "u", 0, 0, 0) +OPTION("--warn-", _warn_, Joined, INVALID, W_Joined, "u", 0, 0, 0) +OPTION("--write-dependencies", _write_dependencies, Flag, INVALID, MD, "", 0, 0, 0) +OPTION("--write-user-dependencies", _write_user_dependencies, Flag, INVALID, MMD, "", 0, 0, 0) +OPTION("--", _, Joined, INVALID, f, "u", 0, 0, 0) +OPTION("-A", A, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-B", B, JoinedOrSeparate, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-CC", CC, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-C", C, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-D", D, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-E", E, Flag, INVALID, INVALID, "d", 0, + "Only run the preprocessor", 0) +OPTION("-F", F, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-H", H, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-I-", I_, Flag, I_Group, INVALID, "", 0, 0, 0) +OPTION("-I", I, JoinedOrSeparate, I_Group, INVALID, "", 0, 0, 0) +OPTION("-L", L, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-MD", MD, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MF", MF, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MG", MG, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MMD", MMD, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MM", MM, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MP", MP, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MQ", MQ, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0) +OPTION("-MT", MT, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0) +OPTION("-Mach", Mach, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-M", M, Flag, M_Group, INVALID, "", 0, 0, 0) +OPTION("-O4", O4, Joined, O_Group, INVALID, "", 0, 0, 0) +OPTION("-ObjC++", ObjCXX, Flag, INVALID, INVALID, "d", 0, + "Treat source input files as Objective-C++ inputs", 0) +OPTION("-ObjC", ObjC, Flag, INVALID, INVALID, "d", 0, + "Treat source input files as Objective-C inputs", 0) +OPTION("-O", O, Joined, O_Group, INVALID, "", 0, 0, 0) +OPTION("-P", P, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-Qn", Qn, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-Qunused-arguments", Qunused_arguments, Flag, INVALID, INVALID, "d", 0, + "Don't emit warning for unused driver arguments", 0) +OPTION("-Q", Q, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-R", R, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-S", S, Flag, INVALID, INVALID, "d", 0, + "Only run preprocess and compilation steps", 0) +OPTION("-Tbss", Tbss, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0) +OPTION("-Tdata", Tdata, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0) +OPTION("-Ttext", Ttext, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0) +OPTION("-T", T, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0) +OPTION("-U", U, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-V", V, JoinedOrSeparate, INVALID, INVALID, "du", 0, 0, 0) +OPTION("-Wa,", Wa_COMMA, CommaJoined, INVALID, INVALID, "", 0, + "Pass the comma separated arguments in <arg> to the assembler", "<arg>") +OPTION("-Wall", Wall, Flag, W_Group, INVALID, "", 0, 0, 0) +OPTION("-Wextra", Wextra, Flag, W_Group, INVALID, "", 0, 0, 0) +OPTION("-Wl,", Wl_COMMA, CommaJoined, INVALID, INVALID, "li", 0, + "Pass the comma separated arguments in <arg> to the linker", "<arg>") +OPTION("-Wno-nonportable-cfstrings", Wno_nonportable_cfstrings, Joined, W_Group, INVALID, "", 0, 0, 0) +OPTION("-Wnonportable-cfstrings", Wnonportable_cfstrings, Joined, W_Group, INVALID, "", 0, 0, 0) +OPTION("-Wp,", Wp_COMMA, CommaJoined, INVALID, INVALID, "", 0, + "Pass the comma separated arguments in <arg> to the preprocessor", "<arg>") +OPTION("-W", W_Joined, Joined, W_Group, INVALID, "", 0, 0, 0) +OPTION("-Xanalyzer", Xanalyzer, Separate, INVALID, INVALID, "", 0, + "Pass <arg> to the static analyzer", "<arg>") +OPTION("-Xarch_", Xarch__, JoinedAndSeparate, INVALID, INVALID, "d", 0, 0, 0) +OPTION("-Xassembler", Xassembler, Separate, INVALID, INVALID, "", 0, + "Pass <arg> to the assembler", "<arg>") +OPTION("-Xclang", Xclang, Separate, INVALID, INVALID, "", 0, + "Pass <arg> to the clang compiler", "<arg>") +OPTION("-Xlinker", Xlinker, Separate, INVALID, INVALID, "li", 0, + "Pass <arg> to the linker", "<arg>") +OPTION("-Xpreprocessor", Xpreprocessor, Separate, INVALID, INVALID, "", 0, + "Pass <arg> to the preprocessor", "<arg>") +OPTION("-X", X_Flag, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-X", X_Joined, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-Z", Z_Flag, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-Z", Z_Joined, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-all_load", all__load, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-allowable_client", allowable__client, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-ansi", ansi, Flag, a_Group, INVALID, "", 0, 0, 0) +OPTION("-arch", arch, Separate, INVALID, INVALID, "d", 0, 0, 0) +OPTION("-a", a, Joined, a_Group, INVALID, "", 0, 0, 0) +OPTION("-bind_at_load", bind__at__load, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-bundle_loader", bundle__loader, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-bundle", bundle, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-b", b, JoinedOrSeparate, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-client_name", client__name, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-combine", combine, Flag, INVALID, INVALID, "du", 0, 0, 0) +OPTION("-compatibility_version", compatibility__version, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-coverage", coverage, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-cpp-precomp", cpp_precomp, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-current_version", current__version, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-c", c, Flag, INVALID, INVALID, "d", 0, + "Only run preprocess, compile, and assemble steps", 0) +OPTION("-dA", dA, Flag, d_Group, INVALID, "", 0, 0, 0) +OPTION("-dD", dD, Flag, d_Group, INVALID, "", 0, 0, 0) +OPTION("-dM", dM, Flag, d_Group, INVALID, "", 0, 0, 0) +OPTION("-dead_strip", dead__strip, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dependency-file", dependency_file, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dumpmachine", dumpmachine, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-dumpspecs", dumpspecs, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-dumpversion", dumpversion, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dylib_file", dylib__file, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dylinker_install_name", dylinker__install__name, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dylinker", dylinker, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dynamiclib", dynamiclib, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-dynamic", dynamic, Flag, INVALID, INVALID, "q", 0, 0, 0) +OPTION("-d", d_Flag, Flag, d_Group, INVALID, "", 0, 0, 0) +OPTION("-d", d_Joined, Joined, d_Group, INVALID, "", 0, 0, 0) +OPTION("-emit-llvm", emit_llvm, Flag, INVALID, INVALID, "", 0, + "Use the LLVM representation for assembler and object files", 0) +OPTION("-exported_symbols_list", exported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-e", e, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-fPIC", fPIC, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fPIE", fPIE, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fapple-kext", fapple_kext, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fasm-blocks", fasm_blocks, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fastcp", fastcp, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fastf", fastf, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fast", fast, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fasynchronous-unwind-tables", fasynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fblocks", fblocks, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fbootclasspath=", fbootclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fbuiltin", fbuiltin, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fclasspath=", fclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fcommon", fcommon, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fcompile-resource=", fcompile_resource_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fconstant-cfstrings", fconstant_cfstrings, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fcreate-profile", fcreate_profile, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdebug-pass-arguments", fdebug_pass_arguments, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdebug-pass-structure", fdebug_pass_structure, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdiagnostics-fixit-info", fdiagnostics_fixit_info, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdiagnostics-print-source-range-info", fdiagnostics_print_source_range_info, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdiagnostics-show-option", fdiagnostics_show_option, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fdollars-in-identifiers", fdollars_in_identifiers, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-feliminate-unused-debug-symbols", feliminate_unused_debug_symbols, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-femit-all-decls", femit_all_decls, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fencoding=", fencoding_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fexceptions", fexceptions, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fextdirs=", fextdirs_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-ffreestanding", ffreestanding, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fgnu-runtime", fgnu_runtime, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fheinous-gnu-extensions", fheinous_gnu_extensions, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-filelist", filelist, Separate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-findirect-virtual-calls", findirect_virtual_calls, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-finline-functions", finline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-finline", finline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fkeep-inline-functions", fkeep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-flat_namespace", flat__namespace, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-flax-vector-conversions", flax_vector_conversions, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-flimited-precision=", flimited_precision_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-flto", flto, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fmath-errno", fmath_errno, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fmessage-length=", fmessage_length_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fms-extensions", fms_extensions, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fmudflapth", fmudflapth, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fmudflap", fmudflap, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fnested-functions", fnested_functions, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fnext-runtime", fnext_runtime, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-asynchronous-unwind-tables", fno_asynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-blocks", fno_blocks, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-builtin", fno_builtin, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-caret-diagnostics", fno_caret_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-common", fno_common, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-constant-cfstrings", fno_constant_cfstrings, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-diagnostics-fixit-info", fno_diagnostics_fixit_info, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-diagnostics-show-option", fno_diagnostics_show_option, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-dollars-in-identifiers", fno_dollars_in_identifiers, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-eliminate-unused-debug-symbols", fno_eliminate_unused_debug_symbols, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-inline-functions", fno_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-inline", fno_inline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-keep-inline-functions", fno_keep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-math-errno", fno_math_errno, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-pascal-strings", fno_pascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-show-column", fno_show_column, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-stack-protector", fno_stack_protector, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-strict-aliasing", fno_strict_aliasing, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-unit-at-a-time", fno_unit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-unwind-tables", fno_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-working-directory", fno_working_directory, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-zero-initialized-in-bss", fno_zero_initialized_in_bss, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-atdefs", fobjc_atdefs, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-call-cxx-cdtors", fobjc_call_cxx_cdtors, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-gc-only", fobjc_gc_only, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-gc", fobjc_gc, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-new-property", fobjc_new_property, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-nonfragile-abi", fobjc_nonfragile_abi, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-sender-dependent-dispatch", fobjc_sender_dependent_dispatch, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc-tight-layout", fobjc_tight_layout, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fobjc", fobjc, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fomit-frame-pointer", fomit_frame_pointer, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fopenmp", fopenmp, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-force_cpusubtype_ALL", force__cpusubtype__ALL, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-force_flat_namespace", force__flat__namespace, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-foutput-class-dir=", foutput_class_dir_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fpascal-strings", fpascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fpch-preprocess", fpch_preprocess, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fpic", fpic, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fpie", fpie, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fprofile-arcs", fprofile_arcs, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fprofile-generate", fprofile_generate, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-framework", framework, Separate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-fsigned-bitfields", fsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fstack-protector", fstack_protector, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fstrict-aliasing", fstrict_aliasing, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) +OPTION("-fsyntax-only", fsyntax_only, Flag, INVALID, INVALID, "d", 0, 0, 0) +OPTION("-ftemplate-depth-", ftemplate_depth_, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fterminated-vtables", fterminated_vtables, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-ftime-report", ftime_report, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-ftraditional", ftraditional, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-ftrapv", ftrapv, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-funit-at-a-time", funit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-funsigned-bitfields", funsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-funwind-tables", funwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fverbose-asm", fverbose_asm, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fvisibility=", fvisibility_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fwritable-strings", fwritable_strings, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fzero-initialized-in-bss", fzero_initialized_in_bss, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-f", f, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-g0", g0, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-g3", g3, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-gfull", gfull, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-gstabs", gstabs, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-gused", gused, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-g", g_Flag, Flag, g_Group, INVALID, "", 0, 0, 0) +OPTION("-g", g_Joined, Joined, g_Group, INVALID, "", 0, 0, 0) +OPTION("-headerpad_max_install_names", headerpad__max__install__names, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-idirafter", idirafter, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-iframework", iframework, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-imacros", imacros, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-image_base", image__base, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-include", include, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-init", init, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-install_name", install__name, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-iprefix", iprefix, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-iquote", iquote, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-isysroot", isysroot, JoinedOrSeparate, i_Group, INVALID, "", 0, 0, 0) +OPTION("-isystem", isystem, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-iwithprefixbefore", iwithprefixbefore, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-iwithprefix", iwithprefix, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0) +OPTION("-iwithsysroot", iwithsysroot, JoinedOrSeparate, i_Group, INVALID, "", 0, 0, 0) +OPTION("-i", i, Joined, i_Group, INVALID, "", 0, 0, 0) +OPTION("-keep_private_externs", keep__private__externs, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-l", l, JoinedOrSeparate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-m32", m32, Flag, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-m3dnowa", m3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-m3dnow", m3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-m64", m64, Flag, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-march=", march_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-mconstant-cfstrings", mconstant_cfstrings, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) +OPTION("-mdynamic-no-pic", mdynamic_no_pic, Joined, m_Group, INVALID, "q", 0, 0, 0) +OPTION("-mfix-and-continue", mfix_and_continue, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) +OPTION("-miphoneos-version-min=", miphoneos_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mkernel", mkernel, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mmacosx-version-min=", mmacosx_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mmmx", mmmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-3dnowa", mno_3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-3dnow", mno_3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-constant-cfstrings", mno_constant_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-mmx", mno_mmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-pascal-strings", mno_pascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-red-zone", mno_red_zone, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-soft-float", mno_soft_float, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse2", mno_sse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse3", mno_sse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse4a", mno_sse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse4", mno_sse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse", mno_sse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-ssse3", mno_ssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-warn-nonportable-cfstrings", mno_warn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mpascal-strings", mpascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mred-zone", mred_zone, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-msoft-float", msoft_float, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-msse2", msse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse3", msse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse4a", msse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse4", msse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse", msse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mssse3", mssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mtune=", mtune_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) +OPTION("-multi_module", multi__module, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-multiply_defined_unused", multiply__defined__unused, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-multiply_defined", multiply__defined, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-mwarn-nonportable-cfstrings", mwarn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-m", m_Separate, Separate, m_Group, INVALID, "", 0, 0, 0) +OPTION("-m", m_Joined, Joined, m_Group, INVALID, "", 0, 0, 0) +OPTION("-no-cpp-precomp", no_cpp_precomp, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-no-integrated-cpp", no_integrated_cpp, Flag, INVALID, INVALID, "d", 0, 0, 0) +OPTION("-no_dead_strip_inits_and_terms", no__dead__strip__inits__and__terms, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nodefaultlibs", nodefaultlibs, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nofixprebinding", nofixprebinding, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nolibc", nolibc, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nomultidefs", nomultidefs, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-noprebind", noprebind, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-noseglinkedit", noseglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nostartfiles", nostartfiles, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nostdinc", nostdinc, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nostdlib", nostdlib, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-object", object, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-o", o, JoinedOrSeparate, INVALID, INVALID, "di", 0, + "Write output to <file>", "<file>") +OPTION("-pagezero_size", pagezero__size, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-pass-exit-codes", pass_exit_codes, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-pedantic-errors", pedantic_errors, Flag, pedantic_Group, INVALID, "", 0, 0, 0) +OPTION("-pedantic", pedantic, Flag, pedantic_Group, INVALID, "", 0, 0, 0) +OPTION("-pg", pg, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-pipe", pipe, Flag, INVALID, INVALID, "", 0, + "Use pipes between commands, when possible", 0) +OPTION("-prebind_all_twolevel_modules", prebind__all__twolevel__modules, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-prebind", prebind, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-preload", preload, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-print-file-name=", print_file_name_EQ, Joined, INVALID, INVALID, "", 0, + "Print the full library path of <file>", "<file>") +OPTION("-print-ivar-layout", print_ivar_layout, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-print-libgcc-file-name", print_libgcc_file_name, Flag, INVALID, INVALID, "", 0, + "Print the library path for \"libgcc.a\"", 0) +OPTION("-print-multi-directory", print_multi_directory, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-print-multi-lib", print_multi_lib, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-print-multi-os-directory", print_multi_os_directory, Flag, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-print-prog-name=", print_prog_name_EQ, Joined, INVALID, INVALID, "", 0, + "Print the full program path of <name>", "<name>") +OPTION("-print-search-dirs", print_search_dirs, Flag, INVALID, INVALID, "", 0, + "Print the paths used for finding libraries and programs", 0) +OPTION("-private_bundle", private__bundle, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-pthreads", pthreads, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-pthread", pthread, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-p", p, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-read_only_relocs", read__only__relocs, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-remap", remap, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-r", r, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-save-temps", save_temps, Flag, INVALID, INVALID, "d", 0, + "Save intermediate compilation results", 0) +OPTION("-sectalign", sectalign, MultiArg, INVALID, INVALID, "", 3, 0, 0) +OPTION("-sectcreate", sectcreate, MultiArg, INVALID, INVALID, "", 3, 0, 0) +OPTION("-sectobjectsymbols", sectobjectsymbols, MultiArg, INVALID, INVALID, "", 2, 0, 0) +OPTION("-sectorder", sectorder, MultiArg, INVALID, INVALID, "", 3, 0, 0) +OPTION("-seg1addr", seg1addr, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-seg_addr_table_filename", seg__addr__table__filename, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-seg_addr_table", seg__addr__table, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-segaddr", segaddr, MultiArg, INVALID, INVALID, "", 2, 0, 0) +OPTION("-segcreate", segcreate, MultiArg, INVALID, INVALID, "", 3, 0, 0) +OPTION("-seglinkedit", seglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-segprot", segprot, MultiArg, INVALID, INVALID, "", 3, 0, 0) +OPTION("-segs_read_only_addr", segs__read__only__addr, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-segs_read_write_addr", segs__read__write__addr, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-segs_read_", segs__read__, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-shared-libgcc", shared_libgcc, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-shared", shared, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-single_module", single__module, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-specs=", specs_EQ, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-specs", specs, Separate, INVALID, INVALID, "u", 0, 0, 0) +OPTION("-static-libgcc", static_libgcc, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-static", static, Flag, INVALID, INVALID, "q", 0, 0, 0) +OPTION("-std-default=", std_default_EQ, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-std=", std_EQ, Joined, INVALID, INVALID, "", 0, 0, 0) +OPTION("-sub_library", sub__library, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-sub_umbrella", sub__umbrella, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-s", s, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-time", time, Flag, INVALID, INVALID, "", 0, + "Time individual commands", 0) +OPTION("-traditional-cpp", traditional_cpp, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-traditional", traditional, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-trigraphs", trigraphs, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-twolevel_namespace_hints", twolevel__namespace__hints, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-twolevel_namespace", twolevel__namespace, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-t", t, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-umbrella", umbrella, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-undefined", undefined, JoinedOrSeparate, u_Group, INVALID, "", 0, 0, 0) +OPTION("-undef", undef, Flag, u_Group, INVALID, "", 0, 0, 0) +OPTION("-unexported_symbols_list", unexported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-u", u, JoinedOrSeparate, u_Group, INVALID, "", 0, 0, 0) +OPTION("-v", v, Flag, INVALID, INVALID, "", 0, + "Show commands to run and use verbose output", 0) +OPTION("-weak-l", weak_l, Joined, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-weak_framework", weak__framework, Separate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-weak_library", weak__library, Separate, INVALID, INVALID, "l", 0, 0, 0) +OPTION("-weak_reference_mismatches", weak__reference__mismatches, Separate, INVALID, INVALID, "", 0, 0, 0) +OPTION("-whatsloaded", whatsloaded, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-whyload", whyload, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-w", w, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-x", x, JoinedOrSeparate, INVALID, INVALID, "d", 0, + "Treat subsequent input files as having type <language>", "<language>") +OPTION("-y", y, Joined, INVALID, INVALID, "", 0, 0, 0) diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h new file mode 100644 index 000000000000..8b959d369c0e --- /dev/null +++ b/include/clang/Driver/Options.h @@ -0,0 +1,90 @@ +//===--- Options.h - Option info & table ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTIONS_H_ +#define CLANG_DRIVER_OPTIONS_H_ + +namespace clang { +namespace driver { +namespace options { + enum ID { + OPT_INVALID = 0, // This is not an option ID. + OPT_INPUT, // Reserved ID for input option. + OPT_UNKNOWN, // Reserved ID for unknown option. +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/Options.def" + LastOption +#undef OPTION + }; +} + + class Arg; + class InputArgList; + class Option; + + /// OptTable - Provide access to the Option info table. + /// + /// The OptTable class provides a layer of indirection which allows + /// Option instance to be created lazily. In the common case, only a + /// few options will be needed at runtime; the OptTable class + /// maintains enough information to parse command lines without + /// instantiating Options, while letting other parts of the driver + /// still use Option instances where convient. + class OptTable { + /// The table of options which have been constructed, indexed by + /// option::ID - 1. + mutable Option **Options; + + /// The index of the first option which can be parsed (i.e., is + /// not a special option like 'input' or 'unknown', and is not an + /// option group). + unsigned FirstSearchableOption; + + Option *constructOption(options::ID id) const; + + public: + OptTable(); + ~OptTable(); + + unsigned getNumOptions() const; + + const char *getOptionName(options::ID id) const; + + /// getOption - Get the given \arg id's Option instance, lazily + /// creating it if necessary. + const Option *getOption(options::ID id) const; + + /// getOptionKind - Get the kind of the given option. + unsigned getOptionKind(options::ID id) const; + + /// getOptionHelpText - Get the help text to use to describe this + /// option. + const char *getOptionHelpText(options::ID id) const; + + /// getOptionMetaVar - Get the meta-variable name to use when + /// describing this options values in the help text. + const char *getOptionMetaVar(options::ID id) const; + + /// parseOneArg - Parse a single argument; returning the new + /// argument and updating Index. + /// + /// \param [in] [out] Index - The current parsing position in the + /// argument string list; on return this will be the index of the + /// next argument string to parse. + /// + /// \return - The parsed argument, or 0 if the argument is missing + /// values (in which case Index still points at the conceptual + /// next argument string to parse). + Arg *ParseOneArg(const InputArgList &Args, unsigned &Index) const; + }; +} +} + +#endif diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h new file mode 100644 index 000000000000..a0c42ea17362 --- /dev/null +++ b/include/clang/Driver/Phases.h @@ -0,0 +1,32 @@ +//===--- Phases.h - Transformations on Driver Types -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_PHASES_H_ +#define CLANG_DRIVER_PHASES_H_ + +namespace clang { +namespace driver { +namespace phases { + /// ID - Ordered values for successive stages in the + /// compilation process which interact with user options. + enum ID { + Preprocess, + Precompile, + Compile, + Assemble, + Link + }; + + const char *getPhaseName(ID Id); + +} // end namespace phases +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h new file mode 100644 index 000000000000..d8b37e9ead88 --- /dev/null +++ b/include/clang/Driver/Tool.h @@ -0,0 +1,69 @@ +//===--- Tool.h - Compilation Tools -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TOOL_H_ +#define CLANG_DRIVER_TOOL_H_ + +namespace llvm { + template<typename T, unsigned N> class SmallVector; +} + +namespace clang { +namespace driver { + class ArgList; + class Compilation; + class InputInfo; + class Job; + class JobAction; + class ToolChain; + + typedef llvm::SmallVector<InputInfo, 4> InputInfoList; + +/// Tool - Information on a specific compilation tool. +class Tool { + /// The tool name (for debugging). + const char *Name; + + /// The tool chain this tool is a part of. + const ToolChain &TheToolChain; + +public: + Tool(const char *Name, const ToolChain &TC); + +public: + virtual ~Tool(); + + const char *getName() const { return Name; } + + const ToolChain &getToolChain() const { return TheToolChain; } + + virtual bool acceptsPipedInput() const = 0; + virtual bool canPipeOutput() const = 0; + virtual bool hasIntegratedCPP() const = 0; + + /// ConstructJob - Construct jobs to perform the action \arg JA, + /// writing to \arg Output and with \arg Inputs. + /// + /// \param Dest - Where to put the resulting commands. + /// \param TCArgs - The argument list for this toolchain, with any + /// tool chain specific translations applied. + /// \param LinkingOutput - If this output will eventually feed the + /// linker, then this is the final output name of the linked image. + virtual void ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const = 0; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h new file mode 100644 index 000000000000..6196c130266d --- /dev/null +++ b/include/clang/Driver/ToolChain.h @@ -0,0 +1,105 @@ +//===--- ToolChain.h - Collections of tools for one platform ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TOOLCHAIN_H_ +#define CLANG_DRIVER_TOOLCHAIN_H_ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/System/Path.h" +#include <string> + +namespace clang { +namespace driver { + class Compilation; + class DerivedArgList; + class HostInfo; + class InputArgList; + class JobAction; + class Tool; + +/// ToolChain - Access to tools for a single platform. +class ToolChain { +public: + typedef llvm::SmallVector<std::string, 4> path_list; + +private: + const HostInfo &Host; + const llvm::Triple Triple; + + /// The list of toolchain specific path prefixes to search for + /// files. + path_list FilePaths; + + /// The list of toolchain specific path prefixes to search for + /// programs. + path_list ProgramPaths; + +protected: + ToolChain(const HostInfo &Host, const llvm::Triple &_Triple); + +public: + virtual ~ToolChain(); + + // Accessors + + const HostInfo &getHost() const { return Host; } + std::string getArchName() const { return Triple.getArchName(); } + std::string getPlatform() const { return Triple.getVendorName(); } + std::string getOS() const { return Triple.getOSName(); } + + std::string getTripleString() const { + return Triple.getTriple(); + } + + path_list &getFilePaths() { return FilePaths; } + const path_list &getFilePaths() const { return FilePaths; } + + path_list &getProgramPaths() { return ProgramPaths; } + const path_list &getProgramPaths() const { return ProgramPaths; } + + // Tool access. + + /// TranslateArgs - Create a new derived argument list for any + /// argument translations this ToolChain may wish to perform. + virtual DerivedArgList *TranslateArgs(InputArgList &Args) const = 0; + + /// SelectTool - Choose a tool to use to handle the action \arg JA. + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const = 0; + + // Helper methods + + llvm::sys::Path GetFilePath(const Compilation &C, const char *Name) const; + llvm::sys::Path GetProgramPath(const Compilation &C, const char *Name, + bool WantFile = false) const; + + // Platform defaults information + + /// IsMathErrnoDefault - Does this tool chain set -fmath-errno by + /// default. + virtual bool IsMathErrnoDefault() const = 0; + + /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables + /// by default. + virtual bool IsUnwindTablesDefault() const = 0; + + /// GetDefaultRelocationModel - Return the LLVM name of the default + /// relocation model for this tool chain. + virtual const char *GetDefaultRelocationModel() const = 0; + + /// GetForcedPicModel - Return the LLVM name of the forced PIC model + /// for this tool chain, or 0 if this tool chain does not force a + /// particular PIC mode. + virtual const char *GetForcedPicModel() const = 0; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def new file mode 100644 index 000000000000..8d24e5013fb0 --- /dev/null +++ b/include/clang/Driver/Types.def @@ -0,0 +1,78 @@ +//===--- Types.def - Driver Type info ---------------------------*- 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 driver type information. Users of this file +// must define the TYPE macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#ifndef TYPE +#error "Define TYPE prior to including this file!" +#endif + +// TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) + +// The first value is the type name as a string; for types which can +// be user specified this should be the equivalent -x option. + +// The second value is the type id, which will result in a +// clang::driver::types::TY_XX enum constant. + +// The third value is that id of the type for preprocessed inputs of +// this type, or INVALID if this type is not preprocessed. + +// The fourth value is the suffix to use when creating temporary files +// of this type, or null if unspecified. + +// The fifth value is a string containt option flags. Valid values: +// a - The type should only be assembled. +// p - The type should only be precompiled. +// u - The type can be user specified (with -x). +// A - The type's temporary suffix should be appended when generating +// outputs of this type. + + +// C family source language (with and without preprocessing). +TYPE("cpp-output", PP_C, INVALID, "i", "u") +TYPE("c", C, PP_C, 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") +TYPE("c++", CXX, PP_CXX, 0, "u") +TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", "u") +TYPE("objective-c++", ObjCXX, PP_ObjCXX, 0, "u") + +// C family input files to precompile. +TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", "p") +TYPE("c-header", CHeader, PP_CHeader, 0, "pu") +TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", "p") +TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, 0, "pu") +TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p") +TYPE("c++-header", CXXHeader, PP_CXXHeader, 0, "pu") +TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p") +TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, 0, "pu") + +// Other languages. +TYPE("ada", Ada, INVALID, 0, "u") +TYPE("assembler", PP_Asm, INVALID, "s", "au") +TYPE("assembler-with-cpp", Asm, PP_Asm, 0, "au") +TYPE("f95", PP_Fortran, INVALID, 0, "u") +TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u") +TYPE("java", Java, INVALID, 0, "u") + +// Misc. +TYPE("llvm-asm", LLVMAsm, INVALID, "s", "") +TYPE("llvm-bc", LLVMBC, INVALID, "o", "") +TYPE("plist", Plist, INVALID, "plist", "") +TYPE("precompiled-header", PCH, INVALID, "gch", "A") +TYPE("object", Object, INVALID, "o", "") +TYPE("treelang", Treelang, INVALID, 0, "u") +TYPE("image", Image, INVALID, "out", "") +TYPE("dependencies", Dependencies, INVALID, "d", "") +TYPE("none", Nothing, INVALID, 0, "u") diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h new file mode 100644 index 000000000000..92520a77b33b --- /dev/null +++ b/include/clang/Driver/Types.h @@ -0,0 +1,85 @@ +//===--- Types.h - Input & Temporary Driver Types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TYPES_H_ +#define CLANG_DRIVER_TYPES_H_ + +#include "clang/Driver/Phases.h" + +namespace clang { +namespace driver { +namespace types { + enum ID { + TY_INVALID, +#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) TY_##ID, +#include "clang/Driver/Types.def" +#undef TYPE + TY_LAST + }; + + /// getTypeName - Return the name of the type for \arg Id. + const char *getTypeName(ID Id); + + /// getPreprocessedType - Get the ID of the type for this input when + /// it has been preprocessed, or INVALID if this input is not + /// preprocessed. + ID getPreprocessedType(ID Id); + + /// getTypeTempSuffix - Return the suffix to use when creating a + /// temp file of this type, or null if unspecified. + const char *getTypeTempSuffix(ID Id); + + /// onlyAssembleType - Should this type only be assembled. + bool onlyAssembleType(ID Id); + + /// onlyPrecompileType - Should this type only be precompiled. + bool onlyPrecompileType(ID Id); + + /// canTypeBeUserSpecified - Can this type be specified on the + /// command line (by the type name); this is used when forwarding + /// commands to gcc. + bool canTypeBeUserSpecified(ID Id); + + /// appendSuffixForType - When generating outputs of this type, + /// should the suffix be appended (instead of replacing the existing + /// suffix). + bool appendSuffixForType(ID Id); + + /// canLipoType - Is this type acceptable as the output of a + /// universal build (currently, just the Nothing, Image, and Object + /// types). + bool canLipoType(ID Id); + + /// isAcceptedByClang - Can clang handle this input type. + bool isAcceptedByClang(ID Id); + + /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers). + bool isCXX(ID Id); + + /// lookupTypeForExtension - Lookup the type to use for the file + /// extension \arg Ext. + ID lookupTypeForExtension(const char *Ext); + + /// lookupTypeForTypSpecifier - Lookup the type to use for a user + /// specified type name. + ID lookupTypeForTypeSpecifier(const char *Name); + + /// getNumCompilationPhases - Return the complete number of phases + /// to be done for this type. + unsigned getNumCompilationPhases(ID Id); + + /// getCompilationPhase - Return the \args N th compilation phase to + /// be done for this type. + phases::ID getCompilationPhase(ID Id, unsigned N); + +} // end namespace types +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h new file mode 100644 index 000000000000..52f268d182a8 --- /dev/null +++ b/include/clang/Driver/Util.h @@ -0,0 +1,30 @@ +//===--- Util.h - Common Driver Utilities -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_UTIL_H_ +#define CLANG_DRIVER_UTIL_H_ + +namespace llvm { + template<typename T, unsigned N> class SmallVector; +} + +namespace clang { +namespace driver { + class Action; + + /// ArgStringList - Type used for constructing argv lists for subprocesses. + typedef llvm::SmallVector<const char*, 16> ArgStringList; + + /// ActionList - Type used for lists of actions. + typedef llvm::SmallVector<Action*, 3> ActionList; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h new file mode 100644 index 000000000000..04365d7c78d8 --- /dev/null +++ b/include/clang/Frontend/ASTConsumers.h @@ -0,0 +1,107 @@ +//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef DRIVER_ASTCONSUMERS_H +#define DRIVER_ASTCONSUMERS_H + +#include "llvm/Support/raw_ostream.h" +#include <string> +#include <iosfwd> + +namespace llvm { + class Module; + namespace sys { class Path; } +} +namespace clang { + +class ASTConsumer; +class Diagnostic; +class FileManager; +class Preprocessor; +class PreprocessorFactory; +struct CompileOptions; +class LangOptions; + +// AST pretty-printer: prints out the AST in a format that is close to the +// original C code. The output is intended to be in a format such that +// clang could re-parse the output back into the same AST, but the +// implementation is still incomplete. +ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS); + +// AST XML-printer: prints out the AST in a XML format +// The output is intended to be in a format such that +// clang or any other tool could re-parse the output back into the same AST, +// but the implementation is still incomplete. +ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream* OS); + +// AST dumper: dumps the raw AST in human-readable form to stderr; this is +// intended for debugging. +ASTConsumer *CreateASTDumper(); + +// 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. +ASTConsumer *CreateASTViewer(); + +// DeclContext printer: prints out the DeclContext tree in human-readable form +// to stderr; this is intended for debugging. +ASTConsumer *CreateDeclContextPrinter(); + +// ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code. +// This is considered experimental, and only works with Apple's ObjC runtime. +ASTConsumer *CreateObjCRewriter(const std::string& InFile, + llvm::raw_ostream* OS, + Diagnostic &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning); + +// LLVM code generator: uses the code generation backend to generate LLVM +// assembly. This runs optimizations depending on the CompileOptions +// parameter. The output depends on the Action parameter. +enum BackendAction { + Backend_EmitAssembly, // Emit native assembly + Backend_EmitBC, // Emit LLVM bitcode file + Backend_EmitLL, // Emit human-readable LLVM assembly + Backend_EmitNothing // Don't emit anything (benchmarking mode) +}; +ASTConsumer *CreateBackendConsumer(BackendAction Action, + Diagnostic &Diags, + const LangOptions &Features, + const CompileOptions &CompileOpts, + const std::string &ModuleID, + llvm::raw_ostream *OS); + +// HTML printer: uses the rewriter to convert source code to HTML with +// syntax highlighting suitable for viewing in a web-browser. +ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, + Preprocessor *PP, PreprocessorFactory *PPF); + +// PCH generator: generates a precompiled header file; this file can be +// used later with the PCHReader (clang-cc option -include-pch) +// to speed up compile times. +ASTConsumer *CreatePCHGenerator(const Preprocessor &PP, + llvm::raw_ostream *OS); + +// Block rewriter: rewrites code using the Apple blocks extension to pure +// C code. Output is always sent to stdout. +ASTConsumer *CreateBlockRewriter(const std::string &InFile, + Diagnostic &Diags, + const LangOptions &LangOpts); + +// 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/Analyses.def b/include/clang/Frontend/Analyses.def new file mode 100644 index 000000000000..3492d09c10aa --- /dev/null +++ b/include/clang/Frontend/Analyses.def @@ -0,0 +1,77 @@ +//===-- Analyses.def - Metadata about Static Analyses -----------*- 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 set of static analyses used by AnalysisConsumer. +// +//===----------------------------------------------------------------------===// + +#ifndef ANALYSIS +#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(WarnDeadStores, "warn-dead-stores", + "Warn about stores to dead variables", Code) + +ANALYSIS(WarnUninitVals, "warn-uninit-values", + "Warn about uses of uninitialized variables", Code) + +ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs", + "Warn about Objective-C method signatures with type incompatibilities", + ObjCImplementation) + +ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc", + "Warn about Objective-C classes that lack a correct implementation of -dealloc", + ObjCImplementation) + +ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars", + "Warn about private ivars that are never used", ObjCImplementation) + +ANALYSIS(CheckerSimple, "checker-simple", + "Perform simple path-sensitive checks.", Code) + +ANALYSIS(CheckerCFRef, "checker-cfref", + "Run the [Core] Foundation reference count checker", Code) + + +#ifndef ANALYSIS_STORE +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store", CreateBasicStoreManager) +ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) + +#ifndef ANALYSIS_CONSTRAINTS +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_CONSTRAINTS(BasicConstraints, "basic", "Use basic constraint tracking", CreateBasicConstraintManager) +ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) + +#ifndef ANALYSIS_DIAGNOSTICS +#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) + +#undef ANALYSIS +#undef ANALYSIS_STORE +#undef ANALYSIS_CONSTRAINTS +#undef ANALYSIS_DIAGNOSTICS +#undef ANALYSIS_STORE + diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h new file mode 100644 index 000000000000..0e4b09bd2a12 --- /dev/null +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -0,0 +1,78 @@ +//===--- AnalysisConsumer.h - Front-end hooks for the analysis engine------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include <string> +#include <vector> + +namespace clang { +class ASTConsumer; +class Diagnostic; +class Preprocessor; +class PreprocessorFactory; +class LangOptions; + +/// Analysis - Set of available source code analyses. +enum Analyses { +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME, +#include "clang/Frontend/Analyses.def" +NumAnalyses +}; + +/// AnalysisStores - Set of available analysis store models. +enum AnalysisStores { +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/Frontend/Analyses.def" +NumStores +}; + +/// AnalysisConstraints - Set of available constraint models. +enum AnalysisConstraints { +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/Frontend/Analyses.def" +NumConstraints +}; + +/// AnalysisDiagClients - Set of available diagnostic clients for rendering +/// analysis results. +enum AnalysisDiagClients { +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME, +#include "clang/Frontend/Analyses.def" +NUM_ANALYSIS_DIAG_CLIENTS +}; + +struct AnalyzerOptions { + std::vector<Analyses> AnalysisList; + AnalysisStores AnalysisStoreOpt; + AnalysisConstraints AnalysisConstraintsOpt; + AnalysisDiagClients AnalysisDiagOpt; + bool VisualizeEGDot; + bool VisualizeEGUbi; + bool AnalyzeAll; + bool AnalyzerDisplayProgress; + bool PurgeDead; + bool EagerlyAssume; + std::string AnalyzeSpecificFunction; + bool TrimGraph; +}; + +/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code +/// analysis passes. (The set of analyses run is controlled by command-line +/// options.) +ASTConsumer* CreateAnalysisConsumer(Diagnostic &diags, Preprocessor *pp, + PreprocessorFactory *ppf, + const LangOptions &lopts, + const std::string &output, + const AnalyzerOptions& Opts); + +} diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h new file mode 100644 index 000000000000..1af5e48ea119 --- /dev/null +++ b/include/clang/Frontend/CompileOptions.h @@ -0,0 +1,62 @@ +//===--- CompileOptions.h ---------------------------------------*- 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 CompileOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_COMPILEOPTIONS_H +#define LLVM_CLANG_FRONTEND_COMPILEOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// CompileOptions - Track various options which control how the code +/// is optimized and passed to the backend. +class CompileOptions { +public: + unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. + unsigned OptimizeSize : 1; /// If -Os is specified. + unsigned DebugInfo : 1; /// Should generate deubg info (-g). + unsigned UnitAtATime : 1; /// Unused. For mirroring GCC + /// optimization selection. + unsigned InlineFunctions : 1; /// Should functions be inlined? + unsigned SimplifyLibCalls : 1; /// Should standard library calls be + /// treated specially. + unsigned UnrollLoops : 1; /// Control whether loops are unrolled. + unsigned VerifyModule : 1; /// Control whether the module + /// should be run through the LLVM Verifier. + unsigned TimePasses : 1; /// Set when -ftime-report is enabled. + unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. + + /// CPU - An optional CPU to target. + std::string CPU; + + /// Features - A list of subtarget features to pass to the code + /// generator. + std::vector<std::string> Features; + +public: + CompileOptions() { + OptimizationLevel = 0; + OptimizeSize = 0; + DebugInfo = 0; + UnitAtATime = 1; + InlineFunctions = SimplifyLibCalls = UnrollLoops = 0; + VerifyModule = 1; + TimePasses = 0; + NoCommon = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h new file mode 100644 index 000000000000..99db717190dd --- /dev/null +++ b/include/clang/Frontend/DocumentXML.h @@ -0,0 +1,128 @@ +//===--- DocumentXML.h - XML document for ASTs ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_DOCUMENTXML_H +#define LLVM_CLANG_FRONTEND_DOCUMENTXML_H + +#include <string> +#include <map> +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +//--------------------------------------------------------- forwards +class DeclContext; +class Decl; +class NamedDecl; +class FunctionDecl; +class ASTContext; + +//--------------------------------------------------------- +namespace XML +{ + // id maps: + template<class T> + struct IdMap : llvm::DenseMap<T, unsigned> {}; + + template<> + struct IdMap<QualType> : std::map<QualType, unsigned, QualTypeOrdering> {}; + + template<> + struct IdMap<std::string> : std::map<std::string, unsigned> {}; +} + +//--------------------------------------------------------- +class DocumentXML +{ +public: + DocumentXML(const std::string& rootName, llvm::raw_ostream& out); + ~DocumentXML(); + + void initialize(ASTContext &Context); + void PrintDecl(Decl *D); + void PrintStmt(const Stmt *S); // defined in StmtXML.cpp + + void finalize(); + + + DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this + DocumentXML& toParent(); // returns *this + + template<class T> + void addAttribute(const char* pName, const T& value); + + void addTypeAttribute(const QualType& pType); + void addRefAttribute(const NamedDecl* D); + + enum tContextUsage { CONTEXT_AS_CONTEXT, CONTEXT_AS_ID }; + void addContextAttribute(const DeclContext *DC, tContextUsage usage = CONTEXT_AS_CONTEXT); + void addSourceFileAttribute(const std::string& fileName); + + PresumedLoc addLocation(const SourceLocation& Loc); + void addLocationRange(const SourceRange& R); + + static std::string escapeString(const char* pStr, std::string::size_type len); + +private: + DocumentXML(const DocumentXML&); // not defined + DocumentXML& operator=(const DocumentXML&); // not defined + + struct NodeXML; + + NodeXML* Root; + NodeXML* CurrentNode; // always after Root + llvm::raw_ostream& Out; + ASTContext *Ctx; + int CurrentIndent; + bool HasCurrentNodeSubNodes; + + + XML::IdMap<QualType> Types; + XML::IdMap<const DeclContext*> Contexts; + XML::IdMap<const Type*> BasicTypes; + XML::IdMap<std::string> SourceFiles; + XML::IdMap<const NamedDecl*> Decls; + + void addContextsRecursively(const DeclContext *DC); + void addBasicTypeRecursively(const Type* pType); + void addTypeRecursively(const QualType& pType); + + void PrintFunctionDecl(FunctionDecl *FD); + void addDeclIdAttribute(const NamedDecl* D); + void addTypeIdAttribute(const Type* pType); + void Indent(); +}; + +//--------------------------------------------------------- inlines + +inline void DocumentXML::initialize(ASTContext &Context) +{ + Ctx = &Context; +} + +//--------------------------------------------------------- +template<class T> +inline void DocumentXML::addAttribute(const char* pName, const T& value) +{ + Out << ' ' << pName << "=\"" << value << "\""; +} + +//--------------------------------------------------------- + +} //namespace clang + +#endif //LLVM_CLANG_DOCUMENTXML_H diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h new file mode 100644 index 000000000000..7fcd682bf66c --- /dev/null +++ b/include/clang/Frontend/FixItRewriter.h @@ -0,0 +1,95 @@ +//===--- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a diagnostic client adaptor that performs rewrites as +// suggested by code modification hints attached to diagnostics. It +// then forwards any diagnostics to the adapted diagnostic client. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H +#define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Rewrite/Rewriter.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class SourceManager; +class FileEntry; + +/// \brief Stores a source location in the form that it shows up on +/// the Clang command line, e.g., file:line:column. +/// +/// FIXME: Would prefer to use real SourceLocations, but I don't see a +/// good way to resolve them during parsing. +struct RequestedSourceLocation { + const FileEntry *File; + unsigned Line; + unsigned Column; +}; + +class FixItRewriter : public DiagnosticClient { + /// \brief The diagnostics machinery. + Diagnostic &Diags; + + /// \brief The rewriter used to perform the various code + /// modifications. + Rewriter Rewrite; + + /// \brief The diagnostic client that performs the actual formatting + /// of error messages. + DiagnosticClient *Client; + + /// \brief The number of rewriter failures. + unsigned NumFailures; + + /// \brief Locations at which we should perform fix-its. + /// + /// When empty, perform fix-it modifications everywhere. + llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations; + +public: + /// \brief Initialize a new fix-it rewriter. + FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts); + + /// \brief Destroy the fix-it rewriter. + ~FixItRewriter(); + + /// \brief Add a location where fix-it modifications should be + /// performed. + void addFixItLocation(RequestedSourceLocation Loc) { + FixItLocations.push_back(Loc); + } + + /// \brief Write the modified source file. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFile(const std::string &InFileName, + const std::string &OutFileName = std::string()); + + /// IncludeInDiagnosticCounts - This method (whose default implementation + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticClient should be included in the number of diagnostics + /// reported by Diagnostic. + virtual bool IncludeInDiagnosticCounts() const; + + /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + + /// \brief Emit a diagnostic via the adapted diagnostic client. + void Diag(FullSourceLoc Loc, unsigned DiagID); +}; + +} + +#endif // LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h new file mode 100644 index 000000000000..02432ca3a55c --- /dev/null +++ b/include/clang/Frontend/FrontendDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticFrontend.h - Diagnostics for frontend --------*- 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_FRONTENDDIAGNOSTIC_H +#define LLVM_CLANG_FRONTENDDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define FRONTENDSTART +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#undef DIAG + NUM_BUILTIN_FRONTEND_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/InitHeaderSearch.h b/include/clang/Frontend/InitHeaderSearch.h new file mode 100644 index 000000000000..51516661c99e --- /dev/null +++ b/include/clang/Frontend/InitHeaderSearch.h @@ -0,0 +1,74 @@ +//===--- InitHeaderSearch.h - Initialize header search paths ----*- 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 InitHeaderSearch class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_ +#define LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_ + +#include <string> +#include <vector> + +#include "clang/Lex/DirectoryLookup.h" + +namespace clang { + +class HeaderSearch; +class LangOptions; + +/// InitHeaderSearch - This class makes it easier to set the search paths of +/// a HeaderSearch object. InitHeaderSearch stores several search path lists +/// internally, which can be sent to a HeaderSearch object in one swoop. +class InitHeaderSearch { + std::vector<DirectoryLookup> IncludeGroup[4]; + HeaderSearch& Headers; + bool Verbose; + std::string isysroot; + +public: + /// InitHeaderSearch::IncludeDirGroup - Identifies the several search path + /// lists stored internally. + enum IncludeDirGroup { + Quoted = 0, //< `#include ""` paths. Thing `gcc -iquote`. + Angled, //< Paths for both `#include ""` and `#include <>`. (`-I`) + System, //< Like Angled, but marks system directories. + After //< Like System, but searched after the system directories. + }; + + InitHeaderSearch(HeaderSearch &HS, + bool verbose = false, const std::string &iSysroot = "") + : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} + + /// AddPath - Add the specified path to the specified group list. + void AddPath(const std::string &Path, IncludeDirGroup Group, + bool isCXXAware, bool isUserSupplied, + bool isFramework, bool IgnoreSysRoot = false); + + /// AddEnvVarPaths - Add a list of paths from an environment variable to a + /// header search list. + void AddEnvVarPaths(const char *Name); + + /// AddDefaultEnvVarPaths - Adds list of paths from default environment + /// variables such as CPATH. + void AddDefaultEnvVarPaths(const LangOptions &Lang); + + /// AddDefaultSystemIncludePaths - Adds the default system include paths so + /// that e.g. stdio.h is found. + void AddDefaultSystemIncludePaths(const LangOptions &Lang); + + /// Realize - Merges all search path lists into one list and send it to + /// HeaderSearch. + void Realize(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/InitPreprocessor.h b/include/clang/Frontend/InitPreprocessor.h new file mode 100644 index 000000000000..eb03602dc57b --- /dev/null +++ b/include/clang/Frontend/InitPreprocessor.h @@ -0,0 +1,70 @@ +//===--- InitPreprocessor.h - InitializePreprocessor function. --*- 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 clang::InitializePreprocessor function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_INIT_PREPROCESSOR_H_ +#define LLVM_CLANG_FRONTEND_INIT_PREPROCESSOR_H_ + +#include <string> +#include <vector> + +namespace clang { + +class Preprocessor; +class LangOptions; + +/// PreprocessorInitOptions - This class is used for passing the various +/// options used in preprocessor initialization to InitializePreprocessor(). +class PreprocessorInitOptions { + std::vector<std::pair<std::string, bool/*isUndef*/> > Macros; + std::vector<std::pair<std::string, bool/*isPTH*/> > Includes; + std::vector<std::string> MacroIncludes; + +public: + + void addMacroDef(const std::string &Name) { + Macros.push_back(std::make_pair(Name, false)); + } + void addMacroUndef(const std::string &Name) { + Macros.push_back(std::make_pair(Name, true)); + } + void addInclude(const std::string &Name, bool isPTH = false) { + Includes.push_back(std::make_pair(Name, isPTH)); + } + void addMacroInclude(const std::string &Name) { + MacroIncludes.push_back(Name); + } + + typedef std::vector<std::pair<std::string, + bool> >::const_iterator macro_iterator; + macro_iterator macro_begin() const { return Macros.begin(); } + macro_iterator macro_end() const { return Macros.end(); } + + typedef std::vector<std::pair<std::string, + bool> >::const_iterator include_iterator; + include_iterator include_begin() const { return Includes.begin(); } + include_iterator include_end() const { return Includes.end(); } + + typedef std::vector<std::string>::const_iterator imacro_iterator; + imacro_iterator imacro_begin() const { return MacroIncludes.begin(); } + imacro_iterator imacro_end() const { return MacroIncludes.end(); } +}; + +/// InitializePreprocessor - Initialize the preprocessor getting it and the +/// environment ready to process a single file. This returns true on error. +/// +bool InitializePreprocessor(Preprocessor &PP, + const PreprocessorInitOptions& InitOptions); + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/ManagerRegistry.h b/include/clang/Frontend/ManagerRegistry.h new file mode 100644 index 000000000000..ecab67a3b676 --- /dev/null +++ b/include/clang/Frontend/ManagerRegistry.h @@ -0,0 +1,53 @@ +//===-- 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_FRONTEND_MANAGER_REGISTRY_H +#define LLVM_CLANG_FRONTEND_MANAGER_REGISTRY_H + +#include "clang/Analysis/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/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h new file mode 100644 index 000000000000..0862cd6390f4 --- /dev/null +++ b/include/clang/Frontend/PCHBitCodes.h @@ -0,0 +1,660 @@ +//===- PCHBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines Bitcode enum values for Clang precompiled header files. +// +// The enum values defined in this file should be considered permanent. If +// new features are added, they should have values added at the end of the +// respective lists. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H +#define LLVM_CLANG_FRONTEND_PCHBITCODES_H + +#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Support/DataTypes.h" + +namespace clang { + namespace pch { + /// \brief PCH major version number supported by this version of + /// Clang. + /// + /// Whenever the PCH format changes in a way that makes it + /// incompatible with previous versions (such that a reader + /// designed for the previous version could not support reading + /// the new version), this number should be increased. + const unsigned VERSION_MAJOR = 1; + + /// \brief PCH minor version number supported by this version of + /// Clang. + /// + /// Whenever the PCH format changes in a way that is still + /// compatible with previous versions (such that a reader designed + /// for the previous version could still support reading the new + /// version by ignoring new kinds of subblocks), this number + /// should be increased. + const unsigned VERSION_MINOR = 0; + + /// \brief An ID number that refers to a declaration in a PCH file. + /// + /// The ID numbers of types are consecutive (in order of + /// discovery) and start at 2. 0 is reserved for NULL, and 1 is + /// reserved for the translation unit declaration. + typedef uint32_t DeclID; + + /// \brief An ID number that refers to a type in a PCH file. + /// + /// The ID of a type is partitioned into two parts: the lower + /// three bits are used to store the const/volatile/restrict + /// qualifiers (as with QualType) and the upper bits provide a + /// type index. The type index values are partitioned into two + /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type + /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a + /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are + /// other types that have serialized representations. + typedef uint32_t TypeID; + + /// \brief An ID number that refers to an identifier in a PCH + /// file. + typedef uint32_t IdentID; + + typedef uint32_t SelectorID; + + /// \brief Describes the various kinds of blocks that occur within + /// a PCH file. + enum BlockIDs { + /// \brief The PCH block, which acts as a container around the + /// full PCH block. + PCH_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// \brief The block containing information about the source + /// manager. + SOURCE_MANAGER_BLOCK_ID, + + /// \brief The block containing information about the + /// preprocessor. + PREPROCESSOR_BLOCK_ID, + + /// \brief The block containing the definitions of all of the + /// types used within the PCH file. + TYPES_BLOCK_ID, + + /// \brief The block containing the definitions of all of the + /// declarations stored in the PCH file. + DECLS_BLOCK_ID + }; + + /// \brief Record types that occur within the PCH block itself. + enum PCHRecordTypes { + /// \brief Offset of each type within the types block. + /// + /// The TYPE_OFFSET constant describes the record that occurs + /// within the block identified by TYPE_OFFSETS_BLOCK_ID within + /// the PCH file. The record itself is an array of offsets that + /// point into the types block (identified by TYPES_BLOCK_ID in + /// the PCH file). The index into the array is based on the ID + /// of a type. For a given type ID @c T, the lower three bits of + /// @c T are its qualifiers (const, volatile, restrict), as in + /// the QualType class. The upper bits, after being shifted and + /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the + /// TYPE_OFFSET block to determine the offset of that type's + /// corresponding record within the TYPES_BLOCK_ID block. + TYPE_OFFSET = 1, + + /// \brief Record code for the offsets of each decl. + /// + /// The DECL_OFFSET constant describes the record that occurs + /// within the block identifier by DECL_OFFSETS_BLOCK_ID within + /// the PCH file. The record itself is an array of offsets that + /// point into the declarations block (identified by + /// DECLS_BLOCK_ID). The declaration ID is an index into this + /// record, after subtracting one to account for the use of + /// declaration ID 0 for a NULL declaration pointer. Index 0 is + /// reserved for the translation unit declaration. + DECL_OFFSET = 2, + + /// \brief Record code for the language options table. + /// + /// The record with this code contains the contents of the + /// LangOptions structure. We serialize the entire contents of + /// the structure, and let the reader decide which options are + /// actually important to check. + LANGUAGE_OPTIONS = 3, + + /// \brief PCH metadata, including the PCH file version number + /// and the target triple used to build the PCH file. + METADATA = 4, + + /// \brief Record code for the table of offsets of each + /// identifier ID. + /// + /// The offset table contains offsets into the blob stored in + /// the IDENTIFIER_TABLE record. Each offset points to the + /// NULL-terminated string that corresponds to that identifier. + IDENTIFIER_OFFSET = 5, + + /// \brief Record code for the identifier table. + /// + /// The identifier table is a simple blob that contains + /// NULL-terminated strings for all of the identifiers + /// referenced by the PCH file. The IDENTIFIER_OFFSET table + /// contains the mapping from identifier IDs to the characters + /// in this blob. Note that the starting offsets of all of the + /// identifiers are odd, so that, when the identifier offset + /// table is loaded in, we can use the low bit to distinguish + /// between offsets (for unresolved identifier IDs) and + /// IdentifierInfo pointers (for already-resolved identifier + /// IDs). + IDENTIFIER_TABLE = 6, + + /// \brief Record code for the array of external definitions. + /// + /// The PCH file contains a list of all of the unnamed external + /// definitions present within the parsed headers, stored as an + /// array of declaration IDs. These external definitions will be + /// reported to the AST consumer after the PCH file has been + /// read, since their presence can affect the semantics of the + /// program (e.g., for code generation). + EXTERNAL_DEFINITIONS = 7, + + /// \brief Record code for the set of non-builtin, special + /// types. + /// + /// This record contains the type IDs for the various type nodes + /// that are constructed during semantic analysis (e.g., + /// __builtin_va_list). The SPECIAL_TYPE_* constants provide + /// offsets into this record. + SPECIAL_TYPES = 8, + + /// \brief Record code for the extra statistics we gather while + /// generating a PCH file. + STATISTICS = 9, + + /// \brief Record code for the array of tentative definitions. + TENTATIVE_DEFINITIONS = 10, + + /// \brief Record code for the array of locally-scoped external + /// declarations. + LOCALLY_SCOPED_EXTERNAL_DECLS = 11, + + /// \brief Record code for the table of offsets into the + /// Objective-C method pool. + SELECTOR_OFFSETS = 12, + + /// \brief Record code for the Objective-C method pool, + METHOD_POOL = 13, + + /// \brief The value of the next __COUNTER__ to dispense. + /// [PP_COUNTER_VALUE, Val] + PP_COUNTER_VALUE = 14, + + /// \brief Record code for the table of offsets into the block + /// of source-location information. + SOURCE_LOCATION_OFFSETS = 15, + + /// \brief Record code for the set of source location entries + /// that need to be preloaded by the PCH reader. + /// + /// This set contains the source location entry for the + /// predefines buffer and for any file entries that need to be + /// preloaded. + SOURCE_LOCATION_PRELOADS = 16, + + /// \brief Record code for the stat() cache. + STAT_CACHE = 17, + + /// \brief Record code for the set of ext_vector type names. + EXT_VECTOR_DECLS = 18, + + /// \brief Record code for the set of Objective-C category + /// implementations. + OBJC_CATEGORY_IMPLEMENTATIONS = 19, + + /// \brief Record code for the original file that was used to + /// generate the precompiled header. + ORIGINAL_FILE_NAME = 20 + }; + + /// \brief Record types used within a source manager block. + enum SourceManagerRecordTypes { + /// \brief Describes a source location entry (SLocEntry) for a + /// file. + SM_SLOC_FILE_ENTRY = 1, + /// \brief Describes a source location entry (SLocEntry) for a + /// buffer. + SM_SLOC_BUFFER_ENTRY = 2, + /// \brief Describes a blob that contains the data for a buffer + /// entry. This kind of record always directly follows a + /// SM_SLOC_BUFFER_ENTRY record. + SM_SLOC_BUFFER_BLOB = 3, + /// \brief Describes a source location entry (SLocEntry) for a + /// macro instantiation. + SM_SLOC_INSTANTIATION_ENTRY = 4, + /// \brief Describes the SourceManager's line table, with + /// information about #line directives. + SM_LINE_TABLE = 5, + /// \brief Describes one header file info [isImport, DirInfo, NumIncludes] + /// ControllingMacro is optional. + SM_HEADER_FILE_INFO = 6 + }; + + /// \brief Record types used within a preprocessor block. + enum PreprocessorRecordTypes { + // The macros in the PP section are a PP_MACRO_* instance followed by a + // list of PP_TOKEN instances for each token in the definition. + + /// \brief An object-like macro definition. + /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] + PP_MACRO_OBJECT_LIKE = 1, + + /// \brief A function-like macro definition. + /// [PP_MACRO_FUNCTION_LIKE, <ObjectLikeStuff>, IsC99Varargs, IsGNUVarars, + /// NumArgs, ArgIdentInfoID* ] + PP_MACRO_FUNCTION_LIKE = 2, + + /// \brief Describes one token. + /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] + PP_TOKEN = 3 + }; + + /// \defgroup PCHAST Precompiled header AST constants + /// + /// The constants in this group describe various components of the + /// abstract syntax tree within a precompiled header. + /// + /// @{ + + /// \brief Predefined type IDs. + /// + /// These type IDs correspond to predefined types in the AST + /// context, such as built-in types (int) and special place-holder + /// types (the <overload> and <dependent> type markers). Such + /// types are never actually serialized, since they will be built + /// by the AST context when it is created. + enum PredefinedTypeIDs { + /// \brief The NULL type. + PREDEF_TYPE_NULL_ID = 0, + /// \brief The void type. + PREDEF_TYPE_VOID_ID = 1, + /// \brief The 'bool' or '_Bool' type. + PREDEF_TYPE_BOOL_ID = 2, + /// \brief The 'char' type, when it is unsigned. + PREDEF_TYPE_CHAR_U_ID = 3, + /// \brief The 'unsigned char' type. + PREDEF_TYPE_UCHAR_ID = 4, + /// \brief The 'unsigned short' type. + PREDEF_TYPE_USHORT_ID = 5, + /// \brief The 'unsigned int' type. + PREDEF_TYPE_UINT_ID = 6, + /// \brief The 'unsigned long' type. + PREDEF_TYPE_ULONG_ID = 7, + /// \brief The 'unsigned long long' type. + PREDEF_TYPE_ULONGLONG_ID = 8, + /// \brief The 'char' type, when it is signed. + PREDEF_TYPE_CHAR_S_ID = 9, + /// \brief The 'signed char' type. + PREDEF_TYPE_SCHAR_ID = 10, + /// \brief The C++ 'wchar_t' type. + PREDEF_TYPE_WCHAR_ID = 11, + /// \brief The (signed) 'short' type. + PREDEF_TYPE_SHORT_ID = 12, + /// \brief The (signed) 'int' type. + PREDEF_TYPE_INT_ID = 13, + /// \brief The (signed) 'long' type. + PREDEF_TYPE_LONG_ID = 14, + /// \brief The (signed) 'long long' type. + PREDEF_TYPE_LONGLONG_ID = 15, + /// \brief The 'float' type. + PREDEF_TYPE_FLOAT_ID = 16, + /// \brief The 'double' type. + PREDEF_TYPE_DOUBLE_ID = 17, + /// \brief The 'long double' type. + PREDEF_TYPE_LONGDOUBLE_ID = 18, + /// \brief The placeholder type for overloaded function sets. + PREDEF_TYPE_OVERLOAD_ID = 19, + /// \brief The placeholder type for dependent types. + PREDEF_TYPE_DEPENDENT_ID = 20, + /// \brief The '__uint128_t' type. + PREDEF_TYPE_UINT128_ID = 21, + /// \brief The '__int128_t' type. + PREDEF_TYPE_INT128_ID = 22, + /// \brief The type of 'nullptr'. + PREDEF_TYPE_NULLPTR_ID = 23 + }; + + /// \brief The number of predefined type IDs that are reserved for + /// the PREDEF_TYPE_* constants. + /// + /// Type IDs for non-predefined types will start at + /// NUM_PREDEF_TYPE_IDs. + const unsigned NUM_PREDEF_TYPE_IDS = 100; + + /// \brief Record codes for each kind of type. + /// + /// These constants describe the records that can occur within a + /// block identified by TYPES_BLOCK_ID in the PCH file. Each + /// constant describes a record for a specific type class in the + /// AST. + enum TypeCode { + /// \brief An ExtQualType record. + TYPE_EXT_QUAL = 1, + /// \brief A FixedWidthIntType record. + TYPE_FIXED_WIDTH_INT = 2, + /// \brief A ComplexType record. + TYPE_COMPLEX = 3, + /// \brief A PointerType record. + TYPE_POINTER = 4, + /// \brief A BlockPointerType record. + TYPE_BLOCK_POINTER = 5, + /// \brief An LValueReferenceType record. + TYPE_LVALUE_REFERENCE = 6, + /// \brief An RValueReferenceType record. + TYPE_RVALUE_REFERENCE = 7, + /// \brief A MemberPointerType record. + TYPE_MEMBER_POINTER = 8, + /// \brief A ConstantArrayType record. + TYPE_CONSTANT_ARRAY = 9, + /// \brief An IncompleteArrayType record. + TYPE_INCOMPLETE_ARRAY = 10, + /// \brief A VariableArrayType record. + TYPE_VARIABLE_ARRAY = 11, + /// \brief A VectorType record. + TYPE_VECTOR = 12, + /// \brief An ExtVectorType record. + TYPE_EXT_VECTOR = 13, + /// \brief A FunctionNoProtoType record. + TYPE_FUNCTION_NO_PROTO = 14, + /// \brief A FunctionProtoType record. + TYPE_FUNCTION_PROTO = 15, + /// \brief A TypedefType record. + TYPE_TYPEDEF = 16, + /// \brief A TypeOfExprType record. + TYPE_TYPEOF_EXPR = 17, + /// \brief A TypeOfType record. + TYPE_TYPEOF = 18, + /// \brief A RecordType record. + TYPE_RECORD = 19, + /// \brief An EnumType record. + TYPE_ENUM = 20, + /// \brief An ObjCInterfaceType record. + TYPE_OBJC_INTERFACE = 21, + /// \brief An ObjCQualifiedInterfaceType record. + TYPE_OBJC_QUALIFIED_INTERFACE = 22, + /// \brief An ObjCQualifiedIdType record. + TYPE_OBJC_QUALIFIED_ID = 23 + }; + + /// \brief The type IDs for special types constructed by semantic + /// analysis. + /// + /// The constants in this enumeration are indices into the + /// SPECIAL_TYPES record. + enum SpecialTypeIDs { + /// \brief __builtin_va_list + SPECIAL_TYPE_BUILTIN_VA_LIST = 0, + /// \brief Objective-C "id" type + SPECIAL_TYPE_OBJC_ID = 1, + /// \brief Objective-C selector type + SPECIAL_TYPE_OBJC_SELECTOR = 2, + /// \brief Objective-C Protocol type + SPECIAL_TYPE_OBJC_PROTOCOL = 3, + /// \brief Objective-C Class type + SPECIAL_TYPE_OBJC_CLASS = 4, + /// \brief CFConstantString type + SPECIAL_TYPE_CF_CONSTANT_STRING = 5, + /// \brief Objective-C fast enumeration state type + SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6 + }; + + /// \brief Record codes for each kind of declaration. + /// + /// These constants describe the records that can occur within a + /// declarations block (identified by DECLS_BLOCK_ID). Each + /// constant describes a record for a specific declaration class + /// in the AST. + enum DeclCode { + /// \brief Attributes attached to a declaration. + DECL_ATTR = 1, + /// \brief A TranslationUnitDecl record. + DECL_TRANSLATION_UNIT, + /// \brief A TypedefDecl record. + DECL_TYPEDEF, + /// \brief An EnumDecl record. + DECL_ENUM, + /// \brief A RecordDecl record. + DECL_RECORD, + /// \brief An EnumConstantDecl record. + DECL_ENUM_CONSTANT, + /// \brief A FunctionDecl record. + DECL_FUNCTION, + /// \brief A ObjCMethodDecl record. + DECL_OBJC_METHOD, + /// \brief A ObjCInterfaceDecl record. + DECL_OBJC_INTERFACE, + /// \brief A ObjCProtocolDecl record. + DECL_OBJC_PROTOCOL, + /// \brief A ObjCIvarDecl record. + DECL_OBJC_IVAR, + /// \brief A ObjCAtDefsFieldDecl record. + DECL_OBJC_AT_DEFS_FIELD, + /// \brief A ObjCClassDecl record. + DECL_OBJC_CLASS, + /// \brief A ObjCForwardProtocolDecl record. + DECL_OBJC_FORWARD_PROTOCOL, + /// \brief A ObjCCategoryDecl record. + DECL_OBJC_CATEGORY, + /// \brief A ObjCCategoryImplDecl record. + DECL_OBJC_CATEGORY_IMPL, + /// \brief A ObjCImplementationDecl record. + DECL_OBJC_IMPLEMENTATION, + /// \brief A ObjCCompatibleAliasDecl record. + DECL_OBJC_COMPATIBLE_ALIAS, + /// \brief A ObjCPropertyDecl record. + DECL_OBJC_PROPERTY, + /// \brief A ObjCPropertyImplDecl record. + DECL_OBJC_PROPERTY_IMPL, + /// \brief A FieldDecl record. + DECL_FIELD, + /// \brief A VarDecl record. + DECL_VAR, + /// \brief An ImplicitParamDecl record. + DECL_IMPLICIT_PARAM, + /// \brief A ParmVarDecl record. + DECL_PARM_VAR, + /// \brief An OriginalParmVarDecl record. + DECL_ORIGINAL_PARM_VAR, + /// \brief A FileScopeAsmDecl record. + DECL_FILE_SCOPE_ASM, + /// \brief A BlockDecl record. + DECL_BLOCK, + /// \brief A record that stores the set of declarations that are + /// lexically stored within a given DeclContext. + /// + /// The record itself is an array of declaration IDs, in the + /// order in which those declarations were added to the + /// declaration context. This data is used when iterating over + /// the contents of a DeclContext, e.g., via + /// DeclContext::decls_begin()/DeclContext::decls_end(). + DECL_CONTEXT_LEXICAL, + /// \brief A record that stores the set of declarations that are + /// visible from a given DeclContext. + /// + /// The record itself stores a set of mappings, each of which + /// associates a declaration name with one or more declaration + /// IDs. This data is used when performing qualified name lookup + /// into a DeclContext via DeclContext::lookup. + DECL_CONTEXT_VISIBLE + }; + + /// \brief Record codes for each kind of statement or expression. + /// + /// These constants describe the records that describe statements + /// or expressions. These records can occur within either the type + /// or declaration blocks, so they begin with record values of + /// 50. Each constant describes a record for a specific + /// statement or expression class in the AST. + enum StmtCode { + /// \brief A marker record that indicates that we are at the end + /// of an expression. + STMT_STOP = 50, + /// \brief A NULL expression. + STMT_NULL_PTR, + /// \brief A NullStmt record. + STMT_NULL, + /// \brief A CompoundStmt record. + STMT_COMPOUND, + /// \brief A CaseStmt record. + STMT_CASE, + /// \brief A DefaultStmt record. + STMT_DEFAULT, + /// \brief A LabelStmt record. + STMT_LABEL, + /// \brief An IfStmt record. + STMT_IF, + /// \brief A SwitchStmt record. + STMT_SWITCH, + /// \brief A WhileStmt record. + STMT_WHILE, + /// \brief A DoStmt record. + STMT_DO, + /// \brief A ForStmt record. + STMT_FOR, + /// \brief A GotoStmt record. + STMT_GOTO, + /// \brief An IndirectGotoStmt record. + STMT_INDIRECT_GOTO, + /// \brief A ContinueStmt record. + STMT_CONTINUE, + /// \brief A BreakStmt record. + STMT_BREAK, + /// \brief A ReturnStmt record. + STMT_RETURN, + /// \brief A DeclStmt record. + STMT_DECL, + /// \brief An AsmStmt record. + STMT_ASM, + /// \brief A PredefinedExpr record. + EXPR_PREDEFINED, + /// \brief A DeclRefExpr record. + EXPR_DECL_REF, + /// \brief An IntegerLiteral record. + EXPR_INTEGER_LITERAL, + /// \brief A FloatingLiteral record. + EXPR_FLOATING_LITERAL, + /// \brief An ImaginaryLiteral record. + EXPR_IMAGINARY_LITERAL, + /// \brief A StringLiteral record. + EXPR_STRING_LITERAL, + /// \brief A CharacterLiteral record. + EXPR_CHARACTER_LITERAL, + /// \brief A ParenExpr record. + EXPR_PAREN, + /// \brief A UnaryOperator record. + EXPR_UNARY_OPERATOR, + /// \brief A SizefAlignOfExpr record. + EXPR_SIZEOF_ALIGN_OF, + /// \brief An ArraySubscriptExpr record. + EXPR_ARRAY_SUBSCRIPT, + /// \brief A CallExpr record. + EXPR_CALL, + /// \brief A MemberExpr record. + EXPR_MEMBER, + /// \brief A BinaryOperator record. + EXPR_BINARY_OPERATOR, + /// \brief A CompoundAssignOperator record. + EXPR_COMPOUND_ASSIGN_OPERATOR, + /// \brief A ConditionOperator record. + EXPR_CONDITIONAL_OPERATOR, + /// \brief An ImplicitCastExpr record. + EXPR_IMPLICIT_CAST, + /// \brief A CStyleCastExpr record. + EXPR_CSTYLE_CAST, + /// \brief A CompoundLiteralExpr record. + EXPR_COMPOUND_LITERAL, + /// \brief An ExtVectorElementExpr record. + EXPR_EXT_VECTOR_ELEMENT, + /// \brief An InitListExpr record. + EXPR_INIT_LIST, + /// \brief A DesignatedInitExpr record. + EXPR_DESIGNATED_INIT, + /// \brief An ImplicitValueInitExpr record. + EXPR_IMPLICIT_VALUE_INIT, + /// \brief A VAArgExpr record. + EXPR_VA_ARG, + /// \brief An AddrLabelExpr record. + 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. + EXPR_GNU_NULL, + /// \brief A ShuffleVectorExpr record. + EXPR_SHUFFLE_VECTOR, + /// \brief BlockExpr + EXPR_BLOCK, + /// \brief A BlockDeclRef record. + EXPR_BLOCK_DECL_REF, + + // Objective-C + + /// \brief An ObjCStringLiteral record. + EXPR_OBJC_STRING_LITERAL, + /// \brief An ObjCEncodeExpr record. + EXPR_OBJC_ENCODE, + /// \brief An ObjCSelectorExpr record. + EXPR_OBJC_SELECTOR_EXPR, + /// \brief An ObjCProtocolExpr record. + EXPR_OBJC_PROTOCOL_EXPR, + /// \brief An ObjCIvarRefExpr record. + EXPR_OBJC_IVAR_REF_EXPR, + /// \brief An ObjCPropertyRefExpr record. + EXPR_OBJC_PROPERTY_REF_EXPR, + /// \brief An ObjCKVCRefExpr record. + EXPR_OBJC_KVC_REF_EXPR, + /// \brief An ObjCMessageExpr record. + EXPR_OBJC_MESSAGE_EXPR, + /// \brief An ObjCSuperExpr record. + EXPR_OBJC_SUPER_EXPR, + + /// \brief An ObjCForCollectionStmt record. + STMT_OBJC_FOR_COLLECTION, + /// \brief An ObjCAtCatchStmt record. + STMT_OBJC_CATCH, + /// \brief An ObjCAtFinallyStmt record. + STMT_OBJC_FINALLY, + /// \brief An ObjCAtTryStmt record. + STMT_OBJC_AT_TRY, + /// \brief An ObjCAtSynchronizedStmt record. + STMT_OBJC_AT_SYNCHRONIZED, + /// \brief An ObjCAtThrowStmt record. + STMT_OBJC_AT_THROW + }; + + /// \brief The kinds of designators that can occur in a + /// DesignatedInitExpr. + enum DesignatorTypes { + /// \brief Field designator where only the field name is known. + DESIG_FIELD_NAME = 0, + /// \brief Field designator where the field has been resolved to + /// a declaration. + DESIG_FIELD_DECL = 1, + /// \brief Array designator. + DESIG_ARRAY = 2, + /// \brief GNU array range designator. + DESIG_ARRAY_RANGE = 3 + }; + + /// @} + } +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h new file mode 100644 index 000000000000..1e00ae34137d --- /dev/null +++ b/include/clang/Frontend/PCHReader.h @@ -0,0 +1,567 @@ +//===--- PCHReader.h - Precompiled Headers Reader ---------------*- 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 PCHReader class, which reads a precompiled header. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PCH_READER_H +#define LLVM_CLANG_FRONTEND_PCH_READER_H + +#include "clang/Frontend/PCHBitCodes.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/DataTypes.h" +#include <map> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class AddrLabelExpr; +class ASTConsumer; +class ASTContext; +class Attr; +class Decl; +class DeclContext; +class GotoStmt; +class LabelStmt; +class NamedDecl; +class Preprocessor; +class Sema; +class SwitchCase; + +/// \brief Reads a precompiled head containing the contents of a +/// translation unit. +/// +/// The PCHReader class reads a bitstream (produced by the PCHWriter +/// class) containing the serialized representation of a given +/// abstract syntax tree and its supporting data structures. An +/// instance of the PCHReader can be attached to an ASTContext object, +/// which will provide access to the contents of the PCH file. +/// +/// The PCH reader provides lazy de-serialization of declarations, as +/// required when traversing the AST. Only those AST nodes that are +/// actually required will be de-serialized. +class PCHReader + : public ExternalSemaSource, + public IdentifierInfoLookup, + public ExternalIdentifierLookup, + public ExternalSLocEntrySource { +public: + enum PCHReadResult { Success, Failure, IgnorePCH }; + +private: + /// \brief The semantic analysis object that will be processing the + /// PCH file and the translation unit that uses it. + Sema *SemaObj; + + /// \brief The preprocessor that will be loading the source file. + Preprocessor &PP; + + /// \brief The AST context into which we'll read the PCH file. + ASTContext *Context; + + /// \brief The AST consumer. + ASTConsumer *Consumer; + + /// \brief The bitstream reader from which we'll read the PCH file. + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + + /// 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 file name of the PCH file. + std::string FileName; + + /// \brief The memory buffer that stores the data associated with + /// this PCH file. + llvm::OwningPtr<llvm::MemoryBuffer> Buffer; + + /// \brief Offset type for all of the source location entries in the + /// PCH file. + const uint32_t *SLocOffsets; + + /// \brief The number of source location entries in the PCH file. + unsigned TotalNumSLocEntries; + + /// \brief Cursor used to read source location entries. + llvm::BitstreamCursor SLocEntryCursor; + + /// \brief Offset of each type within the bitstream, indexed by the + /// type ID, or the representation of a Type*. + const uint32_t *TypeOffsets; + + /// \brief Types that have already been loaded from the PCH file. + /// + /// When the pointer at index I is non-NULL, the type with + /// ID = (I + 1) << 3 has already been loaded from the PCH file. + std::vector<Type *> TypesLoaded; + + /// \brief Offset of each declaration within the bitstream, indexed + /// by the declaration ID (-1). + const uint32_t *DeclOffsets; + + /// \brief Declarations that have already been loaded from the PCH file. + /// + /// When the pointer at index I is non-NULL, the declaration with ID + /// = I + 1 has already been loaded. + std::vector<Decl *> DeclsLoaded; + + typedef llvm::DenseMap<const DeclContext *, std::pair<uint64_t, uint64_t> > + DeclContextOffsetsMap; + + /// \brief Offsets of the lexical and visible declarations for each + /// DeclContext. + DeclContextOffsetsMap DeclContextOffsets; + + /// \brief Actual data for the on-disk hash table. + /// + // 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; + + /// \brief Offsets into the identifier table data. + /// + /// This array is indexed by the identifier ID (-1), and provides + /// the offset into IdentifierTableData where the string data is + /// stored. + const uint32_t *IdentifierOffsets; + + /// \brief A vector containing identifiers that have already been + /// loaded. + /// + /// If the pointer at index I is non-NULL, then it refers to the + /// IdentifierInfo for the identifier with ID=I+1 that has already + /// been loaded. + std::vector<IdentifierInfo *> IdentifiersLoaded; + + /// \brief A pointer to an on-disk hash table of opaque type + /// PCHMethodPoolLookupTable. + /// + /// This hash table provides the instance and factory methods + /// associated with every selector known in the PCH file. + void *MethodPoolLookupTable; + + /// \brief A pointer to the character data that comprises the method + /// pool. + /// + /// The SelectorOffsets table refers into this memory. + const unsigned char *MethodPoolLookupTableData; + + /// \brief The number of selectors stored in the method pool itself. + unsigned TotalSelectorsInMethodPool; + + /// \brief Offsets into the method pool lookup table's data array + /// where each selector resides. + const uint32_t *SelectorOffsets; + + /// \brief The total number of selectors stored in the PCH file. + unsigned TotalNumSelectors; + + /// \brief A vector containing selectors that have already been loaded. + /// + /// This vector is indexed by the Selector ID (-1). NULL selector + /// entries indicate that the particular selector ID has not yet + /// been loaded. + llvm::SmallVector<Selector, 16> SelectorsLoaded; + + /// \brief The set of external definitions stored in the the PCH + /// file. + llvm::SmallVector<uint64_t, 16> ExternalDefinitions; + + /// \brief The set of tentative definitions stored in the the PCH + /// file. + llvm::SmallVector<uint64_t, 16> TentativeDefinitions; + + /// \brief The set of locally-scoped external declarations stored in + /// the the PCH file. + llvm::SmallVector<uint64_t, 16> LocallyScopedExternalDecls; + + /// \brief The set of ext_vector type declarations stored in the the + /// PCH file. + llvm::SmallVector<uint64_t, 4> ExtVectorDecls; + + /// \brief The set of Objective-C category definitions stored in the + /// the PCH file. + llvm::SmallVector<uint64_t, 4> ObjCCategoryImpls; + + /// \brief The original file name that was used to build the PCH + /// file. + std::string OriginalFileName; + + /// \brief Mapping from switch-case IDs in the PCH file to + /// switch-case statements. + std::map<unsigned, SwitchCase *> SwitchCaseStmts; + + /// \brief Mapping from label statement IDs in the PCH file to label + /// statements. + 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 The number of stat() calls that hit/missed the stat + /// cache. + unsigned NumStatHits, NumStatMisses; + + /// \brief The number of source location entries de-serialized from + /// the PCH file. + unsigned NumSLocEntriesRead; + + /// \brief The number of statements (and expressions) de-serialized + /// from the PCH file. + unsigned NumStatementsRead; + + /// \brief The total number of statements (and expressions) stored + /// in the PCH file. + unsigned TotalNumStatements; + + /// \brief The number of macros de-serialized from the PCH file. + unsigned NumMacrosRead; + + /// \brief The number of method pool entries that have been read. + unsigned NumMethodPoolSelectorsRead; + + /// \brief The number of times we have looked into the global method + /// pool and not found anything. + unsigned NumMethodPoolMisses; + + /// \brief The total number of macros stored in the PCH file. + unsigned TotalNumMacros; + + /// Number of lexical decl contexts read/total. + unsigned NumLexicalDeclContextsRead, TotalLexicalDeclContexts; + + /// Number of visible decl contexts read/total. + unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts; + + /// \brief FIXME: document! + llvm::SmallVector<uint64_t, 4> SpecialTypes; + + /// \brief Contains declarations and definitions that will be + /// "interesting" to the ASTConsumer, when we get that AST consumer. + /// + /// "Interesting" declarations are those that have data that may + /// need to be emitted, such as inline function definitions or + /// Objective-C protocols. + llvm::SmallVector<Decl *, 16> InterestingDecls; + + /// \brief The file ID for the predefines buffer in the PCH file. + FileID PCHPredefinesBufferID; + + /// \brief Pointer to the beginning of the predefines buffer in the + /// PCH file. + const char *PCHPredefines; + + /// \brief Length of the predefines buffer in the PCH file. + unsigned PCHPredefinesLen; + + /// \brief Suggested contents of the predefines buffer, after this + /// PCH file has been processed. + /// + /// In most cases, this string will be empty, because the predefines + /// buffer computed to build the PCH file will be identical to the + /// predefines buffer computed from the command line. However, when + /// there are differences that the PCH reader can work around, this + /// predefines buffer may contain additional definitions. + std::string SuggestedPredefines; + + PCHReadResult ReadPCHBlock(); + bool CheckPredefinesBuffer(const char *PCHPredef, + unsigned PCHPredefLen, + FileID PCHBufferID); + PCHReadResult ReadSourceManagerBlock(); + PCHReadResult ReadSLocEntryRecord(unsigned ID); + + bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record); + QualType ReadTypeRecord(uint64_t Offset); + void LoadedDecl(unsigned Index, Decl *D); + Decl *ReadDeclRecord(uint64_t Offset, unsigned Index); + + /// \brief Produce an error diagnostic and return true. + /// + /// This routine should only be used for fatal errors that have to + /// do with non-routine failures (e.g., corrupted PCH file). + bool Error(const char *Msg); + + PCHReader(const PCHReader&); // do not implement + PCHReader &operator=(const PCHReader &); // do not implement + +public: + typedef llvm::SmallVector<uint64_t, 64> RecordData; + + explicit PCHReader(Preprocessor &PP, ASTContext *Context); + ~PCHReader(); + + /// \brief Load the precompiled header designated by the given file + /// name. + PCHReadResult ReadPCH(const std::string &FileName); + + /// \brief Retrieve the name of the original source file name + const std::string &getOriginalSourceFile() { return OriginalFileName; } + + /// \brief Retrieve the name of the original source file name + /// directly from the PCH file, without actually loading the PCH + /// file. + static std::string getOriginalSourceFile(const std::string &PCHFileName); + + /// \brief Returns the suggested contents of the predefines buffer, + /// which contains a (typically-empty) subset of the predefines + /// build prior to including the precompiled header. + const std::string &getSuggestedPredefines() { return SuggestedPredefines; } + + /// \brief Resolve a type ID into a type, potentially building a new + /// type. + virtual QualType GetType(pch::TypeID ID); + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + virtual Decl *GetDecl(pch::DeclID ID); + + /// \brief Resolve the offset of a statement into a statement. + /// + /// This operation will read a new statement from the external + /// source each time it is called, and is meant to be used via a + /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). + virtual Stmt *GetDeclStmt(uint64_t Offset); + + /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the + /// specified cursor. Read the abbreviations that are at the top of the block + /// and then leave the cursor pointing into the block. + bool ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID); + + /// \brief Read all of the declarations lexically stored in a + /// declaration context. + /// + /// \param DC The declaration context whose declarations will be + /// read. + /// + /// \param Decls Vector that will contain the declarations loaded + /// from the external source. The caller is responsible for merging + /// these declarations with any declarations already stored in the + /// declaration context. + /// + /// \returns true if there was an error while reading the + /// declarations for this declaration context. + virtual bool ReadDeclsLexicallyInContext(DeclContext *DC, + llvm::SmallVectorImpl<pch::DeclID> &Decls); + + /// \brief Read all of the declarations visible from a declaration + /// context. + /// + /// \param DC The declaration context whose visible declarations + /// will be read. + /// + /// \param Decls A vector of visible declaration structures, + /// providing the mapping from each name visible in the declaration + /// context to the declaration IDs of declarations with that name. + /// + /// \returns true if there was an error while reading the + /// declarations for this declaration context. + /// + /// FIXME: Using this intermediate data structure results in an + /// extraneous copying of the data. Could we pass in a reference to + /// the StoredDeclsMap instead? + virtual bool ReadDeclsVisibleInContext(DeclContext *DC, + llvm::SmallVectorImpl<VisibleDeclaration> & Decls); + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + /// + /// This function will provide all of the external definitions to + /// the ASTConsumer. + virtual void StartTranslationUnit(ASTConsumer *Consumer); + + /// \brief Print some statistics about PCH usage. + virtual void PrintStats(); + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S); + + /// \brief Retrieve the IdentifierInfo for the named identifier. + /// + /// This routine builds a new IdentifierInfo for the given + /// identifier. If any declarations with this name are visible from + /// translation unit scope, their declarations will be deserialized + /// and introduced into the declaration chain of the + /// identifier. FIXME: if this identifier names a macro, deserialize + /// the macro. + virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd); + + /// \brief Load the contents of the global method pool for a given + /// selector. + /// + /// \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); + + void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(unsigned DiagID); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + + IdentifierInfo *DecodeIdentifierInfo(unsigned Idx); + + IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) { + return DecodeIdentifierInfo(Record[Idx++]); + } + + virtual IdentifierInfo *GetIdentifier(unsigned ID) { + return DecodeIdentifierInfo(ID); + } + + /// \brief Read the source location entry with index ID. + virtual void ReadSLocEntry(unsigned ID); + + Selector DecodeSelector(unsigned Idx); + + Selector GetSelector(const RecordData &Record, unsigned &Idx) { + return DecodeSelector(Record[Idx++]); + } + DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx); + + /// \brief Read an integral value + llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a signed integral value + llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a floating-point value + llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx); + + // \brief Read a string + std::string ReadString(const RecordData &Record, unsigned &Idx); + + /// \brief Reads attributes from the current stream position. + Attr *ReadAttributes(); + + /// \brief ReadDeclExpr - Reads an expression from the current decl cursor. + Expr *ReadDeclExpr(); + + /// \brief ReadTypeExpr - Reads an expression from the current type cursor. + Expr *ReadTypeExpr(); + + /// \brief Reads a statement from the specified cursor. + Stmt *ReadStmt(llvm::BitstreamCursor &Cursor); + + /// \brief Read a statement from the current DeclCursor. + Stmt *ReadDeclStmt() { + return ReadStmt(DeclsCursor); + } + + /// \brief Reads the macro record located at the given offset. + void ReadMacroRecord(uint64_t Offset); + + /// \brief Retrieve the AST context that this PCH reader + /// supplements. + ASTContext *getContext() { return Context; } + + // \brief Contains declarations that were loaded before we have + // access to a Sema object. + llvm::SmallVector<NamedDecl *, 16> PreloadedDecls; + + /// \brief Retrieve the semantic analysis object used to analyze the + /// translation unit in which the precompiled header is being + /// imported. + Sema *getSema() { return SemaObj; } + + /// \brief Retrieve the stream that this PCH reader is reading from. + llvm::BitstreamCursor &getStream() { return Stream; } + llvm::BitstreamCursor &getDeclsCursor() { return DeclsCursor; } + + /// \brief Retrieve the identifier table associated with the + /// preprocessor. + IdentifierTable &getIdentifierTable(); + + /// \brief Record that the given ID maps to the given switch-case + /// statement. + void RecordSwitchCaseID(SwitchCase *SC, unsigned ID); + + /// \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); +}; + +/// \brief Helper class that saves the current stream position and +/// then restores it when destroyed. +struct SavedStreamPosition { + explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) + : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } + + ~SavedStreamPosition() { + Cursor.JumpToBit(Offset); + } + +private: + llvm::BitstreamCursor &Cursor; + uint64_t Offset; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h new file mode 100644 index 000000000000..5cb939547f2c --- /dev/null +++ b/include/clang/Frontend/PCHWriter.h @@ -0,0 +1,278 @@ +//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- 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 PCHWriter class, which writes a precompiled +// header containing a serialized representation of a translation +// unit. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_PCH_WRITER_H +#define LLVM_CLANG_FRONTEND_PCH_WRITER_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Frontend/PCHBitCodes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include <map> +#include <queue> + +namespace llvm { + class APFloat; + class APInt; + class BitstreamWriter; +} + +namespace clang { + +class ASTContext; +class LabelStmt; +class MemorizeStatCalls; +class Preprocessor; +class Sema; +class SourceManager; +class SwitchCase; +class TargetInfo; + +/// \brief Writes a precompiled header containing the contents of a +/// translation unit. +/// +/// The PCHWriter class produces a bitstream containing the serialized +/// representation of a given abstract syntax tree and its supporting +/// data structures. This bitstream can be de-serialized via an +/// instance of the PCHReader class. +class PCHWriter { +public: + typedef llvm::SmallVector<uint64_t, 64> RecordData; + +private: + /// \brief The bitstream writer used to emit this precompiled header. + llvm::BitstreamWriter &Stream; + + /// \brief Map that provides the ID numbers of each declaration within + /// the output stream. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery) and start at 2. 1 is reserved for the translation + /// unit, while 0 is reserved for NULL. + llvm::DenseMap<const Decl *, pch::DeclID> DeclIDs; + + /// \brief Offset of each declaration in the bitstream, indexed by + /// the declaration's ID. + std::vector<uint32_t> DeclOffsets; + + /// \brief Queue containing the declarations that we still need to + /// emit. + std::queue<Decl *> DeclsToEmit; + + /// \brief Map that provides the ID numbers of each type within the + /// output stream. + /// + /// The ID numbers of types are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. When types are actually + /// stored in the stream, the ID number is shifted by 3 bits to + /// allow for the const/volatile/restrict qualifiers. + llvm::DenseMap<const Type *, pch::TypeID> TypeIDs; + + /// \brief Offset of each type in the bitstream, indexed by + /// the type's ID. + std::vector<uint32_t> TypeOffsets; + + /// \brief The type ID that will be assigned to the next new type. + pch::TypeID NextTypeID; + + /// \brief Queue containing the types that we still need to + /// emit. + std::queue<const Type *> TypesToEmit; + + /// \brief Map that provides the ID numbers of each identifier in + /// the output stream. + /// + /// The ID numbers for identifiers are consecutive (in order of + /// discovery), starting at 1. An ID of zero refers to a NULL + /// IdentifierInfo. + llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs; + + /// \brief Offsets of each of the identifier IDs into the identifier + /// table. + std::vector<uint32_t> IdentifierOffsets; + + /// \brief Map that provides the ID numbers of each Selector. + llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs; + + /// \brief Offset of each selector within the method pool/selector + /// table, indexed by the Selector ID (-1). + std::vector<uint32_t> SelectorOffsets; + + /// \brief A vector of all Selectors (ordered by ID). + std::vector<Selector> SelVector; + + /// \brief Offsets of each of the macro identifiers into the + /// bitstream. + /// + /// For each identifier that is associated with a macro, this map + /// provides the offset into the bitstream where that macro is + /// defined. + llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets; + + /// \brief Declarations encountered that might be external + /// definitions. + /// + /// We keep track of external definitions (as well as tentative + /// definitions) as we are emitting declarations to the PCH + /// file. The PCH file contains a separate record for these external + /// definitions, which are provided to the AST consumer by the PCH + /// reader. This is behavior is required to properly cope with, + /// e.g., tentative variable definitions that occur within + /// headers. The declarations themselves are stored as declaration + /// IDs, since they will be written out to an EXTERNAL_DEFINITIONS + /// record. + llvm::SmallVector<uint64_t, 16> ExternalDefinitions; + + /// \brief Statements that we've encountered while serializing a + /// declaration or type. + llvm::SmallVector<Stmt *, 8> StmtsToEmit; + + /// \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 The number of statements written to the PCH file. + unsigned NumStatements; + + /// \brief The number of macros written to the PCH file. + unsigned NumMacros; + + /// \brief The number of lexical declcontexts written to the PCH + /// file. + unsigned NumLexicalDeclContexts; + + /// \brief The number of visible declcontexts written to the PCH + /// file. + unsigned NumVisibleDeclContexts; + + void WriteBlockInfoBlock(); + void WriteMetadata(ASTContext &Context); + void WriteLanguageOptions(const LangOptions &LangOpts); + void WriteStatCache(MemorizeStatCalls &StatCalls); + void WriteSourceManagerBlock(SourceManager &SourceMgr, + const Preprocessor &PP); + void WritePreprocessor(const Preprocessor &PP); + void WriteType(const Type *T); + void WriteTypesBlock(ASTContext &Context); + uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); + uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); + + void WriteDeclsBlock(ASTContext &Context); + void WriteMethodPool(Sema &SemaRef); + void WriteIdentifierTable(Preprocessor &PP); + void WriteAttributeRecord(const Attr *Attr); + + unsigned ParmVarDeclAbbrev; + void WriteDeclsBlockAbbrevs(); + +public: + /// \brief Create a new precompiled header writer that outputs to + /// the given bitstream. + PCHWriter(llvm::BitstreamWriter &Stream); + + /// \brief Write a precompiled header for the given semantic analysis. + void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls); + + /// \brief Emit a source location. + void AddSourceLocation(SourceLocation Loc, RecordData &Record); + + /// \brief Emit an integral value. + void AddAPInt(const llvm::APInt &Value, RecordData &Record); + + /// \brief Emit a signed integral value. + void AddAPSInt(const llvm::APSInt &Value, RecordData &Record); + + /// \brief Emit a floating-point value. + void AddAPFloat(const llvm::APFloat &Value, RecordData &Record); + + /// \brief Emit a reference to an identifier + void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record); + + /// \brief Emit a Selector (which is a smart pointer reference) + void AddSelectorRef(const Selector, RecordData &Record); + + /// \brief Get the unique number used to refer to the given + /// identifier. + pch::IdentID getIdentifierRef(const IdentifierInfo *II); + + /// \brief Retrieve the offset of the macro definition for the given + /// identifier. + /// + /// The identifier must refer to a macro. + uint64_t getMacroOffset(const IdentifierInfo *II) { + assert(MacroOffsets.find(II) != MacroOffsets.end() && + "Identifier does not name a macro"); + return MacroOffsets[II]; + } + + /// \brief Emit a reference to a type. + void AddTypeRef(QualType T, RecordData &Record); + + /// \brief Emit a reference to a declaration. + void AddDeclRef(const Decl *D, RecordData &Record); + + /// \brief Determine the declaration ID of an already-emitted + /// declaration. + pch::DeclID getDeclID(const Decl *D); + + /// \brief Emit a declaration name. + void AddDeclarationName(DeclarationName Name, RecordData &Record); + + /// \brief Add a string to the given record. + void AddString(const std::string &Str, RecordData &Record); + + /// \brief Note that the identifier II occurs at the given offset + /// within the identifier table. + void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset); + + /// \brief Note that the selector Sel occurs at the given offset + /// within the method pool/selector table. + void SetSelectorOffset(Selector Sel, uint32_t Offset); + + /// \brief Add the given statement or expression to the queue of + /// statements to emit. + /// + /// This routine should be used when emitting types and declarations + /// that have expressions as part of their formulation. Once the + /// type or declaration has been written, call FlushStmts() to write + /// the corresponding statements just after the type or + /// declaration. + void AddStmt(Stmt *S) { StmtsToEmit.push_back(S); } + + /// \brief Write the given subexpression to the bitstream. + void WriteSubStmt(Stmt *S); + + /// \brief Flush all of the statements and expressions that have + /// been added to the queue via AddStmt(). + void FlushStmts(); + + /// \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); + + unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h new file mode 100644 index 000000000000..028cd8549272 --- /dev/null +++ b/include/clang/Frontend/PathDiagnosticClients.h @@ -0,0 +1,34 @@ +//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- 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 create different path diagostic clients. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H +#define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H + +#include <string> + +namespace clang { + +class PathDiagnosticClient; +class Preprocessor; +class PreprocessorFactory; + +PathDiagnosticClient* CreateHTMLDiagnosticClient(const std::string& prefix, + Preprocessor* PP = 0, + PreprocessorFactory* PPF = 0); + +PathDiagnosticClient* CreatePlistDiagnosticClient(const std::string& prefix, + Preprocessor* PP, + PreprocessorFactory* PPF); +} + +#endif diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h new file mode 100644 index 000000000000..4e907e1965ea --- /dev/null +++ b/include/clang/Frontend/TextDiagnosticBuffer.h @@ -0,0 +1,48 @@ +//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_ +#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_ + +#include "clang/Basic/Diagnostic.h" +#include <vector> + +namespace clang { + +class Preprocessor; +class SourceManager; + +class TextDiagnosticBuffer : public DiagnosticClient { +public: + typedef std::vector<std::pair<SourceLocation, std::string> > DiagList; + typedef DiagList::iterator iterator; + typedef DiagList::const_iterator const_iterator; +private: + DiagList Errors, Warnings, Notes; +public: + const_iterator err_begin() const { return Errors.begin(); } + const_iterator err_end() const { return Errors.end(); } + + const_iterator warn_begin() const { return Warnings.begin(); } + const_iterator warn_end() const { return Warnings.end(); } + + const_iterator note_begin() const { return Notes.begin(); } + const_iterator note_end() const { return Notes.end(); } + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); +}; + +} // end namspace clang + +#endif diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h new file mode 100644 index 000000000000..3c9dcb8d9c17 --- /dev/null +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -0,0 +1,85 @@ +//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which prints the diagnostics to +// standard error. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_ +#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_ + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { +class SourceManager; +class LangOptions; + +class TextDiagnosticPrinter : public DiagnosticClient { + llvm::raw_ostream &OS; + const LangOptions *LangOpts; + SourceLocation LastWarningLoc; + FullSourceLoc LastLoc; + bool LastCaretDiagnosticWasNote; + + bool ShowColumn; + bool CaretDiagnostics; + bool ShowLocation; + bool PrintRangeInfo; + bool PrintDiagnosticOption; + bool PrintFixItInfo; + unsigned MessageLength; + +public: + TextDiagnosticPrinter(llvm::raw_ostream &os, + bool showColumn = true, + bool caretDiagnistics = true, bool showLocation = true, + bool printRangeInfo = true, + bool printDiagnosticOption = true, + bool printFixItInfo = true, + unsigned messageLength = 0) + : OS(os), LangOpts(0), + LastCaretDiagnosticWasNote(false), ShowColumn(showColumn), + CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation), + PrintRangeInfo(printRangeInfo), + PrintDiagnosticOption(printDiagnosticOption), + PrintFixItInfo(printFixItInfo), + MessageLength(messageLength) {} + + void setLangOptions(const LangOptions *LO) { + LangOpts = LO; + } + + void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM); + + void HighlightRange(const SourceRange &R, + const SourceManager &SrcMgr, + unsigned LineNo, FileID FID, + std::string &CaretLine, + const std::string &SourceLine); + + void EmitCaretDiagnostic(SourceLocation Loc, + SourceRange *Ranges, unsigned NumRanges, + SourceManager &SM, + const CodeModificationHint *Hints, + unsigned NumHints, + unsigned Columns); + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); +}; + +} // end namspace clang + +#endif diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h new file mode 100644 index 000000000000..41eb31a0fc35 --- /dev/null +++ b/include/clang/Frontend/Utils.h @@ -0,0 +1,79 @@ +//===--- Utils.h - Misc utilities for the front-end------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_UTILS_H +#define LLVM_CLANG_FRONTEND_UTILS_H + +#include <vector> +#include <string> + +namespace llvm { +class raw_ostream; +class raw_fd_ostream; +} + +namespace clang { +class Preprocessor; +class MinimalAction; +class TargetInfo; +class Diagnostic; +class ASTConsumer; +class IdentifierTable; +class SourceManager; +class PreprocessorFactory; +class LangOptions; + +/// ProcessWarningOptions - Initialize the diagnostic client and process the +/// warning options specified on the command line. +bool ProcessWarningOptions(Diagnostic &Diags, + std::vector<std::string> &Warnings, + bool Pedantic, bool PedanticErrors, + bool NoWarnings); + +/// DoPrintPreprocessedInput - Implement -E -dM mode. +void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream* OS); + +/// DoPrintPreprocessedInput - Implement -E mode. +void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS, + bool EnableCommentOutput, + bool EnableMacroCommentOutput, + bool DisableLineMarkers, + bool DumpDefines); + +/// RewriteMacrosInInput - Implement -rewrite-macros mode. +void RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream* OS); + +/// RewriteMacrosInInput - A simple test for the TokenRewriter class. +void DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS); + +/// CreatePrintParserActionsAction - Return the actions implementation that +/// implements the -parse-print-callbacks option. +MinimalAction *CreatePrintParserActionsAction(Preprocessor &PP, + llvm::raw_ostream* OS); + +/// CheckDiagnostics - Gather the expected diagnostics and check them. +bool CheckDiagnostics(Preprocessor &PP); + +/// AttachDependencyFileGen - Create a dependency file generator, and attach +/// it to the given preprocessor. This takes ownership of the output stream. +void AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS, + std::vector<std::string> &Targets, + bool IncludeSystemHeaders, bool PhonyTarget); + +/// CacheTokens - Cache tokens for use with PCH. Note that this requires +/// a seekable stream. +void CacheTokens(Preprocessor& PP, llvm::raw_fd_ostream* OS); + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h new file mode 100644 index 000000000000..618de39233db --- /dev/null +++ b/include/clang/Lex/DirectoryLookup.h @@ -0,0 +1,133 @@ +//===--- DirectoryLookup.h - Info for searching for headers -----*- 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 DirectoryLookup interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H +#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H + +#include "clang/Basic/SourceManager.h" + +namespace clang { +class HeaderMap; +class DirectoryEntry; +class FileEntry; +class HeaderSearch; + +/// DirectoryLookup - This class represents one entry in the search list that +/// specifies the search order for directories in #include directives. It +/// represents either a directory, a framework, or a headermap. +/// +class DirectoryLookup { +public: + enum LookupType_t { + LT_NormalDir, + LT_Framework, + LT_HeaderMap + }; +private: + union { // This union is discriminated by isHeaderMap. + /// Dir - This is the actual directory that we're referring to for a normal + /// directory or a framework. + const DirectoryEntry *Dir; + + /// Map - This is the HeaderMap if this is a headermap lookup. + /// + const HeaderMap *Map; + } u; + + /// DirCharacteristic - The type of directory this is: this is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirCharacteristic : 2; + + /// UserSupplied - True if this is a user-supplied directory. + /// + bool UserSupplied : 1; + + /// LookupType - This indicates whether this DirectoryLookup object is a + /// normal directory, a framework, or a headermap. + unsigned LookupType : 2; +public: + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'dir'. + DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT, + bool isUser, bool isFramework) + : DirCharacteristic(DT), UserSupplied(isUser), + LookupType(isFramework ? LT_Framework : LT_NormalDir) { + u.Dir = dir; + } + + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'map'. + DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT, + bool isUser) + : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap) { + u.Map = map; + } + + /// getLookupType - Return the kind of directory lookup that this is: either a + /// normal directory, a framework path, or a HeaderMap. + LookupType_t getLookupType() const { return (LookupType_t)LookupType; } + + /// getName - Return the directory or filename corresponding to this lookup + /// object. + const char *getName() const; + + /// getDir - Return the directory that this entry refers to. + /// + const DirectoryEntry *getDir() const { return isNormalDir() ? u.Dir : 0; } + + /// getFrameworkDir - Return the directory that this framework refers to. + /// + const DirectoryEntry *getFrameworkDir() const { + return isFramework() ? u.Dir : 0; + } + + /// getHeaderMap - Return the directory that this entry refers to. + /// + const HeaderMap *getHeaderMap() const { return isHeaderMap() ? u.Map : 0; } + + /// isNormalDir - Return true if this is a normal directory, not a header map. + bool isNormalDir() const { return getLookupType() == LT_NormalDir; } + + /// isFramework - True if this is a framework directory. + /// + bool isFramework() const { return getLookupType() == LT_Framework; } + + /// isHeaderMap - Return true if this is a header map, not a normal directory. + bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; } + + /// DirCharacteristic - The type of directory this is, one of the DirType enum + /// values. + SrcMgr::CharacteristicKind getDirCharacteristic() const { + return (SrcMgr::CharacteristicKind)DirCharacteristic; + } + + /// isUserSupplied - True if this is a user-supplied directory. + /// + bool isUserSupplied() const { return UserSupplied; } + + + /// LookupFile - Lookup the specified file in this search path, returning it + /// if it exists or returning null if not. + const FileEntry *LookupFile(const char *FilenameStart, + const char *FilenameEnd, HeaderSearch &HS) const; + +private: + const FileEntry *DoFrameworkLookup(const char *FilenameStart, + const char *FilenameEnd, + HeaderSearch &HS) const; + +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h new file mode 100644 index 000000000000..d8033093bd8e --- /dev/null +++ b/include/clang/Lex/HeaderMap.h @@ -0,0 +1,67 @@ +//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- 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 HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAP_H +#define LLVM_CLANG_LEX_HEADERMAP_H + +namespace llvm { + class MemoryBuffer; +} +namespace clang { + class FileEntry; + class FileManager; + struct HMapBucket; + struct HMapHeader; + +/// This class represents an Apple concept known as a 'header map'. To the +/// #include file resolution process, it basically acts like a directory of +/// symlinks to files. Its advantages are that it is dense and more efficient +/// to create and process than a directory of symlinks. +class HeaderMap { + HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT + void operator=(const HeaderMap&); // DO NOT IMPLEMENT + + const llvm::MemoryBuffer *FileBuffer; + bool NeedsBSwap; + + HeaderMap(const llvm::MemoryBuffer *File, bool BSwap) + : FileBuffer(File), NeedsBSwap(BSwap) { + } +public: + ~HeaderMap(); + + /// HeaderMap::Create - This attempts to load the specified file as a header + /// map. If it doesn't look like a HeaderMap, it gives up and returns null. + static const HeaderMap *Create(const FileEntry *FE); + + /// LookupFile - Check to see if the specified relative filename is located in + /// this HeaderMap. If so, open it and return its FileEntry. + const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd, + FileManager &FM) const; + + /// getFileName - Return the filename of the headermap. + const char *getFileName() const; + + /// dump - Print the contents of this headermap to stderr. + void dump() const; + +private: + unsigned getEndianAdjustedWord(unsigned X) const; + const HMapHeader &getHeader() const; + HMapBucket getBucket(unsigned BucketNo) const; + const char *getString(unsigned StrTabIdx) const; +}; + +} // end namespace clang. + +#endif diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h new file mode 100644 index 000000000000..f21aab1b4015 --- /dev/null +++ b/include/clang/Lex/HeaderSearch.h @@ -0,0 +1,237 @@ +//===--- HeaderSearch.h - Resolve Header File Locations ---------*- 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 HeaderSearch interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H +#define LLVM_CLANG_LEX_HEADERSEARCH_H + +#include "clang/Lex/DirectoryLookup.h" +#include "llvm/ADT/StringMap.h" +#include <vector> + +namespace clang { + +class ExternalIdentifierLookup; +class FileEntry; +class FileManager; +class IdentifierInfo; + +/// HeaderFileInfo - The preprocessor keeps track of this information for each +/// file that is #included. +struct HeaderFileInfo { + /// isImport - True if this is a #import'd or #pragma once file. + bool isImport : 1; + + /// DirInfo - Keep track of whether this is a system header, and if so, + /// whether it is C++ clean or not. This can be set by the include paths or + /// by #pragma gcc system_header. This is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirInfo : 2; + + /// NumIncludes - This is the number of times the file has been included + /// already. + unsigned short NumIncludes; + + /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard + /// that protects the entire contents of the file, this is the identifier + /// for the macro that controls whether or not it has any effect. + /// + /// Note: Most clients should use getControllingMacro() to access + /// the controlling macro of this header, since + /// getControllingMacro() is able to load a controlling macro from + /// 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) {} + + /// \brief Retrieve the controlling macro for this header file, if + /// any. + const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External); +}; + +/// 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 + /// directory in SearchDirs, starting at SystemDirIdx, consequtively. If + /// NoCurDirSearch is true, then the check for the file in the current + /// directory is supressed. + std::vector<DirectoryLookup> SearchDirs; + unsigned SystemDirIdx; + bool NoCurDirSearch; + + /// FileInfo - This contains all of the preprocessor-specific data about files + /// that are included. The vector is indexed by the FileEntry's UID. + /// + std::vector<HeaderFileInfo> FileInfo; + + /// LookupFileCache - This is keeps track of each lookup performed by + /// LookupFile. The first part of the value is the starting index in + /// SearchDirs that the cached search was performed from. If there is a hit + /// and this value doesn't match the current query, the cache has to be + /// ignored. The second value is the entry in SearchDirs that satisfied the + /// query. + llvm::StringMap<std::pair<unsigned, unsigned> > LookupFileCache; + + + /// FrameworkMap - This is a collection mapping a framework or subframework + /// name like "Carbon" to the Carbon.framework directory. + llvm::StringMap<const DirectoryEntry *> FrameworkMap; + + /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing + /// headermaps. This vector owns the headermap. + std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; + + /// \brief Entity used to resolve the identifier IDs of controlling + /// macros into IdentifierInfo pointers, as needed. + ExternalIdentifierLookup *ExternalLookup; + + // Various statistics we track for performance analysis. + unsigned NumIncluded; + unsigned NumMultiIncludeFileOptzn; + unsigned NumFrameworkLookups, NumSubFrameworkLookups; + + // HeaderSearch doesn't support default or copy construction. + explicit HeaderSearch(); + explicit HeaderSearch(const HeaderSearch&); + void operator=(const HeaderSearch&); +public: + HeaderSearch(FileManager &FM); + ~HeaderSearch(); + + FileManager &getFileMgr() const { return FileMgr; } + + /// SetSearchPaths - Interface for setting the file search paths. + /// + void SetSearchPaths(const std::vector<DirectoryLookup> &dirs, + unsigned systemDirIdx, bool noCurDirSearch) { + SearchDirs = dirs; + SystemDirIdx = systemDirIdx; + NoCurDirSearch = noCurDirSearch; + //LookupFileCache.clear(); + } + + /// ClearFileInfo - Forget everything we know about headers so far. + void ClearFileInfo() { + FileInfo.clear(); + } + + void SetExternalLookup(ExternalIdentifierLookup *EIL) { + ExternalLookup = EIL; + } + + /// 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 + /// DirectoryLookup member the file was found in, or null if not applicable. + /// If CurDir is non-null, the file was found in the specified directory + /// search location. This is used to implement #include_next. CurFileEnt, if + /// non-null, indicates where the #including file is, in case a relative + /// search is needed. + const FileEntry *LookupFile(const char *FilenameStart, + const char *FilenameEnd, bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + const FileEntry *CurFileEnt); + + /// LookupSubframeworkHeader - Look up a subframework for the specified + /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from + /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox + /// is a subframework within Carbon.framework. If so, return the FileEntry + /// for the designated file, otherwise return null. + const FileEntry *LookupSubframeworkHeader(const char *FilenameStart, + const char *FilenameEnd, + const FileEntry *RelativeFileEnt); + + /// LookupFrameworkCache - Look up the specified framework name in our + /// framework cache, returning the DirectoryEntry it is in if we know, + /// otherwise, return null. + const DirectoryEntry *&LookupFrameworkCache(const char *FWNameStart, + const char *FWNameEnd) { + return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue(); + } + + /// ShouldEnterIncludeFile - Mark the specified file as a target of of a + /// #include, #include_next, or #import directive. Return false if #including + /// the file will have no effect or true if we should include it. + bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport); + + + /// getFileDirFlavor - Return whether the specified file is a normal header, + /// a system header, or a C++ friendly system header. + SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) { + return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; + } + + /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g. + /// due to #pragma once. + void MarkFileIncludeOnce(const FileEntry *File) { + getFileInfo(File).isImport = true; + } + + /// MarkFileSystemHeader - Mark the specified file as a system header, e.g. + /// due to #pragma GCC system_header. + void MarkFileSystemHeader(const FileEntry *File) { + getFileInfo(File).DirInfo = SrcMgr::C_System; + } + + /// IncrementIncludeCount - Increment the count for the number of times the + /// specified FileEntry has been entered. + void IncrementIncludeCount(const FileEntry *File) { + ++getFileInfo(File).NumIncludes; + } + + /// SetFileControllingMacro - Mark the specified file as having a controlling + /// macro. This is used by the multiple-include optimization to eliminate + /// no-op #includes. + void SetFileControllingMacro(const FileEntry *File, + const IdentifierInfo *ControllingMacro) { + getFileInfo(File).ControllingMacro = ControllingMacro; + } + + /// CreateHeaderMap - This method returns a HeaderMap for the specified + /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. + const HeaderMap *CreateHeaderMap(const FileEntry *FE); + + void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } + + typedef std::vector<HeaderFileInfo>::iterator header_file_iterator; + header_file_iterator header_file_begin() { return FileInfo.begin(); } + header_file_iterator header_file_end() { return FileInfo.end(); } + + // Used by PCHReader. + void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID); + + void PrintStats(); +private: + + /// getFileInfo - Return the HeaderFileInfo structure for the specified + /// FileEntry. + HeaderFileInfo &getFileInfo(const FileEntry *FE); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h new file mode 100644 index 000000000000..1502efb55e63 --- /dev/null +++ b/include/clang/Lex/LexDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticLex.h - Diagnostics for liblex ---------------*- 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_DIAGNOSTICLEX_H +#define LLVM_CLANG_DIAGNOSTICLEX_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define LEXSTART +#include "clang/Basic/DiagnosticLexKinds.inc" +#undef DIAG + NUM_BUILTIN_LEX_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h new file mode 100644 index 000000000000..3a73147152af --- /dev/null +++ b/include/clang/Lex/Lexer.h @@ -0,0 +1,376 @@ +//===--- Lexer.h - C Language Family Lexer ----------------------*- 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 Lexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEXER_H +#define LLVM_CLANG_LEXER_H + +#include "clang/Lex/PreprocessorLexer.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallVector.h" +#include <string> +#include <vector> +#include <cassert> + +namespace clang { +class Diagnostic; +class SourceManager; +class Preprocessor; +class DiagnosticBuilder; + +/// Lexer - This provides a simple interface that turns a text buffer into a +/// stream of tokens. This provides no support for file reading or buffering, +/// or buffering/seeking of tokens, only forward lexing is supported. It relies +/// on the specified Preprocessor object to handle preprocessor directives, etc. +class Lexer : public PreprocessorLexer { + //===--------------------------------------------------------------------===// + // Constant configuration values for this lexer. + const char *BufferStart; // Start of the buffer. + const char *BufferEnd; // End of the buffer. + SourceLocation FileLoc; // Location for start of file. + LangOptions Features; // Features enabled by this language (cache). + bool Is_PragmaLexer; // True if lexer for _Pragma handling. + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + // + + /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace + /// and return them as tokens. This is used for -C and -CC modes, and + /// whitespace preservation can be useful for some clients that want to lex + /// the file in raw mode and get every character from the file. + /// + /// When this is set to 2 it returns comments and whitespace. When set to 1 + /// it returns comments, when it is set to 0 it returns normal tokens only. + unsigned char ExtendedTokenMode; + + //===--------------------------------------------------------------------===// + // Context that changes as the file is lexed. + // NOTE: any state that mutates when in raw mode must have save/restore code + // in Lexer::isNextPPTokenLParen. + + // BufferPtr - Current pointer into the buffer. This is the next character + // to be lexed. + const char *BufferPtr; + + // IsAtStartOfLine - True if the next lexed token should get the "start of + // line" flag set on it. + bool IsAtStartOfLine; + + Lexer(const Lexer&); // DO NOT IMPLEMENT + void operator=(const Lexer&); // DO NOT IMPLEMENT + friend class Preprocessor; + + void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); +public: + + /// Lexer constructor - Create a new lexer object for the specified buffer + /// with the specified preprocessor managing the lexing process. This lexer + /// assumes that the associated file buffer and Preprocessor objects will + /// outlive it, so it doesn't take ownership of either of them. + Lexer(FileID FID, Preprocessor &PP); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexRawToken'. This lexer assumes that the text + /// range will outlive it, so it doesn't take ownership of it. + Lexer(SourceLocation FileLoc, const LangOptions &Features, + const char *BufStart, const char *BufPtr, const char *BufEnd); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexRawToken'. This lexer assumes that the text + /// range will outlive it, so it doesn't take ownership of it. + Lexer(FileID FID, const SourceManager &SM, const LangOptions &Features); + + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for + /// _Pragma expansion. This has a variety of magic semantics that this method + /// sets up. It returns a new'd Lexer that must be delete'd when done. + static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, + SourceLocation InstantiationLocStart, + SourceLocation InstantiationLocEnd, + unsigned TokLen, Preprocessor &PP); + + + /// getFeatures - Return the language features currently enabled. NOTE: this + /// lexer modifies features as a file is parsed! + const LangOptions &getFeatures() const { return Features; } + + /// getFileLoc - Return the File Location for the file we are lexing out of. + /// The physical location encodes the location where the characters come from, + /// the virtual location encodes where we should *claim* the characters came + /// from. Currently this is only used by _Pragma handling. + SourceLocation getFileLoc() const { return FileLoc; } + + /// Lex - Return the next token in the file. If this is the end of file, it + /// return the tok::eof token. Return true if an error occurred and + /// compilation should terminate, false if normal. This implicitly involves + /// the preprocessor. + void Lex(Token &Result) { + // Start a new token. + Result.startToken(); + + // NOTE, any changes here should also change code after calls to + // Preprocessor::HandleDirective + if (IsAtStartOfLine) { + Result.setFlag(Token::StartOfLine); + IsAtStartOfLine = false; + } + + // Get a token. Note that this may delete the current lexer if the end of + // file is reached. + LexTokenInternal(Result); + } + + /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma. + bool isPragmaLexer() const { return Is_PragmaLexer; } + + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) { Lex(Result); } + + /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no + /// associated preprocessor object. Return true if the 'next character to + /// read' pointer points at the end of the lexer buffer, false otherwise. + bool LexFromRawLexer(Token &Result) { + assert(LexingRawMode && "Not already in raw mode!"); + Lex(Result); + // Note that lexing to the end of the buffer doesn't implicitly delete the + // lexer when in raw mode. + return BufferPtr == BufferEnd; + } + + /// isKeepWhitespaceMode - Return true if the lexer should return tokens for + /// every character in the file, including whitespace and comments. This + /// should only be used in raw mode, as the preprocessor is not prepared to + /// deal with the excess tokens. + bool isKeepWhitespaceMode() const { + return ExtendedTokenMode > 1; + } + + /// SetKeepWhitespaceMode - This method lets clients enable or disable + /// whitespace retention mode. + void SetKeepWhitespaceMode(bool Val) { + assert((!Val || LexingRawMode) && + "Can only enable whitespace retention in raw mode"); + ExtendedTokenMode = Val ? 2 : 0; + } + + /// inKeepCommentMode - Return true if the lexer should return comments as + /// tokens. + bool inKeepCommentMode() const { + return ExtendedTokenMode > 0; + } + + /// SetCommentRetentionMode - Change the comment retention mode of the lexer + /// to the specified mode. This is really only useful when lexing in raw + /// mode, because otherwise the lexer needs to manage this. + void SetCommentRetentionState(bool Mode) { + assert(!isKeepWhitespaceMode() && + "Can't play with comment retention state when retaining whitespace"); + ExtendedTokenMode = Mode ? 1 : 0; + } + + const char *getBufferStart() const { return BufferStart; } + + /// ReadToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + std::string ReadToEndOfLine(); + + + /// Diag - Forwarding function for diagnostics. This translate a source + /// position in the current buffer into a SourceLocation object for rendering. + DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const; + + /// getSourceLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const; + + /// getSourceLocation - Return a source location for the next character in + /// the current file. + SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); } + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + /// If Charify is true, this escapes the ' character instead of ". + static std::string Stringify(const std::string &Str, bool Charify = false); + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + static void Stringify(llvm::SmallVectorImpl<char> &Str); + + /// MeasureTokenLength - Relex the token at the specified location and return + /// its length in bytes in the input file. If the token needs cleaning (e.g. + /// includes a trigraph or an escaped newline) then this count includes bytes + /// that are part of that. + static unsigned MeasureTokenLength(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + //===--------------------------------------------------------------------===// + // Internal implementation interfaces. +private: + + /// LexTokenInternal - Internal interface to lex a preprocessing token. Called + /// by Lex. + /// + void LexTokenInternal(Token &Result); + + /// FormTokenWithChars - When we lex a token, we have identified a span + /// starting at BufferPtr, going to TokEnd that forms the token. This method + /// takes that range and assigns it to the token as its location and size. In + /// addition, since tokens cannot overlap, this also updates BufferPtr to be + /// TokEnd. + void FormTokenWithChars(Token &Result, const char *TokEnd, + tok::TokenKind Kind) { + unsigned TokLen = TokEnd-BufferPtr; + Result.setLength(TokLen); + Result.setLocation(getSourceLocation(BufferPtr, TokLen)); + Result.setKind(Kind); + BufferPtr = TokEnd; + } + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens in the buffer controlled by this lexer. + unsigned isNextPPTokenLParen(); + + //===--------------------------------------------------------------------===// + // Lexer character reading interfaces. +public: + + // This lexer is built on two interfaces for reading characters, both of which + // automatically provide phase 1/2 translation. getAndAdvanceChar is used + // when we know that we will be reading a character from the input buffer and + // that this character will be part of the result token. This occurs in (f.e.) + // string processing, because we know we need to read until we find the + // closing '"' character. + // + // The second interface is the combination of PeekCharAndSize with + // ConsumeChar. PeekCharAndSize reads a phase 1/2 translated character, + // returning it and its size. If the lexer decides that this character is + // part of the current token, it calls ConsumeChar on it. This two stage + // approach allows us to emit diagnostics for characters (e.g. warnings about + // trigraphs), knowing that they only are emitted if the character is + // consumed. + + /// isObviouslySimpleCharacter - Return true if the specified character is + /// obviously the same in translation phase 1 and translation phase 3. This + /// can return false for characters that end up being the same, but it will + /// never return true for something that needs to be mapped. + static bool isObviouslySimpleCharacter(char C) { + return C != '?' && C != '\\'; + } + + /// getAndAdvanceChar - Read a single 'character' from the specified buffer, + /// advance over it, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++; + + unsigned Size = 0; + char C = getCharAndSizeSlow(Ptr, Size, &Tok); + Ptr += Size; + return C; + } + +private: + /// ConsumeChar - When a character (identified by PeekCharAndSize) is consumed + /// and added to a given token, check to see if there are diagnostics that + /// need to be emitted or flags that need to be set on the token. If so, do + /// it. + const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) { + // Normal case, we consumed exactly one token. Just return it. + if (Size == 1) + return Ptr+Size; + + // Otherwise, re-lex the character with a current token, allowing + // diagnostics to be emitted and flags to be set. + Size = 0; + getCharAndSizeSlow(Ptr, Size, &Tok); + return Ptr+Size; + } + + /// getCharAndSize - Peek a single 'character' from the specified buffer, + /// get its size, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getCharAndSize(const char *Ptr, unsigned &Size) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlow(Ptr, Size); + } + + /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize + /// method. + char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0); +public: + + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever + /// emit a warning. + static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &Features) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlowNoWarn(Ptr, Size, Features); + } + + /// getEscapedNewLineSize - Return the size of the specified escaped newline, + /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry + /// to this function. + static unsigned getEscapedNewLineSize(const char *P); + + /// SkipEscapedNewLines - If P points to an escaped newline (or a series of + /// them), skip over them and return the first non-escaped-newline found, + /// otherwise return P. + static const char *SkipEscapedNewLines(const char *P); +private: + + /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a + /// diagnostic. + static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &Features); + + //===--------------------------------------------------------------------===// + // Other lexer functions. + + // Helper functions to lex the remainder of a token of the specific type. + void LexIdentifier (Token &Result, const char *CurPtr); + void LexNumericConstant (Token &Result, const char *CurPtr); + void LexStringLiteral (Token &Result, const char *CurPtr,bool Wide); + void LexAngledStringLiteral(Token &Result, const char *CurPtr); + void LexCharConstant (Token &Result, const char *CurPtr); + bool LexEndOfFile (Token &Result, const char *CurPtr); + + bool SkipWhitespace (Token &Result, const char *CurPtr); + bool SkipBCPLComment (Token &Result, const char *CurPtr); + bool SkipBlockComment (Token &Result, const char *CurPtr); + bool SaveBCPLComment (Token &Result, const char *CurPtr); +}; + + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h new file mode 100644 index 000000000000..8ee8ecf7359f --- /dev/null +++ b/include/clang/Lex/LiteralSupport.h @@ -0,0 +1,176 @@ +//===--- LiteralSupport.h ---------------------------------------*- 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 NumericLiteralParser, CharLiteralParser, and +// StringLiteralParser interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LITERALSUPPORT_H +#define CLANG_LITERALSUPPORT_H + +#include <string> +#include "llvm/ADT/SmallString.h" + +namespace llvm { + class APInt; + class APFloat; + struct fltSemantics; +} + +namespace clang { + +class Diagnostic; +class Preprocessor; +class Token; +class SourceLocation; +class TargetInfo; + +/// NumericLiteralParser - This performs strict semantic analysis of the content +/// of a ppnumber, classifying it as either integer, floating, or erroneous, +/// determines the radix of the value and can convert it to a useful value. +class NumericLiteralParser { + Preprocessor &PP; // needed for diagnostics + + const char *const ThisTokBegin; + const char *const ThisTokEnd; + const char *DigitsBegin, *SuffixBegin; // markers + const char *s; // cursor + + unsigned radix; + + bool saw_exponent, saw_period; + +public: + NumericLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP); + bool hadError; + bool isUnsigned; + bool isLong; // This is *not* set for long long. + bool isLongLong; + bool isFloat; // 1.0f + bool isImaginary; // 1.0i + + bool isIntegerLiteral() const { + return !saw_period && !saw_exponent; + } + bool isFloatingLiteral() const { + return saw_period || saw_exponent; + } + bool hasSuffix() const { + return SuffixBegin != ThisTokEnd; + } + + unsigned getRadix() const { return radix; } + + /// GetIntegerValue - Convert this numeric literal value to an APInt that + /// matches Val's input width. If there is an overflow (i.e., if the unsigned + /// value read is larger than the APInt's bits will hold), set Val to the low + /// bits of the result and return true. Otherwise, return false. + bool GetIntegerValue(llvm::APInt &Val); + + /// GetFloatValue - Convert this numeric literal to a floating value, using + /// the specified APFloat fltSemantics (specifying float, double, etc). + /// The optional bool isExact (passed-by-reference) has its value + /// set to true if the returned APFloat can represent the number in the + /// literal exactly, and false otherwise. + llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format, + bool* isExact = NULL); + +private: + + void ParseNumberStartingWithZero(SourceLocation TokLoc); + + /// SkipHexDigits - Read and skip over any hex digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipHexDigits(const char *ptr) { + while (ptr != ThisTokEnd && isxdigit(*ptr)) + ptr++; + return ptr; + } + + /// SkipOctalDigits - Read and skip over any octal digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipOctalDigits(const char *ptr) { + while (ptr != ThisTokEnd && ((*ptr >= '0') && (*ptr <= '7'))) + ptr++; + return ptr; + } + + /// SkipDigits - Read and skip over any digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipDigits(const char *ptr) { + while (ptr != ThisTokEnd && isdigit(*ptr)) + ptr++; + return ptr; + } + + /// SkipBinaryDigits - Read and skip over any binary digits, up to End. + /// Return a pointer to the first non-binary digit or End. + const char *SkipBinaryDigits(const char *ptr) { + while (ptr != ThisTokEnd && (*ptr == '0' || *ptr == '1')) + ptr++; + return ptr; + } + +}; + +/// CharLiteralParser - Perform interpretation and semantic analysis of a +/// character literal. +class CharLiteralParser { + uint64_t Value; + bool IsWide; + bool IsMultiChar; + bool HadError; +public: + CharLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP); + + bool hadError() const { return HadError; } + bool isWide() const { return IsWide; } + bool isMultiChar() const { return IsMultiChar; } + uint64_t getValue() const { return Value; } +}; + +/// StringLiteralParser - This decodes string escape characters and performs +/// wide string analysis and Translation Phase #6 (concatenation of string +/// literals) (C99 5.1.1.2p1). +class StringLiteralParser { + Preprocessor &PP; + + unsigned MaxTokenLength; + unsigned SizeBound; + unsigned wchar_tByteWidth; + llvm::SmallString<512> ResultBuf; + char *ResultPtr; // cursor +public: + StringLiteralParser(const Token *StringToks, unsigned NumStringToks, + Preprocessor &PP); + bool hadError; + bool AnyWide; + bool Pascal; + + const char *GetString() { return &ResultBuf[0]; } + unsigned GetStringLength() const { return ResultPtr-&ResultBuf[0]; } + + unsigned GetNumStringChars() const { + if (AnyWide) + return GetStringLength() / wchar_tByteWidth; + return GetStringLength(); + } + /// getOffsetOfStringByte - This function returns the offset of the + /// specified byte of the string data represented by Token. This handles + /// advancing over escape sequences in the string. + static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo, + Preprocessor &PP); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h new file mode 100644 index 000000000000..ccd13c80d354 --- /dev/null +++ b/include/clang/Lex/MacroInfo.h @@ -0,0 +1,218 @@ +//===--- MacroInfo.h - Information about #defined identifiers ---*- 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 MacroInfo interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_MACROINFO_H +#define LLVM_CLANG_MACROINFO_H + +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <vector> +#include <cassert> + +namespace clang { + class Preprocessor; + +/// MacroInfo - Each identifier that is #define'd has an instance of this class +/// associated with it, used to implement macro expansion. +class MacroInfo { + //===--------------------------------------------------------------------===// + // State set when the macro is defined. + + /// Location - This is the place the macro is defined. + SourceLocation Location; + /// EndLocation - The location of the last token in the macro. + SourceLocation EndLocation; + + /// Arguments - The list of arguments for a function-like macro. This can be + /// empty, for, e.g. "#define X()". In a C99-style variadic macro, this + /// includes the __VA_ARGS__ identifier on the list. + IdentifierInfo **ArgumentList; + unsigned NumArguments; + + /// ReplacementTokens - This is the list of tokens that the macro is defined + /// to. + llvm::SmallVector<Token, 8> ReplacementTokens; + + /// IsFunctionLike - True if this macro is a function-like macro, false if it + /// is an object-like macro. + bool IsFunctionLike : 1; + + /// IsC99Varargs - True if this macro is of the form "#define X(...)" or + /// "#define X(Y,Z,...)". The __VA_ARGS__ token should be replaced with the + /// contents of "..." in an invocation. + bool IsC99Varargs : 1; + + /// IsGNUVarargs - True if this macro is of the form "#define X(a...)". The + /// "a" identifier in the replacement list will be replaced with all arguments + /// of the macro starting with the specified one. + bool IsGNUVarargs : 1; + + /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if + /// it has not yet been redefined or undefined. + bool IsBuiltinMacro : 1; + +private: + //===--------------------------------------------------------------------===// + // State that changes as the macro is used. + + /// IsDisabled - True if we have started an expansion of this macro already. + /// This disbles recursive expansion, which would be quite bad for things like + /// #define A A. + bool IsDisabled : 1; + + /// IsUsed - True if this macro is either defined in the main file and has + /// been used, or if it is not defined in the main file. This is used to + /// emit -Wunused-macros diagnostics. + bool IsUsed : 1; + + ~MacroInfo() { + assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); + } + +public: + MacroInfo(SourceLocation DefLoc); + + /// FreeArgumentList - Free the argument list of the macro, restoring it to a + /// state where it can be reused for other devious purposes. + void FreeArgumentList(llvm::BumpPtrAllocator &PPAllocator) { + PPAllocator.Deallocate(ArgumentList); + ArgumentList = 0; + NumArguments = 0; + } + + /// Destroy - destroy this MacroInfo object. + void Destroy(llvm::BumpPtrAllocator &PPAllocator) { + FreeArgumentList(PPAllocator); + this->~MacroInfo(); + } + + /// getDefinitionLoc - Return the location that the macro was defined at. + /// + SourceLocation getDefinitionLoc() const { return Location; } + + /// setDefinitionEndLoc - Set the location of the last token in the macro. + /// + void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; } + /// getDefinitionEndLoc - Return the location of the last token in the macro. + /// + SourceLocation getDefinitionEndLoc() const { return EndLocation; } + + /// isIdenticalTo - Return true if the specified macro definition is equal to + /// this macro in spelling, arguments, and whitespace. This is used to emit + /// duplicate definition warnings. This implements the rules in C99 6.10.3. + bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const; + + /// setIsBuiltinMacro - Set or clear the isBuiltinMacro flag. + /// + void setIsBuiltinMacro(bool Val = true) { + IsBuiltinMacro = Val; + } + + /// setIsUsed - Set the value of the IsUsed flag. + /// + void setIsUsed(bool Val) { + IsUsed = Val; + } + + /// setArgumentList - Set the specified list of identifiers as the argument + /// list for this macro. + void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs, + llvm::BumpPtrAllocator &PPAllocator) { + assert(ArgumentList == 0 && NumArguments == 0 && + "Argument list already set!"); + if (NumArgs == 0) return; + + NumArguments = NumArgs; + ArgumentList = PPAllocator.Allocate<IdentifierInfo*>(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ArgumentList[i] = List[i]; + } + + /// Arguments - The list of arguments for a function-like macro. This can be + /// empty, for, e.g. "#define X()". + typedef IdentifierInfo* const *arg_iterator; + bool arg_empty() const { return NumArguments == 0; } + arg_iterator arg_begin() const { return ArgumentList; } + arg_iterator arg_end() const { return ArgumentList+NumArguments; } + unsigned getNumArgs() const { return NumArguments; } + + /// getArgumentNum - Return the argument number of the specified identifier, + /// or -1 if the identifier is not a formal argument identifier. + int getArgumentNum(IdentifierInfo *Arg) const { + for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I) + if (*I == Arg) return I-arg_begin(); + return -1; + } + + /// Function/Object-likeness. Keep track of whether this macro has formal + /// parameters. + void setIsFunctionLike() { IsFunctionLike = true; } + bool isFunctionLike() const { return IsFunctionLike; } + bool isObjectLike() const { return !IsFunctionLike; } + + /// Varargs querying methods. This can only be set for function-like macros. + void setIsC99Varargs() { IsC99Varargs = true; } + void setIsGNUVarargs() { IsGNUVarargs = true; } + bool isC99Varargs() const { return IsC99Varargs; } + bool isGNUVarargs() const { return IsGNUVarargs; } + bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; } + + /// isBuiltinMacro - Return true if this macro is a builtin macro, such as + /// __LINE__, which requires processing before expansion. + bool isBuiltinMacro() const { return IsBuiltinMacro; } + + /// isUsed - Return false if this macro is defined in the main file and has + /// not yet been used. + bool isUsed() const { return IsUsed; } + + /// getNumTokens - Return the number of tokens that this macro expands to. + /// + unsigned getNumTokens() const { + return ReplacementTokens.size(); + } + + const Token &getReplacementToken(unsigned Tok) const { + assert(Tok < ReplacementTokens.size() && "Invalid token #"); + return ReplacementTokens[Tok]; + } + + typedef llvm::SmallVector<Token, 8>::const_iterator tokens_iterator; + tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); } + tokens_iterator tokens_end() const { return ReplacementTokens.end(); } + bool tokens_empty() const { return ReplacementTokens.empty(); } + + /// AddTokenToBody - Add the specified token to the replacement text for the + /// macro. + void AddTokenToBody(const Token &Tok) { + ReplacementTokens.push_back(Tok); + } + + /// isEnabled - Return true if this macro is enabled: in other words, that we + /// are not currently in an expansion of this macro. + bool isEnabled() const { return !IsDisabled; } + + void EnableMacro() { + assert(IsDisabled && "Cannot enable an already-enabled macro!"); + IsDisabled = false; + } + + void DisableMacro() { + assert(!IsDisabled && "Cannot disable an already-disabled macro!"); + IsDisabled = true; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h new file mode 100644 index 000000000000..94d4677f9d29 --- /dev/null +++ b/include/clang/Lex/MultipleIncludeOpt.h @@ -0,0 +1,130 @@ +//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- 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 MultipleIncludeOpt interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H +#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H + +namespace clang { +class IdentifierInfo; + +/// MultipleIncludeOpt - This class implements the simple state machine that the +/// Lexer class uses to detect files subject to the 'multiple-include' +/// optimization. The public methods in this class are triggered by various +/// events that occur when a file is lexed, and after the entire file is lexed, +/// information about which macro (if any) controls the header is returned. +class MultipleIncludeOpt { + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool ReadAnyTokens; + + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool DidMacroExpansion; + + /// TheMacro - The controlling macro for a file, if valid. + /// + const IdentifierInfo *TheMacro; +public: + MultipleIncludeOpt() { + ReadAnyTokens = false; + DidMacroExpansion = false; + TheMacro = 0; + } + + /// Invalidate - Permenantly mark this file as not being suitable for the + /// include-file optimization. + void Invalidate() { + // If we have read tokens but have no controlling macro, the state-machine + // below can never "accept". + ReadAnyTokens = true; + TheMacro = 0; + } + + /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the + /// top of the file when reading preprocessor directives. Otherwise, reading + /// the "ifndef x" would count as reading tokens. + bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } + + // If a token is read, remember that we have seen a side-effect in this file. + void ReadToken() { ReadAnyTokens = true; } + + /// ExpandedMacro - When a macro is expanded with this lexer as the current + /// buffer, this method is called to disable the MIOpt if needed. + void ExpandedMacro() { DidMacroExpansion = true; } + + /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the + /// "#if !defined" equivalent) without any preceding tokens, this method is + /// called. + /// + /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller + /// ensures that this is only called if there are no tokens read before the + /// #ifndef. The caller is required to do this, because reading the #if line + /// obviously reads in in tokens. + void EnterTopLevelIFNDEF(const IdentifierInfo *M) { + // If the macro is already set, this is after the top-level #endif. + if (TheMacro) + return Invalidate(); + + // If we have already expanded a macro by the end of the #ifndef line, then + // there is a macro expansion *in* the #ifndef line. This means that the + // condition could evaluate differently when subsequently #included. Reject + // this. + if (DidMacroExpansion) + return Invalidate(); + + // Remember that we're in the #if and that we have the macro. + ReadAnyTokens = true; + TheMacro = M; + } + + /// EnterTopLevelConditional - This is invoked when a top level conditional + /// (except #ifndef) is found. + void EnterTopLevelConditional() { + /// If a conditional directive (except #ifndef) is found at the top level, + /// there is a chunk of the file not guarded by the controlling macro. + Invalidate(); + } + + /// ExitTopLevelConditional - This method is called when the lexer exits the + /// top-level conditional. + void ExitTopLevelConditional() { + // If we have a macro, that means the top of the file was ok. Set our state + // back to "not having read any tokens" so we can detect anything after the + // #endif. + if (!TheMacro) return Invalidate(); + + // At this point, we haven't "read any tokens" but we do have a controlling + // macro. + ReadAnyTokens = false; + } + + /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if + /// there is a controlling macro, return it. + const IdentifierInfo *GetControllingMacroAtEndOfFile() const { + // If we haven't read any tokens after the #endif, return the controlling + // macro if it's valid (if it isn't, it will be null). + if (!ReadAnyTokens) + return TheMacro; + return 0; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h new file mode 100644 index 000000000000..e5cbeebd22aa --- /dev/null +++ b/include/clang/Lex/PPCallbacks.h @@ -0,0 +1,122 @@ +//===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- 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 PPCallbacks interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H +#define LLVM_CLANG_LEX_PPCALLBACKS_H + +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Basic/SourceLocation.h" +#include <string> + +namespace clang { + class SourceLocation; + class Token; + class IdentifierInfo; + class MacroInfo; + +/// PPCallbacks - This interface provides a way to observe the actions of the +/// preprocessor as it does its thing. Clients can define their hooks here to +/// implement preprocessor level tools. +class PPCallbacks { +public: + virtual ~PPCallbacks(); + + enum FileChangeReason { + EnterFile, ExitFile, SystemHeaderPragma, RenameFile + }; + + /// FileChanged - This callback is invoked whenever a source file is + /// entered or exited. The SourceLocation indicates the new location, and + /// EnteringFile indicates whether this is because we are entering a new + /// #include'd file (when true) or whether we're exiting one because we ran + /// off the end (when false). + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType) { + } + + /// Ident - This callback is invoked when a #ident or #sccs directive is read. + /// + virtual void Ident(SourceLocation Loc, const std::string &str) { + } + + /// PragmaComment - This callback is invoked when a #pragma comment directive + /// is read. + /// + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str) { + } + + /// MacroExpands - This is called by + /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is + /// found. + virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { + } + + /// MacroDefined - This hook is called whenever a macro definition is seen. + virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { + } + + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + /// MI is released immediately following this callback. + virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI) { + } +}; + +/// PPChainedCallbacks - Simple wrapper class for chaining callbacks. +class PPChainedCallbacks : public PPCallbacks { + PPCallbacks *First, *Second; + +public: + PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second) + : First(_First), Second(_Second) {} + ~PPChainedCallbacks() { + delete Second; + delete First; + } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType) { + First->FileChanged(Loc, Reason, FileType); + Second->FileChanged(Loc, Reason, FileType); + } + + virtual void Ident(SourceLocation Loc, const std::string &str) { + First->Ident(Loc, str); + Second->Ident(Loc, str); + } + + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str) { + First->PragmaComment(Loc, Kind, Str); + Second->PragmaComment(Loc, Kind, Str); + } + + virtual void MacroExpands(const Token &Id, const MacroInfo* MI) { + First->MacroExpands(Id, MI); + Second->MacroExpands(Id, MI); + } + + virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) { + First->MacroDefined(II, MI); + Second->MacroDefined(II, MI); + } + + virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI) { + First->MacroUndefined(II, MI); + Second->MacroUndefined(II, MI); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h new file mode 100644 index 000000000000..369b818a1fc9 --- /dev/null +++ b/include/clang/Lex/PTHLexer.h @@ -0,0 +1,104 @@ +//===--- PTHLexer.h - Lexer based on Pre-tokenized input --------*- 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 PTHLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PTHLEXER_H +#define LLVM_CLANG_PTHLEXER_H + +#include "clang/Lex/PreprocessorLexer.h" +#include <vector> + +namespace clang { + +class PTHManager; +class PTHSpellingSearch; + +class PTHLexer : public PreprocessorLexer { + SourceLocation FileStartLoc; + + /// TokBuf - Buffer from PTH file containing raw token data. + const unsigned char* TokBuf; + + /// CurPtr - Pointer into current offset of the token buffer where + /// the next token will be read. + const unsigned char* CurPtr; + + /// LastHashTokPtr - Pointer into TokBuf of the last processed '#' + /// token that appears at the start of a line. + const unsigned char* LastHashTokPtr; + + /// PPCond - Pointer to a side table in the PTH file that provides a + /// a consise summary of the preproccessor conditional block structure. + /// This is used to perform quick skipping of conditional blocks. + const unsigned char* PPCond; + + /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry + /// to process when doing quick skipping of preprocessor blocks. + const unsigned char* CurPPCondPtr; + + PTHLexer(const PTHLexer&); // DO NOT IMPLEMENT + void operator=(const PTHLexer&); // DO NOT IMPLEMENT + + /// ReadToken - Used by PTHLexer to read tokens TokBuf. + void ReadToken(Token& T); + + /// PTHMgr - The PTHManager object that created this PTHLexer. + PTHManager& PTHMgr; + + Token EofToken; + +protected: + friend class PTHManager; + + /// Create a PTHLexer for the specified token stream. + PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D, + const unsigned char* ppcond, PTHManager &PM); +public: + + ~PTHLexer() {} + + /// Lex - Return the next token. + void Lex(Token &Tok); + + void getEOF(Token &Tok); + + /// DiscardToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + void DiscardToEndOfLine(); + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens controlled by this lexer. + unsigned isNextPPTokenLParen() { + // isNextPPTokenLParen is not on the hot path, and all we care about is + // whether or not we are at a token with kind tok::eof or tok::l_paren. + // Just read the first byte from the current token pointer to determine + // its kind. + tok::TokenKind x = (tok::TokenKind)*CurPtr; + return x == tok::eof ? 2 : x == tok::l_paren; + } + + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) { Lex(Result); } + + /// getSourceLocation - Return a source location for the token in + /// the current file. + SourceLocation getSourceLocation(); + + /// SkipBlock - Used by Preprocessor to skip the current conditional block. + bool SkipBlock(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h new file mode 100644 index 000000000000..507576473f60 --- /dev/null +++ b/include/clang/Lex/PTHManager.h @@ -0,0 +1,141 @@ +//===--- PTHManager.h - Manager object for PTH processing -------*- 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 PTHManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PTHMANAGER_H +#define LLVM_CLANG_PTHMANAGER_H + +#include "clang/Lex/PTHLexer.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" +#include <string> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class FileEntry; +class PTHLexer; +class Diagnostic; +class StatSysCallCache; + +class PTHManager : public IdentifierInfoLookup { + friend class PTHLexer; + + /// The memory mapped PTH file. + const llvm::MemoryBuffer* Buf; + + /// Alloc - Allocator used for IdentifierInfo objects. + llvm::BumpPtrAllocator Alloc; + + /// IdMap - A lazily generated cache mapping from persistent identifiers to + /// IdentifierInfo*. + IdentifierInfo** PerIDCache; + + /// FileLookup - Abstract data structure used for mapping between files + /// and token data in the PTH file. + void* FileLookup; + + /// IdDataTable - Array representing the mapping from persistent IDs to the + /// data offset within the PTH file containing the information to + /// reconsitute an IdentifierInfo. + const unsigned char* const IdDataTable; + + /// SortedIdTable - Abstract data structure mapping from strings to + /// persistent IDs. This is used by get(). + void* StringIdLookup; + + /// NumIds - The number of identifiers in the PTH file. + const unsigned NumIds; + + /// PP - The Preprocessor object that will use this PTHManager to create + /// PTHLexer objects. + Preprocessor* PP; + + /// SpellingBase - The base offset within the PTH memory buffer that + /// contains the cached spellings for literals. + const unsigned char* const SpellingBase; + + /// OriginalSourceFile - A null-terminated C-string that specifies the name + /// if the file (if any) that was to used to generate the PTH cache. + const char* OriginalSourceFile; + + /// This constructor is intended to only be called by the static 'Create' + /// method. + PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup, + const unsigned char* idDataTable, IdentifierInfo** perIDCache, + void* stringIdLookup, unsigned numIds, + const unsigned char* spellingBase, const char *originalSourceFile); + + // Do not implement. + PTHManager(); + void operator=(const PTHManager&); + + /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached + /// spelling for a token. + unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer); + + /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the + /// PTH file. + inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) { + // Check if the IdentifierInfo has already been resolved. + if (IdentifierInfo* II = PerIDCache[PersistentID]) + return II; + return LazilyCreateIdentifierInfo(PersistentID); + } + IdentifierInfo* LazilyCreateIdentifierInfo(unsigned PersistentID); + +public: + // The current PTH version. + enum { Version = 9 }; + + ~PTHManager(); + + /// getOriginalSourceFile - Return the full path to the original header + /// file name that was used to generate the PTH cache. + const char* getOriginalSourceFile() const { + return OriginalSourceFile; + } + + /// get - Return the identifier token info for the specified named identifier. + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// be found. + IdentifierInfo *get(const char *NameStart, const char *NameEnd); + + /// Create - This method creates PTHManager objects. The 'file' argument + /// is the name of the PTH file. This method returns NULL upon failure. + static PTHManager *Create(const std::string& file, Diagnostic* Diags = 0, + Diagnostic::Level failureLevel=Diagnostic::Warning); + + void setPreprocessor(Preprocessor *pp) { PP = pp; } + + /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the + /// specified file. This method returns NULL if no cached tokens exist. + /// It is the responsibility of the caller to 'delete' the returned object. + PTHLexer *CreateLexer(FileID FID); + + /// createStatCache - Returns a StatSysCallCache object for use with + /// FileManager objects. These objects use the PTH data to speed up + /// calls to stat by memoizing their results from when the PTH file + /// was generated. + StatSysCallCache *createStatCache(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h new file mode 100644 index 000000000000..136dc6fabfb6 --- /dev/null +++ b/include/clang/Lex/Pragma.h @@ -0,0 +1,90 @@ +//===--- Pragma.h - Pragma registration and 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 PragmaHandler and PragmaTable interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PRAGMA_H +#define LLVM_CLANG_PRAGMA_H + +#include <cassert> +#include <vector> + +namespace clang { + class Preprocessor; + class Token; + class IdentifierInfo; + class PragmaNamespace; + +/// 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 +/// that identifier is found. If a handler does not match any of the declared +/// pragmas the handler with a null identifier is invoked, if it exists. +/// +/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g. +/// we treat "#pragma STDC" and "#pragma GCC" as namespaces that contain other +/// pragmas. +class PragmaHandler { + const IdentifierInfo *Name; +public: + PragmaHandler(const IdentifierInfo *name) : Name(name) {} + virtual ~PragmaHandler(); + + const IdentifierInfo *getName() const { return Name; } + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken) = 0; + + /// getIfNamespace - If this is a namespace, return it. This is equivalent to + /// using a dynamic_cast, but doesn't require RTTI. + virtual PragmaNamespace *getIfNamespace() { return 0; } +}; + +/// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas, +/// allowing hierarchical pragmas to be defined. Common examples of namespaces +/// are "#pragma GCC", "#pragma STDC", and "#pragma omp", but any namespaces may +/// be (potentially recursively) defined. +class PragmaNamespace : public PragmaHandler { + /// Handlers - This is the list of handlers in this namespace. + /// + std::vector<PragmaHandler*> Handlers; +public: + PragmaNamespace(const IdentifierInfo *Name) : PragmaHandler(Name) {} + virtual ~PragmaNamespace(); + + /// FindHandler - Check to see if there is already a handler for the + /// specified name. If not, return the handler for the null identifier if it + /// exists, otherwise return null. If IgnoreNull is true (the default) then + /// the null handler isn't returned on failure to match. + PragmaHandler *FindHandler(const IdentifierInfo *Name, + bool IgnoreNull = true) const; + + /// AddPragma - Add a pragma to this namespace. + /// + void AddPragma(PragmaHandler *Handler) { + Handlers.push_back(Handler); + } + + /// RemovePragmaHandler - Remove the given handler from the + /// namespace. + void RemovePragmaHandler(PragmaHandler *Handler); + + bool IsEmpty() { + return Handlers.empty(); + } + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + + virtual PragmaNamespace *getIfNamespace() { return this; } +}; + + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h new file mode 100644 index 000000000000..5b9959c32a2d --- /dev/null +++ b/include/clang/Lex/Preprocessor.h @@ -0,0 +1,801 @@ +//===--- Preprocessor.h - C Language Family Preprocessor --------*- 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 Preprocessor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H +#define LLVM_CLANG_LEX_PREPROCESSOR_H + +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PTHLexer.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/TokenLexer.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +class SourceManager; +class FileManager; +class FileEntry; +class HeaderSearch; +class PragmaNamespace; +class PragmaHandler; +class ScratchBuffer; +class TargetInfo; +class PPCallbacks; +class DirectoryLookup; + +/// Preprocessor - This object engages in a tight little dance with the lexer to +/// efficiently preprocess tokens. Lexers know only about tokens within a +/// single source file, and don't know anything about preprocessor-level issues +/// like the #include stack, token expansion, etc. +/// +class Preprocessor { + Diagnostic *Diags; + const LangOptions &Features; + TargetInfo &Target; + FileManager &FileMgr; + SourceManager &SourceMgr; + ScratchBuffer *ScratchBuf; + HeaderSearch &HeaderInfo; + + /// PTH - An optional PTHManager object used for getting tokens from + /// a token cache rather than lexing the original source file. + llvm::OwningPtr<PTHManager> PTH; + + /// BP - A BumpPtrAllocator object used to quickly allocate and release + /// objects internal to the Preprocessor. + llvm::BumpPtrAllocator BP; + + /// Identifiers for builtin macros and other builtins. + IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ + IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ + IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__ + IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__ + IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__ + IdentifierInfo *Ident__COUNTER__; // __COUNTER__ + IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__ + + SourceLocation DATELoc, TIMELoc; + unsigned CounterValue; // Next __COUNTER__ value. + + enum { + /// MaxIncludeStackDepth - Maximum depth of #includes. + MaxAllowedIncludeStackDepth = 200 + }; + + // State that is set before the preprocessor begins. + bool KeepComments : 1; + bool KeepMacroComments : 1; + + // State that changes while the preprocessor runs: + bool DisableMacroExpansion : 1; // True if macro expansion is disabled. + bool InMacroArgs : 1; // True if parsing fn macro invocation args. + + /// Identifiers - This is mapping/lookup information for all identifiers in + /// the program, including program keywords. + IdentifierTable Identifiers; + + /// Selectors - This table contains all the selectors in the program. Unlike + /// IdentifierTable above, this table *isn't* populated by the preprocessor. + /// It is declared/instantiated here because it's role/lifetime is + /// conceptually similar the IdentifierTable. In addition, the current control + /// flow (in clang::ParseAST()), make it convenient to put here. + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime fo the preprocessor. + SelectorTable Selectors; + + /// PragmaHandlers - This tracks all of the pragmas that the client registered + /// with this preprocessor. + PragmaNamespace *PragmaHandlers; + + /// CurLexer - This is the current top of the stack that we're lexing from if + /// not expanding a macro and we are lexing directly from source code. + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + llvm::OwningPtr<Lexer> CurLexer; + + /// CurPTHLexer - This is the current top of stack that we're lexing from if + /// not expanding from a macro and we are lexing from a PTH cache. + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + llvm::OwningPtr<PTHLexer> CurPTHLexer; + + /// CurPPLexer - This is the current top of the stack what we're lexing from + /// if not expanding a macro. This is an alias for either CurLexer or + /// CurPTHLexer. + PreprocessorLexer* CurPPLexer; + + /// CurLookup - The DirectoryLookup structure used to find the current + /// FileEntry, if CurLexer is non-null and if applicable. This allows us to + /// implement #include_next and find directory-specific properties. + const DirectoryLookup *CurDirLookup; + + /// CurTokenLexer - This is the current macro we are expanding, if we are + /// expanding a macro. One of CurLexer and CurTokenLexer must be null. + llvm::OwningPtr<TokenLexer> CurTokenLexer; + + /// IncludeMacroStack - This keeps track of the stack of files currently + /// #included, and macros currently being expanded from, not counting + /// CurLexer/CurTokenLexer. + struct IncludeStackInfo { + Lexer *TheLexer; + PTHLexer *ThePTHLexer; + PreprocessorLexer *ThePPLexer; + TokenLexer *TheTokenLexer; + const DirectoryLookup *TheDirLookup; + + IncludeStackInfo(Lexer *L, PTHLexer* P, PreprocessorLexer* PPL, + TokenLexer* TL, const DirectoryLookup *D) + : TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL), TheTokenLexer(TL), + TheDirLookup(D) {} + }; + std::vector<IncludeStackInfo> IncludeMacroStack; + + /// Callbacks - These are actions invoked when some preprocessor activity is + /// encountered (e.g. a file is #included, etc). + PPCallbacks *Callbacks; + + /// Macros - For each IdentifierInfo with 'HasMacro' set, we keep a mapping + /// to the actual definition of the macro. + llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros; + + /// MICache - A "freelist" of MacroInfo objects that can be reused for quick + /// allocation. + std::vector<MacroInfo*> MICache; + + // Various statistics we track for performance analysis. + unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma; + unsigned NumIf, NumElse, NumEndif; + unsigned NumEnteredSourceFiles, MaxIncludeStackDepth; + unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; + unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; + unsigned NumSkipped; + + /// Predefines - This string is the predefined macros that preprocessor + /// should use from the command line etc. + std::string Predefines; + + /// TokenLexerCache - Cache macro expanders to reduce malloc traffic. + enum { TokenLexerCacheSize = 8 }; + unsigned NumCachedTokenLexers; + TokenLexer *TokenLexerCache[TokenLexerCacheSize]; + +private: // Cached tokens state. + typedef std::vector<Token> CachedTokensTy; + + /// CachedTokens - Cached tokens are stored here when we do backtracking or + /// lookahead. They are "lexed" by the CachingLex() method. + CachedTokensTy CachedTokens; + + /// CachedLexPos - The position of the cached token that CachingLex() should + /// "lex" next. If it points beyond the CachedTokens vector, it means that + /// a normal Lex() should be invoked. + CachedTokensTy::size_type CachedLexPos; + + /// BacktrackPositions - Stack of backtrack positions, allowing nested + /// backtracks. The EnableBacktrackAtThisPos() method pushes a position to + /// indicate where CachedLexPos should be set when the BackTrack() method is + /// invoked (at which point the last position is popped). + std::vector<CachedTokensTy::size_type> BacktrackPositions; + +public: + Preprocessor(Diagnostic &diags, const LangOptions &opts, TargetInfo &target, + SourceManager &SM, HeaderSearch &Headers, + IdentifierInfoLookup* IILookup = 0); + + ~Preprocessor(); + + Diagnostic &getDiagnostics() const { return *Diags; } + void setDiagnostics(Diagnostic &D) { Diags = &D; } + + + const LangOptions &getLangOptions() const { return Features; } + TargetInfo &getTargetInfo() const { return Target; } + FileManager &getFileManager() const { return FileMgr; } + SourceManager &getSourceManager() const { return SourceMgr; } + HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } + + IdentifierTable &getIdentifierTable() { return Identifiers; } + SelectorTable &getSelectorTable() { return Selectors; } + llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } + + void setPTHManager(PTHManager* pm); + + PTHManager *getPTHManager() { return PTH.get(); } + + /// SetCommentRetentionState - Control whether or not the preprocessor retains + /// comments in output. + void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { + this->KeepComments = KeepComments | KeepMacroComments; + this->KeepMacroComments = KeepMacroComments; + } + + bool getCommentRetentionState() const { return KeepComments; } + + /// isCurrentLexer - Return true if we are lexing directly from the specified + /// lexer. + bool isCurrentLexer(const PreprocessorLexer *L) const { + return CurPPLexer == L; + } + + /// getCurrentLexer - Return the current file lexer being lexed from. Note + /// that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentFileLexer() const; + + /// getPPCallbacks/setPPCallbacks - Accessors for preprocessor callbacks. + /// Note that this class takes ownership of any PPCallbacks object given to + /// it. + PPCallbacks *getPPCallbacks() const { return Callbacks; } + void setPPCallbacks(PPCallbacks *C) { + if (Callbacks) + C = new PPChainedCallbacks(C, Callbacks); + Callbacks = C; + } + + /// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to + /// or null if it isn't #define'd. + MacroInfo *getMacroInfo(IdentifierInfo *II) const { + return II->hasMacroDefinition() ? Macros.find(II)->second : 0; + } + + /// setMacroInfo - Specify a macro for this identifier. + /// + void setMacroInfo(IdentifierInfo *II, MacroInfo *MI); + + /// macro_iterator/macro_begin/macro_end - This allows you to walk the current + /// state of the macro table. This visits every currently-defined macro. + typedef llvm::DenseMap<IdentifierInfo*, + MacroInfo*>::const_iterator macro_iterator; + macro_iterator macro_begin() const { return Macros.begin(); } + macro_iterator macro_end() const { return Macros.end(); } + + + + const std::string &getPredefines() const { return Predefines; } + /// setPredefines - Set the predefines for this Preprocessor. These + /// predefines are automatically injected when parsing the main file. + void setPredefines(const char *P) { Predefines = P; } + void setPredefines(const std::string &P) { Predefines = P; } + + /// getIdentifierInfo - Return information about the specified preprocessor + /// identifier token. The version of this method that takes two character + /// pointers is preferred unless the identifier is already available as a + /// string (this avoids allocation and copying of memory to construct an + /// std::string). + IdentifierInfo *getIdentifierInfo(const char *NameStart, + const char *NameEnd) { + return &Identifiers.get(NameStart, NameEnd); + } + IdentifierInfo *getIdentifierInfo(const char *NameStr) { + return getIdentifierInfo(NameStr, NameStr+strlen(NameStr)); + } + + /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. + /// If 'Namespace' is non-null, then it is a token required to exist on the + /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". + void AddPragmaHandler(const char *Namespace, PragmaHandler *Handler); + + /// RemovePragmaHandler - Remove the specific pragma handler from + /// the preprocessor. If \arg Namespace is non-null, then it should + /// be the namespace that \arg Handler was added to. It is an error + /// to remove a handler that has not been registered. + void RemovePragmaHandler(const char *Namespace, PragmaHandler *Handler); + + /// EnterMainSourceFile - Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void EnterMainSourceFile(); + + /// EnterSourceFile - Add a source file to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. If isMainFile + /// is true, this is the main file for the translation unit. + void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); + + /// EnterMacro - Add a Macro to the top of the include stack and start lexing + /// tokens from it instead of the current buffer. Args specifies the + /// tokens input to a function-like macro. + /// + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args); + + /// EnterTokenStream - Add a "macro" context to the top of the include stack, + /// which will cause the lexer to start returning the specified tokens. + /// + /// If DisableMacroExpansion is true, tokens lexed from the token stream will + /// not be subject to further macro expansion. Otherwise, these tokens will + /// be re-macro-expanded when/if expansion is enabled. + /// + /// If OwnsTokens is false, this method assumes that the specified stream of + /// tokens has a permanent owner somewhere, so they do not need to be copied. + /// If it is true, it assumes the array of tokens is allocated with new[] and + /// must be freed. + /// + void EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the + /// lexer stack. This should only be used in situations where the current + /// state of the top-of-stack lexer is known. + void RemoveTopOfLexerStack(); + + /// EnableBacktrackAtThisPos - From the point that this method is called, and + /// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor + /// keeps track of the lexed tokens so that a subsequent Backtrack() call will + /// make the Preprocessor re-lex the same tokens. + /// + /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can + /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will + /// be combined with the EnableBacktrackAtThisPos calls in reverse order. + /// + /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack + /// at some point after EnableBacktrackAtThisPos. If you don't, caching of + /// tokens will continue indefinitely. + /// + void EnableBacktrackAtThisPos(); + + /// CommitBacktrackedTokens - Disable the last EnableBacktrackAtThisPos call. + void CommitBacktrackedTokens(); + + /// Backtrack - Make Preprocessor re-lex the tokens that were lexed since + /// EnableBacktrackAtThisPos() was previously called. + void Backtrack(); + + /// isBacktrackEnabled - True if EnableBacktrackAtThisPos() was called and + /// caching of tokens is on. + bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + + /// Lex - To lex a token from the preprocessor, just pull a token from the + /// current lexer or macro object. + void Lex(Token &Result) { + if (CurLexer) + CurLexer->Lex(Result); + else if (CurPTHLexer) + CurPTHLexer->Lex(Result); + else if (CurTokenLexer) + CurTokenLexer->Lex(Result); + else + CachingLex(Result); + } + + /// LexNonComment - Lex a token. If it's a comment, keep lexing until we get + /// something not a comment. This is useful in -E -C mode where comments + /// would foul up preprocessor directive handling. + void LexNonComment(Token &Result) { + do + Lex(Result); + while (Result.getKind() == tok::comment); + } + + /// LexUnexpandedToken - This is just like Lex, but this disables macro + /// expansion of identifier tokens. + void LexUnexpandedToken(Token &Result) { + // Disable macro expansion. + bool OldVal = DisableMacroExpansion; + DisableMacroExpansion = true; + // Lex the token. + Lex(Result); + + // Reenable it. + DisableMacroExpansion = OldVal; + } + + /// LookAhead - This peeks ahead N tokens and returns that token without + /// consuming any tokens. LookAhead(0) returns the next token that would be + /// returned by Lex(), LookAhead(1) returns the token after it, etc. This + /// returns normal tokens after phase 5. As such, it is equivalent to using + /// 'Lex', not 'LexUnexpandedToken'. + const Token &LookAhead(unsigned N) { + if (CachedLexPos + N < CachedTokens.size()) + return CachedTokens[CachedLexPos+N]; + else + return PeekAhead(N+1); + } + + /// RevertCachedTokens - When backtracking is enabled and tokens are cached, + /// this allows to revert a specific number of tokens. + /// Note that the number of tokens being reverted should be up to the last + /// backtrack position, not more. + void RevertCachedTokens(unsigned N) { + assert(isBacktrackEnabled() && + "Should only be called when tokens are cached for backtracking"); + assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) + && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= 0 && + "Corrupted backtrack positions ?"); + CachedLexPos -= N; + } + + /// EnterToken - Enters a token in the token stream to be lexed next. If + /// BackTrack() is called afterwards, the token will remain at the insertion + /// point. + void EnterToken(const Token &Tok) { + EnterCachingLexMode(); + CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok); + } + + /// AnnotateCachedTokens - We notify the Preprocessor that if it is caching + /// tokens (because backtrack is enabled) it should replace the most recent + /// cached tokens with the given annotation token. This function has no effect + /// if backtracking is not enabled. + /// + /// Note that the use of this function is just for optimization; so that the + /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is + /// invoked. + void AnnotateCachedTokens(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + AnnotatePreviousCachedTokens(Tok); + } + + /// \brief Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at + /// 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); + } + + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) { + return Diags->Report(FullSourceLoc(Tok.getLocation(), getSourceManager()), + DiagID); + } + + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a + /// token is the characters used to represent the token in the source file + /// after trigraph expansion and escaped-newline folding. In particular, this + /// wants to get the true, uncanonicalized, spelling of things like digraphs + /// UCNs, etc. + std::string getSpelling(const Token &Tok) const; + + /// getSpelling - This method is used to get the spelling of a token into a + /// preallocated buffer, instead of as an std::string. The caller is required + /// to allocate enough space for the token, which is guaranteed to be at least + /// 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. + unsigned getSpelling(const Token &Tok, const char *&Buffer) const; + + /// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant + /// with length 1, return the character. + char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const { + assert(Tok.is(tok::numeric_constant) && + Tok.getLength() == 1 && "Called on unsupported token"); + assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); + + // If the token is carrying a literal data pointer, just use it. + if (const char *D = Tok.getLiteralData()) + return *D; + + // Otherwise, fall back on getCharacterData, which is slower, but always + // works. + return *SourceMgr.getCharacterData(Tok.getLocation()); + } + + /// CreateString - Plop the specified string into a scratch buffer and set the + /// specified token's location and length to it. If specified, the source + /// location provides a location of the instantiation point of the token. + void CreateString(const char *Buf, unsigned Len, + Token &Tok, SourceLocation SourceLoc = SourceLocation()); + + /// \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. + SourceLocation getLocForEndOfToken(SourceLocation Loc); + + /// DumpToken - Print the token to stderr, used for debugging. + /// + void DumpToken(const Token &Tok, bool DumpFlags = false) const; + void DumpLocation(SourceLocation Loc) const; + void DumpMacro(const MacroInfo &MI) const; + + /// AdvanceToTokenCharacter - Given a location that specifies the start of a + /// token, return a new location that specifies a character within the token. + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart,unsigned Char); + + /// IncrementPasteCounter - Increment the counters for the number of token + /// paste operations performed. If fast was specified, this is a 'fast paste' + /// case we handled. + /// + void IncrementPasteCounter(bool isFast) { + if (isFast) + ++NumFastTokenPaste; + else + ++NumTokenPaste; + } + + void PrintStats(); + + /// HandleMicrosoftCommentPaste - When the macro expander pastes together a + /// comment (/##/) in microsoft mode, this method handles updating the current + /// state, returning the token on the next source line. + void HandleMicrosoftCommentPaste(Token &Tok); + + //===--------------------------------------------------------------------===// + // Preprocessor callback methods. These are invoked by a lexer as various + // directives and events are found. + + /// 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); + + /// HandleIdentifier - This callback is invoked when the lexer reads an + /// identifier and has filled in the tokens IdentifierInfo member. This + /// callback potentially macro expands it or turns it into a named token (like + /// 'for'). + void HandleIdentifier(Token &Identifier); + + + /// HandleEndOfFile - This callback is invoked when the lexer hits the end of + /// the current file. This either returns the EOF token and returns true, or + /// pops a level off the include stack and returns false, at which point the + /// client should call lex again. + bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); + + /// HandleEndOfTokenLexer - This callback is invoked when the current + /// TokenLexer hits the end of its token stream. + bool HandleEndOfTokenLexer(Token &Result); + + /// HandleDirective - This callback is invoked when the lexer sees a # token + /// at the start of a line. This consumes the directive, modifies the + /// lexer/preprocessor state, and advances the lexer(s) so that the next token + /// read is the correct one. + void HandleDirective(Token &Result); + + /// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If + /// not, emit a diagnostic and consume up until the eom. If EnableMacros is + /// true, then we consider macros that expand to zero tokens as being ok. + void CheckEndOfDirective(const char *Directive, bool EnableMacros = false); + + /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the + /// current line until the tok::eom token is found. + void DiscardUntilEndOfDirective(); + + /// SawDateOrTime - This returns true if the preprocessor has seen a use of + /// __DATE__ or __TIME__ in the file so far. + bool SawDateOrTime() const { + return DATELoc != SourceLocation() || TIMELoc != SourceLocation(); + } + unsigned getCounterValue() const { return CounterValue; } + void setCounterValue(unsigned V) { CounterValue = V; } + + /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide + /// SourceLocation. + MacroInfo* AllocateMacroInfo(SourceLocation L); + +private: + + void PushIncludeMacroStack() { + IncludeMacroStack.push_back(IncludeStackInfo(CurLexer.take(), + CurPTHLexer.take(), + CurPPLexer, + CurTokenLexer.take(), + CurDirLookup)); + CurPPLexer = 0; + } + + void PopIncludeMacroStack() { + CurLexer.reset(IncludeMacroStack.back().TheLexer); + CurPTHLexer.reset(IncludeMacroStack.back().ThePTHLexer); + CurPPLexer = IncludeMacroStack.back().ThePPLexer; + CurTokenLexer.reset(IncludeMacroStack.back().TheTokenLexer); + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + IncludeMacroStack.pop_back(); + } + + /// ReleaseMacroInfo - Release the specified MacroInfo. This memory will + /// be reused for allocating new MacroInfo objects. + void ReleaseMacroInfo(MacroInfo* MI); + + /// isInPrimaryFile - Return true if we're in the top-level file, not in a + /// #include. + bool isInPrimaryFile() const; + + /// ReadMacroName - Lex and validate a macro name, which occurs after a + /// #define or #undef. This emits a diagnostic, sets the token kind to eom, + /// and discards the rest of the macro line if the macro name is invalid. + void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0); + + /// ReadMacroDefinitionArgList - The ( starting an argument list of a macro + /// definition has just been read. Lex the rest of the arguments and the + /// closing ), updating MI with what we learn. Return true if an error occurs + /// parsing the arg list. + bool ReadMacroDefinitionArgList(MacroInfo *MI); + + /// SkipExcludedConditionalBlock - We just read a #if or related directive and + /// decided that the subsequent tokens are in the #if'd out portion of the + /// file. Lex the rest of the file, until we see an #endif. If + /// FoundNonSkipPortion is true, then we have already emitted code for part of + /// this #if directive, so #else/#elif blocks should never be entered. If + /// FoundElse is false, then #else directives are ok, if not, then we have + /// already seen one so a #else directive is a duplicate. When this returns, + /// the caller can lex the first valid token. + void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse); + + /// PTHSkipExcludedConditionalBlock - A fast PTH version of + /// SkipExcludedConditionalBlock. + void PTHSkipExcludedConditionalBlock(); + + /// EvaluateDirectiveExpression - Evaluate an integer constant expression that + /// may occur after a #if or #elif directive and return it as a bool. If the + /// expression is equivalent to "!defined(X)" return X in IfNDefMacro. + bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + + /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: + /// #pragma GCC poison/system_header/dependency and #pragma once. + void RegisterBuiltinPragmas(); + + /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the + /// identifier table. + void RegisterBuiltinMacros(); + IdentifierInfo *RegisterBuiltinMacro(const char *Name); + + /// HandleMacroExpandedIdentifier - If an identifier token is read that is to + /// be expanded as a macro, handle it and return the next token as 'Tok'. If + /// the macro should not be expanded return true, otherwise return false. + bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI); + + /// isNextPPTokenLParen - Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool isNextPPTokenLParen(); + + /// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is + /// invoked to read all of the formal arguments specified for the macro + /// invocation. This returns null on error. + MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, + SourceLocation &InstantiationEnd); + + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void ExpandBuiltinMacro(Token &Tok); + + /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then + /// return the first token after the directive. The _Pragma token has just + /// been read into 'Tok'. + void Handle_Pragma(Token &Tok); + + /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + + /// EnterSourceFileWithPTH - Add a lexer to the top of the include stack and + /// start getting tokens from it using the PTH cache. + void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); + + /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully + /// checked and spelled filename, e.g. as an operand of #include. This returns + /// true if the input filename was in <>'s or false if it were in ""'s. The + /// caller is expected to provide a buffer that is large enough to hold the + /// spelling of the filename, but is also expected to handle the case when + /// this method decides to use a different buffer. + bool GetIncludeFilenameSpelling(SourceLocation Loc, + const char *&BufStart, const char *&BufEnd); + + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, + /// return null on failure. isAngled indicates whether the file reference is + /// for system #include's or not (i.e. using <> instead of ""). + const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd, + bool isAngled, const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir); + + + + /// IsFileLexer - Returns true if we are lexing from a file and not a + /// pragma or a macro. + static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) { + return L ? !L->isPragmaLexer() : P != 0; + } + + static bool IsFileLexer(const IncludeStackInfo& I) { + return IsFileLexer(I.TheLexer, I.ThePPLexer); + } + + bool IsFileLexer() const { + return IsFileLexer(CurLexer.get(), CurPPLexer); + } + + //===--------------------------------------------------------------------===// + // Caching stuff. + void CachingLex(Token &Result); + bool InCachingLexMode() const { return CurPPLexer == 0 && CurTokenLexer == 0;} + void EnterCachingLexMode(); + void ExitCachingLexMode() { + if (InCachingLexMode()) + RemoveTopOfLexerStack(); + } + const Token &PeekAhead(unsigned N); + void AnnotatePreviousCachedTokens(const Token &Tok); + + //===--------------------------------------------------------------------===// + /// Handle*Directive - implement the various preprocessor directives. These + /// should side-effect the current preprocessor object so that the next call + /// to Lex() will return the appropriate token next. + void HandleLineDirective(Token &Tok); + void HandleDigitDirective(Token &Tok); + void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); + void HandleIdentSCCSDirective(Token &Tok); + + // File inclusion. + void HandleIncludeDirective(Token &Tok, + const DirectoryLookup *LookupFrom = 0, + bool isImport = false); + void HandleIncludeNextDirective(Token &Tok); + void HandleIncludeMacrosDirective(Token &Tok); + void HandleImportDirective(Token &Tok); + + // Macro handling. + void HandleDefineDirective(Token &Tok); + void HandleUndefDirective(Token &Tok); + // HandleAssertDirective(Token &Tok); + // HandleUnassertDirective(Token &Tok); + + // Conditional Inclusion. + void HandleIfdefDirective(Token &Tok, bool isIfndef, + bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective); + void HandleEndifDirective(Token &Tok); + void HandleElseDirective(Token &Tok); + void HandleElifDirective(Token &Tok); + + // Pragmas. + void HandlePragmaDirective(); +public: + void HandlePragmaOnce(Token &OnceTok); + void HandlePragmaMark(); + void HandlePragmaPoison(Token &PoisonTok); + void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaComment(Token &CommentTok); +}; + +/// PreprocessorFactory - A generic factory interface for lazily creating +/// Preprocessor objects on-demand when they are needed. +class PreprocessorFactory { +public: + virtual ~PreprocessorFactory(); + virtual Preprocessor* CreatePreprocessor() = 0; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h new file mode 100644 index 000000000000..f98b5599658f --- /dev/null +++ b/include/clang/Lex/PreprocessorLexer.h @@ -0,0 +1,161 @@ +//===--- PreprocessorLexer.h - C Language Family Lexer ----------*- 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 PreprocessorLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PreprocessorLexer_H +#define LLVM_CLANG_PreprocessorLexer_H + +#include "clang/Lex/MultipleIncludeOpt.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" +#include <string> + +namespace clang { + +class Preprocessor; + +class PreprocessorLexer { +protected: + Preprocessor *PP; // Preprocessor object controlling lexing. + + /// The SourceManager FileID corresponding to the file being lexed. + const FileID FID; + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + //===--------------------------------------------------------------------===// + + /// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns + /// '\n' into a tok::eom token. + bool ParsingPreprocessorDirective; + + /// ParsingFilename - True after #include: this turns <xx> into a + /// tok::angle_string_literal token. + bool ParsingFilename; + + /// LexingRawMode - True if in raw mode: This flag disables interpretation of + /// tokens and is a far faster mode to lex in than non-raw-mode. This flag: + /// 1. If EOF of the current lexer is found, the include stack isn't popped. + /// 2. Identifier information is not looked up for identifier tokens. As an + /// effect of this, implicit macro expansion is naturally disabled. + /// 3. "#" tokens at the start of a line are treated as normal tokens, not + /// implicitly transformed by the lexer. + /// 4. All diagnostic messages are disabled. + /// 5. No callbacks are made into the preprocessor. + /// + /// Note that in raw mode that the PP pointer may be null. + bool LexingRawMode; + + /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file + /// idiom for the multiple-include optimization. + MultipleIncludeOpt MIOpt; + + /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks + /// we are currently in. + llvm::SmallVector<PPConditionalInfo, 4> ConditionalStack; + + PreprocessorLexer(const PreprocessorLexer&); // DO NOT IMPLEMENT + void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT + friend class Preprocessor; + + PreprocessorLexer(Preprocessor *pp, FileID fid) + : PP(pp), FID(fid), ParsingPreprocessorDirective(false), + ParsingFilename(false), LexingRawMode(false) {} + + PreprocessorLexer() + : PP(0), + ParsingPreprocessorDirective(false), + ParsingFilename(false), + LexingRawMode(false) {} + + virtual ~PreprocessorLexer() {} + + virtual void IndirectLex(Token& Result) = 0; + + /// getSourceLocation - Return the source location for the next observable + /// location. + virtual SourceLocation getSourceLocation() = 0; + + //===--------------------------------------------------------------------===// + // #if directive handling. + + /// pushConditionalLevel - When we enter a #if directive, this keeps track of + /// what we are currently in for diagnostic emission (e.g. #if with missing + /// #endif). + void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, + bool FoundNonSkip, bool FoundElse) { + PPConditionalInfo CI; + CI.IfLoc = DirectiveStart; + CI.WasSkipping = WasSkipping; + CI.FoundNonSkip = FoundNonSkip; + CI.FoundElse = FoundElse; + ConditionalStack.push_back(CI); + } + void pushConditionalLevel(const PPConditionalInfo &CI) { + ConditionalStack.push_back(CI); + } + + /// popConditionalLevel - Remove an entry off the top of the conditional + /// stack, returning information about it. If the conditional stack is empty, + /// this returns true and does not fill in the arguments. + bool popConditionalLevel(PPConditionalInfo &CI) { + if (ConditionalStack.empty()) return true; + CI = ConditionalStack.back(); + ConditionalStack.pop_back(); + return false; + } + + /// peekConditionalLevel - Return the top of the conditional stack. This + /// requires that there be a conditional active. + PPConditionalInfo &peekConditionalLevel() { + assert(!ConditionalStack.empty() && "No conditionals active!"); + return ConditionalStack.back(); + } + + unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } + +public: + + //===--------------------------------------------------------------------===// + // Misc. lexing methods. + + /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and + /// (potentially) macro expand the filename. If the sequence parsed is not + /// lexically legal, emit a diagnostic and return a result EOM token. + void LexIncludeFilename(Token &Result); + + /// setParsingPreprocessorDirective - Inform the lexer whether or not + /// we are currently lexing a preprocessor directive. + void setParsingPreprocessorDirective(bool f) { + ParsingPreprocessorDirective = f; + } + + /// isLexingRawMode - Return true if this lexer is in raw mode or not. + bool isLexingRawMode() const { return LexingRawMode; } + + /// getPP - Return the preprocessor object for this lexer. + Preprocessor *getPP() const { return PP; } + + FileID getFileID() const { + assert(PP && + "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); + return FID; + } + + /// getFileEntry - Return the FileEntry corresponding to this FileID. Like + /// getFileID(), this only works for lexers with attached preprocessors. + const FileEntry *getFileEntry() const; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/ScratchBuffer.h b/include/clang/Lex/ScratchBuffer.h new file mode 100644 index 000000000000..6506f9262947 --- /dev/null +++ b/include/clang/Lex/ScratchBuffer.h @@ -0,0 +1,45 @@ +//===--- ScratchBuffer.h - Scratch space for forming tokens -----*- 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 ScratchBuffer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCRATCHBUFFER_H +#define LLVM_CLANG_SCRATCHBUFFER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class SourceManager; + +/// ScratchBuffer - This class exposes a simple interface for the dynamic +/// construction of tokens. This is used for builtin macros (e.g. __LINE__) as +/// well as token pasting, etc. +class ScratchBuffer { + SourceManager &SourceMgr; + char *CurBuffer; + SourceLocation BufferStartLoc; + unsigned BytesUsed; +public: + ScratchBuffer(SourceManager &SM); + + /// getToken - Splat the specified text into a temporary MemoryBuffer and + /// return a SourceLocation that refers to the token. This is just like the + /// previous method, but returns a location that indicates the physloc of the + /// token. + SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr); + +private: + void AllocScratchBuffer(unsigned RequestLen); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h new file mode 100644 index 000000000000..2c8f2ad3f2b6 --- /dev/null +++ b/include/clang/Lex/Token.h @@ -0,0 +1,312 @@ +//===--- Token.h - Token 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 Token interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKEN_H +#define LLVM_CLANG_TOKEN_H + +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Basic/SourceLocation.h" +#include <cstdlib> + +namespace clang { + +class IdentifierInfo; + +/// Token - This structure provides full information about a lexed token. +/// It is not intended to be space efficient, it is intended to return as much +/// information as possible about each returned token. This is expected to be +/// compressed into a smaller form if memory footprint is important. +/// +/// The parser can create a special "annotation token" representing a stream of +/// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>" +/// can be represented by a single typename annotation token that carries +/// information about the SourceRange of the tokens and the type object. +class Token { + /// The location of the token. + SourceLocation Loc; + + // Conceptually these next two fields could be in a union. However, this + // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical + // routine. Keeping as separate members with casts until a more beautiful fix + // presents itself. + + /// UintData - This holds either the length of the token text, when + /// a normal token, or the end of the SourceRange when an annotation + /// token. + unsigned UintData; + + /// PtrData - This is a union of four different pointer types, which depends + /// on what type of token this is: + /// Identifiers, keywords, etc: + /// This is an IdentifierInfo*, which contains the uniqued identifier + /// spelling. + /// Literals: isLiteral() returns true. + /// This is a pointer to the start of the token in a text buffer, which + /// may be dirty (have trigraphs / escaped newlines). + /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). + /// This is a pointer to sema-specific data for the annotation token. + /// Other: + /// This is null. + void *PtrData; + + /// Kind - The actual flavor of token this is. + /// + unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind'; + // MSVC will treat it as a signed char and + // TokenKinds > 127 won't be handled correctly. + + /// Flags - Bits we track about this token, members of the TokenFlags enum. + unsigned Flags : 8; +public: + + // Various flags set per token: + enum TokenFlags { + StartOfLine = 0x01, // At start of line or only after whitespace. + LeadingSpace = 0x02, // Whitespace exists before this token. + DisableExpand = 0x04, // This identifier may never be macro expanded. + NeedsCleaning = 0x08 // Contained an escaped newline or trigraph. + }; + + tok::TokenKind getKind() const { return (tok::TokenKind)Kind; } + void setKind(tok::TokenKind K) { Kind = K; } + + /// is/isNot - Predicates to check if this token is a specific kind, as in + /// "if (Tok.is(tok::l_brace)) {...}". + bool is(tok::TokenKind K) const { return Kind == (unsigned) K; } + bool isNot(tok::TokenKind K) const { return Kind != (unsigned) K; } + + /// isLiteral - Return true if this is a "literal", like a numeric + /// constant, string, etc. + bool isLiteral() const { + return is(tok::numeric_constant) || is(tok::char_constant) || + is(tok::string_literal) || is(tok::wide_string_literal) || + is(tok::angle_string_literal); + } + + bool isAnnotation() const { + return is(tok::annot_typename) || + is(tok::annot_cxxscope) || + is(tok::annot_template_id); + } + + /// getLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getLocation() const { return Loc; } + unsigned getLength() const { + assert(!isAnnotation() && "Annotation tokens have no length field"); + return UintData; + } + + void setLocation(SourceLocation L) { Loc = L; } + void setLength(unsigned Len) { + assert(!isAnnotation() && "Annotation tokens have no length field"); + UintData = Len; + } + + SourceLocation getAnnotationEndLoc() const { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + return SourceLocation::getFromRawEncoding(UintData); + } + void setAnnotationEndLoc(SourceLocation L) { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + UintData = L.getRawEncoding(); + } + + /// getAnnotationRange - SourceRange of the group of tokens that this + /// annotation token represents. + SourceRange getAnnotationRange() const { + return SourceRange(getLocation(), getAnnotationEndLoc()); + } + void setAnnotationRange(SourceRange R) { + setLocation(R.getBegin()); + setAnnotationEndLoc(R.getEnd()); + } + + const char *getName() const { + return tok::getTokenName( (tok::TokenKind) Kind); + } + + /// startToken - Reset all flags to cleared. + /// + void startToken() { + Kind = tok::unknown; + Flags = 0; + PtrData = 0; + Loc = SourceLocation(); + } + + IdentifierInfo *getIdentifierInfo() const { + assert(!isAnnotation() && "Used IdentInfo on annotation token!"); + if (isLiteral()) return 0; + return (IdentifierInfo*) PtrData; + } + void setIdentifierInfo(IdentifierInfo *II) { + PtrData = (void*) II; + } + + /// getLiteralData - For a literal token (numeric constant, string, etc), this + /// returns a pointer to the start of it in the text buffer if known, null + /// otherwise. + const char *getLiteralData() const { + assert(isLiteral() && "Cannot get literal data of non-literal"); + return reinterpret_cast<const char*>(PtrData); + } + void setLiteralData(const char *Ptr) { + assert(isLiteral() && "Cannot set literal data of non-literal"); + PtrData = (void*)Ptr; + } + + void *getAnnotationValue() const { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + return PtrData; + } + void setAnnotationValue(void *val) { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + PtrData = val; + } + + /// setFlag - Set the specified flag. + void setFlag(TokenFlags Flag) { + Flags |= Flag; + } + + /// clearFlag - Unset the specified flag. + void clearFlag(TokenFlags Flag) { + Flags &= ~Flag; + } + + /// getFlags - Return the internal represtation of the flags. + /// Only intended for low-level operations such as writing tokens to + // disk. + unsigned getFlags() const { + return Flags; + } + + /// setFlagValue - Set a flag to either true or false. + void setFlagValue(TokenFlags Flag, bool Val) { + if (Val) + setFlag(Flag); + else + clearFlag(Flag); + } + + /// isAtStartOfLine - Return true if this token is at the start of a line. + /// + bool isAtStartOfLine() const { return (Flags & StartOfLine) ? true : false; } + + /// hasLeadingSpace - Return true if this token has whitespace before it. + /// + bool hasLeadingSpace() const { return (Flags & LeadingSpace) ? true : false; } + + /// isExpandDisabled - Return true if this identifier token should never + /// be expanded in the future, due to C99 6.10.3.4p2. + bool isExpandDisabled() const { + return (Flags & DisableExpand) ? true : false; + } + + /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. + bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; + + /// getObjCKeywordID - Return the ObjC keyword kind. + tok::ObjCKeywordKind getObjCKeywordID() const; + + /// needsCleaning - Return true if this token has trigraphs or escaped + /// newlines in it. + /// + bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; } +}; + +/// PPConditionalInfo - Information about the conditional stack (#if directives) +/// currently active. +struct PPConditionalInfo { + /// IfLoc - Location where the conditional started. + /// + SourceLocation IfLoc; + + /// WasSkipping - True if this was contained in a skipping directive, e.g. + /// in a "#if 0" block. + bool WasSkipping; + + /// FoundNonSkip - True if we have emitted tokens already, and now we're in + /// an #else block or something. Only useful in Skipping blocks. + bool FoundNonSkip; + + /// FoundElse - True if we've seen a #else in this block. If so, + /// #elif/#else directives are not allowed. + bool FoundElse; +}; + +/// TemplateIdAnnotation - Information about a template-id annotation +/// token, which contains the template declaration, template +/// arguments, whether those template arguments were types or +/// expressions, and the source locations for important tokens. All of +/// the information about template arguments is allocated directly +/// after this structure. +struct TemplateIdAnnotation { + /// TemplateNameLoc - The location of the template name within the + /// source. + SourceLocation TemplateNameLoc; + + /// FIXME: Temporarily stores the name of a specialization + IdentifierInfo *Name; + + /// The declaration of the template corresponding to the + /// template-name. This is an Action::DeclTy*. + void *Template; + + /// The kind of template that Template refers to. + TemplateNameKind Kind; + + /// The location of the '<' before the template argument + /// list. + SourceLocation LAngleLoc; + + /// The location of the '>' after the template argument + /// list. + SourceLocation RAngleLoc; + + /// NumArgs - The number of template arguments. + unsigned NumArgs; + + /// \brief Retrieves a pointer to the template arguments + void **getTemplateArgs() { return (void **)(this + 1); } + + /// \brief Retrieves a pointer to the array of template argument + /// locations. + SourceLocation *getTemplateArgLocations() { + return (SourceLocation *)(getTemplateArgs() + NumArgs); + } + + /// \brief Retrieves a pointer to the array of flags that states + /// whether the template arguments are types. + bool *getTemplateArgIsType() { + return (bool *)(getTemplateArgLocations() + NumArgs); + } + + static TemplateIdAnnotation* Allocate(unsigned NumArgs) { + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + + sizeof(void*) * NumArgs + + sizeof(SourceLocation) * NumArgs + + sizeof(bool) * NumArgs); + TemplateId->NumArgs = NumArgs; + return TemplateId; + } + + void Destroy() { free(this); } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h new file mode 100644 index 000000000000..dfc05f4074e0 --- /dev/null +++ b/include/clang/Lex/TokenConcatenation.h @@ -0,0 +1,73 @@ +//===--- TokenConcatenation.h - Token Concatenation Avoidance ---*- 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 TokenConcatenation class. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LEX_TOKEN_CONCATENATION_H +#define CLANG_LEX_TOKEN_CONCATENATION_H + +#include "clang/Basic/TokenKinds.h" + +namespace clang { + class Preprocessor; + class Token; + + /// TokenConcatenation class, which answers the question of + /// "Is it safe to emit two tokens without a whitespace between them, or + /// would that cause implicit concatenation of the tokens?" + /// + /// For example, it emitting two identifiers "foo" and "bar" next to each + /// other would cause the lexer to produce one "foobar" token. Emitting "1" + /// and ")" next to each other is safe. + /// + class TokenConcatenation { + Preprocessor &PP; + + enum AvoidConcatInfo { + /// By default, a token never needs to avoid concatenation. Most tokens + /// (e.g. ',', ')', etc) don't cause a problem when concatenated. + aci_never_avoid_concat = 0, + + /// aci_custom_firstchar - AvoidConcat contains custom code to handle this + /// token's requirements, and it needs to know the first character of the + /// token. + aci_custom_firstchar = 1, + + /// aci_custom - AvoidConcat contains custom code to handle this token's + /// requirements, but it doesn't need to know the first character of the + /// token. + aci_custom = 2, + + /// aci_avoid_equal - Many tokens cannot be safely followed by an '=' + /// character. For example, "<<" turns into "<<=" when followed by an =. + aci_avoid_equal = 4 + }; + + /// TokenInfo - This array contains information for each token on what + /// action to take when avoiding concatenation of tokens in the AvoidConcat + /// method. + char TokenInfo[tok::NUM_TOKENS]; + public: + TokenConcatenation(Preprocessor &PP); + + bool AvoidConcat(const Token &PrevTok, const Token &Tok) const; + + private: + /// StartsWithL - Return true if the spelling of this token starts with 'L'. + bool StartsWithL(const Token &Tok) const; + + /// IsIdentifierL - Return true if the spelling of this token is literally + /// 'L'. + bool IsIdentifierL(const Token &Tok) const; + }; + } // end clang namespace + +#endif diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h new file mode 100644 index 000000000000..c0a61cf93ee5 --- /dev/null +++ b/include/clang/Lex/TokenLexer.h @@ -0,0 +1,154 @@ +//===--- TokenLexer.h - Lex from a token buffer -----------------*- 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 TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENLEXER_H +#define LLVM_CLANG_TOKENLEXER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class MacroInfo; + class Preprocessor; + class Token; + class MacroArgs; + +/// TokenLexer - This implements a lexer that returns token from a macro body +/// or token stream instead of lexing from a character buffer. This is used for +/// macro expansion and _Pragma handling, for example. +/// +class TokenLexer { + /// Macro - The macro we are expanding from. This is null if expanding a + /// token stream. + /// + MacroInfo *Macro; + + /// ActualArgs - The actual arguments specified for a function-like macro, or + /// null. The TokenLexer owns the pointed-to object. + MacroArgs *ActualArgs; + + /// PP - The current preprocessor object we are expanding for. + /// + Preprocessor &PP; + + /// Tokens - This is the pointer to an array of tokens that the macro is + /// defined to, with arguments expanded for function-like macros. If this is + /// a token stream, these are the tokens we are returning. This points into + /// the macro definition we are lexing from, a scratch buffer allocated from + /// the preprocessor's bump pointer allocator, or some other buffer that we + /// may or may not own (depending on OwnsTokens). + const Token *Tokens; + + /// NumTokens - This is the length of the Tokens array. + /// + unsigned NumTokens; + + /// CurToken - This is the next token that Lex will return. + /// + unsigned CurToken; + + /// InstantiateLocStart/End - The source location range where this macro was + /// instantiated. + SourceLocation InstantiateLocStart, InstantiateLocEnd; + + /// Lexical information about the expansion point of the macro: the identifier + /// that the macro expanded from had these properties. + bool AtStartOfLine : 1; + bool HasLeadingSpace : 1; + + /// OwnsTokens - This is true if this TokenLexer allocated the Tokens + /// array, and thus needs to free it when destroyed. For simple object-like + /// macros (for example) we just point into the token buffer of the macro + /// definition, we don't make a copy of it. + bool OwnsTokens : 1; + + /// DisableMacroExpansion - This is true when tokens lexed from the TokenLexer + /// should not be subject to further macro expansion. + bool DisableMacroExpansion : 1; + + TokenLexer(const TokenLexer&); // DO NOT IMPLEMENT + void operator=(const TokenLexer&); // DO NOT IMPLEMENT +public: + /// Create a TokenLexer for the specified macro with the specified actual + /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + TokenLexer(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs, + Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { + Init(Tok, ILEnd, ActualArgs); + } + + /// Init - Initialize this TokenLexer to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. ILEnd specifies the location of the + /// ')' for a function-like macro or the identifier for an object-like macro. + void Init(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs); + + /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is + /// specified, this takes ownership of the tokens and delete[]'s them when + /// the token lexer is empty. + TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion, + bool ownsTokens, Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { + Init(TokArray, NumToks, DisableExpansion, ownsTokens); + } + + /// Init - Initialize this TokenLexer with the specified token stream. + /// This does not take ownership of the specified token vector. + /// + /// DisableExpansion is true when macro expansion of tokens lexed from this + /// stream should be disabled. + void Init(const Token *TokArray, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + ~TokenLexer() { destroy(); } + + /// isNextTokenLParen - If the next token lexed will pop this macro off the + /// expansion stack, return 2. If the next unexpanded token is a '(', return + /// 1, otherwise return 0. + unsigned isNextTokenLParen() const; + + /// Lex - Lex and return a token from this macro stream. + void Lex(Token &Tok); + +private: + void destroy(); + + /// isAtEnd - Return true if the next lex call will pop this macro off the + /// include stack. + bool isAtEnd() const { + return CurToken == NumTokens; + } + + /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## + /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there + /// are is another ## after it, chomp it iteratively. Return the result as + /// Tok. If this returns true, the caller should immediately return the + /// token. + bool PasteTokens(Token &Tok); + + /// Expand the arguments of a function-like macro so that we can quickly + /// return preexpanded tokens from Tokens. + void ExpandFunctionArguments(); + + /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes + /// together to form a comment that comments out everything in the current + /// macro, other active macros, and anything left on the current physical + /// source line of the instantiated buffer. Handle this by returning the + /// first token on the next line. + void HandleMicrosoftCommentPaste(Token &Tok); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Makefile b/include/clang/Makefile new file mode 100644 index 000000000000..82a16d53ea33 --- /dev/null +++ b/include/clang/Makefile @@ -0,0 +1,4 @@ +LEVEL = ../../../.. +DIRS := Basic + +include $(LEVEL)/Makefile.common diff --git a/include/clang/Parse/AccessSpecifier.h b/include/clang/Parse/AccessSpecifier.h new file mode 100644 index 000000000000..8d2cee8ea43a --- /dev/null +++ b/include/clang/Parse/AccessSpecifier.h @@ -0,0 +1,30 @@ +//===--- AccessSpecifier.h - C++ Access Specifiers -*- 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 interfaces used for C++ access specifiers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H +#define LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H + +namespace clang { + +/// AccessSpecifier - A C++ access specifier (none, public, private, +/// protected). +enum AccessSpecifier { + AS_none, + AS_public, + AS_protected, + AS_private +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h new file mode 100644 index 000000000000..5c23f9ac6147 --- /dev/null +++ b/include/clang/Parse/Action.h @@ -0,0 +1,1839 @@ +//===--- Action.h - Parser Action 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 Action and EmptyAction interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_ACTION_H +#define LLVM_CLANG_PARSE_ACTION_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TypeTraits.h" +#include "clang/Parse/AccessSpecifier.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Ownership.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + // Semantic. + class DeclSpec; + class ObjCDeclSpec; + class CXXScopeSpec; + class Declarator; + class AttributeList; + struct FieldDeclarator; + // Parse. + class Scope; + class Action; + class Selector; + class Designation; + class InitListDesignations; + // Lex. + class Preprocessor; + class Token; + + // We can re-use the low bit of expression, statement, base, and + // member-initializer pointers for the "invalid" flag of + // ActionResult. + template<> struct IsResultPtrLowBitFree<0> { static const bool value = true;}; + template<> struct IsResultPtrLowBitFree<1> { static const bool value = true;}; + template<> struct IsResultPtrLowBitFree<3> { static const bool value = true;}; + template<> struct IsResultPtrLowBitFree<4> { static const bool value = true;}; + template<> struct IsResultPtrLowBitFree<5> { static const bool value = true;}; + +/// Action - As the parser reads the input file and recognizes the productions +/// of the grammar, it invokes methods on this class to turn the parsed input +/// into something useful: e.g. a parse tree. +/// +/// The callback methods that this class provides are phrased as actions that +/// the parser has just done or is about to do when the method is called. They +/// are not requests that the actions module do the specified action. +/// +/// All of the methods here are optional except getTypeName() and +/// isCurrentClassName(), which must be specified in order for the +/// parse to complete accurately. The MinimalAction class does this +/// bare-minimum of tracking to implement this functionality. +class Action : public ActionBase { +public: + /// Out-of-line virtual destructor to provide home for this class. + virtual ~Action(); + + // Types - Though these don't actually enforce strong typing, they document + // what types are required to be identical for the actions. + typedef ActionBase::ExprTy ExprTy; + typedef ActionBase::StmtTy StmtTy; + + /// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap + /// ExprTy/StmtTy/TypeTy/BaseTy, providing strong typing and + /// allowing for failure. + typedef ActionResult<0> ExprResult; + typedef ActionResult<1> StmtResult; + typedef ActionResult<2> TypeResult; + typedef ActionResult<3> BaseResult; + typedef ActionResult<4> MemInitResult; + typedef ActionResult<5, DeclPtrTy> DeclResult; + + /// Same, but with ownership. + typedef ASTOwningResult<&ActionBase::DeleteExpr> OwningExprResult; + typedef ASTOwningResult<&ActionBase::DeleteStmt> OwningStmtResult; + // Note that these will replace ExprResult and StmtResult when the transition + // is complete. + + /// Single expressions or statements as arguments. +#if !defined(DISABLE_SMART_POINTERS) + typedef ASTOwningResult<&ActionBase::DeleteExpr> ExprArg; + typedef ASTOwningResult<&ActionBase::DeleteStmt> StmtArg; +#else + typedef ASTOwningPtr<&ActionBase::DeleteExpr> ExprArg; + typedef ASTOwningPtr<&ActionBase::DeleteStmt> StmtArg; +#endif + + /// Multiple expressions or statements as arguments. + typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg; + typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg; + typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg; + + class FullExprArg { + public: + // FIXME: The const_cast here is ugly. RValue references would make this + // much nicer (or we could duplicate a bunch of the move semantics + // emulation code from Ownership.h). + FullExprArg(const FullExprArg& Other) + : Expr(move(const_cast<FullExprArg&>(Other).Expr)) {} + + OwningExprResult release() { + return move(Expr); + } + + ExprArg* operator->() { + return &Expr; + } + + private: + // FIXME: No need to make the entire Action class a friend when it's just + // Action::FullExpr that needs access to the constructor below. + friend class Action; + + explicit FullExprArg(ExprArg expr) + : Expr(move(expr)) {} + + ExprArg Expr; + }; + + template<typename T> + FullExprArg FullExpr(T &Arg) { + return FullExprArg(ActOnFinishFullExpr(move(Arg))); + } + + // Utilities for Action implementations to return smart results. + + OwningExprResult ExprError() { return OwningExprResult(*this, true); } + OwningStmtResult StmtError() { return OwningStmtResult(*this, true); } + + OwningExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); } + OwningStmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); } + + OwningExprResult ExprEmpty() { return OwningExprResult(*this, false); } + OwningStmtResult StmtEmpty() { return OwningStmtResult(*this, false); } + + /// Statistics. + virtual void PrintStats() const {} + + /// getDeclName - Return a pretty name for the specified decl if possible, or + /// an empty string if not. This is used for pretty crash reporting. + virtual std::string getDeclName(DeclPtrTy D) { return ""; } + + //===--------------------------------------------------------------------===// + // Declaration Tracking Callbacks. + //===--------------------------------------------------------------------===// + + /// ConvertDeclToDeclGroup - If the parser has one decl in a context where it + /// needs a decl group, it calls this to convert between the two + /// representations. + virtual DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr) { + return DeclGroupPtrTy(); + } + + /// getTypeName - Return non-null if the specified identifier is a type name + /// in the current scope. + /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or + /// namespace) that the identifier must be a member of. + /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". + virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec *SS = 0) = 0; + + /// isTagName() - This method is called *for error recovery purposes only* + /// to determine if the specified name is a valid tag name ("struct foo"). If + /// so, this returns the TST for the tag corresponding to it (TST_enum, + /// TST_union, TST_struct, TST_class). This is used to diagnose cases in C + /// where the user forgot to specify the tag. + virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S) { + return DeclSpec::TST_unspecified; + } + + /// isCurrentClassName - Return true if the specified name is the + /// name of the innermost C++ class type currently being defined. + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = 0) = 0; + + /// \brief Determines whether the identifier II is a template name + /// in the current scope. If so, the kind of template name is + /// returned, and \p TemplateDecl receives the declaration. An + /// optional CXXScope can be passed to indicate the C++ scope in + /// which the identifier will be found. + virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + TemplateTy &Template, + const CXXScopeSpec *SS = 0) = 0; + + /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the + /// global scope ('::'). + virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, + SourceLocation CCLoc) { + return 0; + } + + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now + /// we want to resolve "bar::". 'SS' is empty or the previously parsed + /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', + /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. + /// Returns a CXXScopeTy* object representing the C++ scope. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + IdentifierInfo &II) { + return 0; + } + + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier that involves a template-id, e.g., + /// "foo::bar<int, float>::", and now we need to build a scope + /// specifier. \p SS is empty or the previously parsed nested-name + /// part ("foo::"), \p Type is the already-parsed class template + /// specialization (or other template-id that names a type), \p + /// TypeRange is the source range where the type is located, and \p + /// CCLoc is the location of the trailing '::'. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Type, + SourceRange TypeRange, + SourceLocation CCLoc) { + return 0; + } + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + } + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + } + + /// ActOnDeclarator - This callback is invoked when a declarator is parsed and + /// 'Init' specifies the initializer if any. This is for things like: + /// "int X = 4" or "typedef int foo". + /// + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { + return DeclPtrTy(); + } + + /// ActOnParamDeclarator - This callback is invoked when a parameter + /// declarator is parsed. This callback only occurs for functions + /// with prototypes. S is the function prototype scope for the + /// parameters (C++ [basic.scope.proto]). + virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) { + return DeclPtrTy(); + } + + /// AddInitializerToDecl - This action is called immediately after + /// ActOnDeclarator (when an initializer is present). The code is factored + /// this way to make sure we are able to handle the following: + /// void func() { int xx = xx; } + /// This allows ActOnDeclarator to register "xx" prior to parsing the + /// initializer. The declaration above should still result in a warning, + /// since the reference to "xx" is uninitialized. + virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) { + return; + } + + /// SetDeclDeleted - This action is called immediately after ActOnDeclarator + /// if =delete is parsed. C++0x [dcl.fct.def]p10 + /// Note that this can be called even for variable declarations. It's the + /// action's job to reject it. + virtual void SetDeclDeleted(DeclPtrTy Dcl, SourceLocation DelLoc) { + return; + } + + /// ActOnUninitializedDecl - This action is called immediately after + /// ActOnDeclarator (when an initializer is *not* present). + virtual void ActOnUninitializedDecl(DeclPtrTy Dcl) { + return; + } + + /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this + /// gives the actions implementation a chance to process the group as a whole. + virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS, + DeclPtrTy *Group, + unsigned NumDecls) { + return DeclGroupPtrTy(); + } + + + /// @brief Indicates that all K&R-style parameter declarations have + /// been parsed prior to a function definition. + /// @param S The function prototype scope. + /// @param D The function declarator. + virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls) { + } + + /// ActOnStartOfFunctionDef - This is called at the start of a function + /// definition, instead of calling ActOnDeclarator. The Declarator includes + /// information about formal arguments that are part of this function. + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { + // Default to ActOnDeclarator. + return ActOnStartOfFunctionDef(FnBodyScope, + ActOnDeclarator(FnBodyScope, D)); + } + + /// ActOnStartOfFunctionDef - This is called at the start of a function + /// definition, after the FunctionDecl has already been created. + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { + return D; + } + + virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { + return; + } + + /// ActOnFinishFunctionBody - This is called when a function body has + /// completed parsing. Decl is returned by ParseStartOfFunctionDef. + virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) { + return Decl; + } + + virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, + ExprArg AsmString) { + return DeclPtrTy(); + } + + /// ActOnPopScope - This callback is called immediately before the specified + /// scope is popped and deleted. + virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {} + + /// ActOnTranslationUnitScope - This callback is called once, immediately + /// after creating the translation unit scope (in Parser::Initialize). + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {} + + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with + /// no declarator (e.g. "struct foo;") is parsed. + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + return DeclPtrTy(); + } + + /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ + /// linkage specification, including the language and (if present) + /// the '{'. ExternLoc is the location of the 'extern', LangLoc is + /// the location of the language string literal, which is provided + /// by Lang/StrSize. LBraceLoc, if valid, provides the location of + /// the '{' brace. Otherwise, this linkage specification does not + /// have any braces. + virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc) { + return DeclPtrTy(); + } + + /// ActOnFinishLinkageSpecification - Completely the definition of + /// the C++ linkage specification LinkageSpec. If RBraceLoc is + /// valid, it's the position of the closing '}' brace in a linkage + /// specification that uses braces. + virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S, + DeclPtrTy LinkageSpec, + SourceLocation RBraceLoc) { + return LinkageSpec; + } + + /// ActOnEndOfTranslationUnit - This is called at the very end of the + /// translation unit when EOF is reached and all but the top-level scope is + /// popped. + virtual void ActOnEndOfTranslationUnit() {} + + //===--------------------------------------------------------------------===// + // Type Parsing Callbacks. + //===--------------------------------------------------------------------===// + + /// ActOnTypeName - A type-name (type-id in C++) was parsed. + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { + return TypeResult(); + } + + enum TagKind { + TK_Reference, // Reference to a tag: 'struct foo *X;' + TK_Declaration, // Fwd decl of a tag: 'struct foo;' + TK_Definition // Definition of a tag: 'struct foo { int X; } Y;' + }; + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + bool &OwnedDecl) { + // TagType is an instance of DeclSpec::TST, indicating what kind of tag this + // is (struct/union/enum/class). + return DeclPtrTy(); + } + + /// Act on @defs() element found when parsing a structure. ClassName is the + /// name of the referenced class. + virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVectorImpl<DeclPtrTy> &Decls) {} + virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { + return DeclPtrTy(); + } + + virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth, + tok::ObjCKeywordKind visibility) { + return DeclPtrTy(); + } + + virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl, + DeclPtrTy *Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *AttrList) {} + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl) { } + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl) { } + + virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, + DeclPtrTy LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *Val) { + return DeclPtrTy(); + } + virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, DeclPtrTy EnumDecl, + DeclPtrTy *Elements, unsigned NumElements) {} + + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks. + //===--------------------------------------------------------------------===// + + virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + MultiStmtArg Elts, + bool isStmtExpr) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) { + return OwningStmtResult(*this, Expr->release()); + } + + /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension, + /// which can specify an RHS value. The sub-statement of the case is + /// specified in a separate action. + virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal, + SourceLocation DotDotDotLoc, + ExprArg RHSVal, + SourceLocation ColonLoc) { + return StmtEmpty(); + } + + /// ActOnCaseStmtBody - This installs a statement as the body of a case. + virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt) {} + + virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + StmtArg SubStmt, Scope *CurScope){ + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation ColonLoc, + StmtArg SubStmt) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, StmtArg ThenVal, + SourceLocation ElseLoc, + StmtArg ElseVal) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + StmtArg Switch, StmtArg Body) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, + FullExprArg Cond, StmtArg Body) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, + SourceLocation WhileLoc, ExprArg Cond) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg First, ExprArg Second, + ExprArg Third, SourceLocation RParenLoc, + StmtArg Body) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + SourceLocation LParenLoc, + StmtArg First, ExprArg Second, + SourceLocation RParenLoc, StmtArg Body) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + IdentifierInfo *LabelII) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + ExprArg DestExp) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc, + Scope *CurScope) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc, + Scope *CurScope) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, + FullExprArg RetValExp) { + return StmtEmpty(); + } + virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + std::string *Names, + MultiExprArg Constraints, + MultiExprArg Exprs, + ExprArg AsmString, + MultiExprArg Clobbers, + SourceLocation RParenLoc) { + return StmtEmpty(); + } + + // Objective-c statements + virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, + DeclPtrTy Parm, StmtArg Body, + StmtArg CatchList) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, + StmtArg Body) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtArg Try, StmtArg Catch, + StmtArg Finally) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw, + Scope *CurScope) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprArg SynchExpr, + StmtArg SynchBody) { + return StmtEmpty(); + } + + // C++ Statements + virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) { + return DeclPtrTy(); + } + + virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + DeclPtrTy ExceptionDecl, + StmtArg HandlerBlock) { + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, + StmtArg TryBlock, + MultiStmtArg Handlers) { + return StmtEmpty(); + } + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks. + //===--------------------------------------------------------------------===// + + // Primary Expressions. + + /// \brief Retrieve the source range that corresponds to the given + /// expression. + virtual SourceRange getExprRange(ExprTy *E) const { + return SourceRange(); + } + + /// ActOnIdentifierExpr - Parse an identifier in expression context. + /// 'HasTrailingLParen' indicates whether or not the identifier has a '(' + /// token immediately after it. + /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or + /// namespace) that the identifier must be a member of. + /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". + virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen, + const CXXScopeSpec *SS = 0, + bool isAddressOfOperand = false){ + return ExprEmpty(); + } + + /// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator + /// name (e.g., @c operator+ ) as an expression. This is very + /// similar to ActOnIdentifierExpr, except that instead of providing + /// an identifier the parser provides the kind of overloaded + /// operator that was parsed. + virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( + Scope *S, SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + bool HasTrailingLParen, const CXXScopeSpec &SS, + bool isAddressOfOperand = false) { + return ExprEmpty(); + } + + /// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function + /// name (e.g., @c operator void const *) as an expression. This is + /// very similar to ActOnIdentifierExpr, except that instead of + /// providing an identifier the parser provides the type of the + /// conversion function. + virtual OwningExprResult ActOnCXXConversionFunctionExpr( + Scope *S, SourceLocation OperatorLoc, + TypeTy *Type, bool HasTrailingLParen, + const CXXScopeSpec &SS, + bool isAddressOfOperand = false) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, + tok::TokenKind Kind) { + return ExprEmpty(); + } + virtual OwningExprResult ActOnCharacterConstant(const Token &) { + return ExprEmpty(); + } + virtual OwningExprResult ActOnNumericConstant(const Token &) { + return ExprEmpty(); + } + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + virtual OwningExprResult ActOnStringLiteral(const Token *Toks, + unsigned NumToks) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, + ExprArg Val) { + return move(Val); // Default impl returns operand. + } + + // Postfix Expressions. + virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, + ExprArg Input) { + return ExprEmpty(); + } + virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base, + SourceLocation LLoc, + ExprArg Idx, + SourceLocation RLoc) { + return ExprEmpty(); + } + virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + IdentifierInfo &Member, + DeclPtrTy ObjCImpDecl) { + return ExprEmpty(); + } + + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. + /// This provides the location of the left/right parens and a list of comma + /// locations. There are guaranteed to be one fewer commas than arguments, + /// unless there are zero arguments. + virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + + // Unary Operators. 'Tok' is the token for the operator. + virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg Input) { + return ExprEmpty(); + } + virtual OwningExprResult + ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, + void *TyOrEx, const SourceRange &ArgRange) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen, + ExprArg Op) { + return ExprEmpty(); + } + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, + MultiExprArg InitList, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + /// @brief Parsed a C99 designated initializer. + /// + /// @param Desig Contains the designation with one or more designators. + /// + /// @param Loc The location of the '=' or ':' prior to the + /// initialization expression. + /// + /// @param GNUSyntax If true, then this designated initializer used + /// the deprecated GNU syntax @c fieldname:foo or @c [expr]foo rather + /// than the C99 syntax @c .fieldname=foo or @c [expr]=foo. + /// + /// @param Init The value that the entity (or entities) described by + /// the designation will be initialized with. + virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig, + SourceLocation Loc, + bool GNUSyntax, + OwningExprResult Init) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprArg Op) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, + ExprArg LHS, ExprArg RHS) { + return ExprEmpty(); + } + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprArg Cond, ExprArg LHS, + ExprArg RHS) { + return ExprEmpty(); + } + + //===---------------------- GNU Extension Expressions -------------------===// + + virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc, + SourceLocation LabLoc, + IdentifierInfo *LabelII) { // "&&foo" + return ExprEmpty(); + } + + virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtArg SubStmt, + SourceLocation RPLoc) { // "({..})" + return ExprEmpty(); + } + + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + struct OffsetOfComponent { + SourceLocation LocStart, LocEnd; + bool isBrackets; // true if [expr], false if .ident + union { + IdentifierInfo *IdentInfo; + ExprTy *E; + } U; + }; + + virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *Arg1, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + + // __builtin_types_compatible_p(type1, type2) + virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1, TypeTy *arg2, + SourceLocation RPLoc) { + return ExprEmpty(); + } + // __builtin_choose_expr(constExpr, expr1, expr2) + virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + ExprArg cond, ExprArg expr1, + ExprArg expr2, SourceLocation RPLoc){ + return ExprEmpty(); + } + + // __builtin_va_arg(expr, type) + virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprArg expr, TypeTy *type, + SourceLocation RPLoc) { + return ExprEmpty(); + } + + /// ActOnGNUNullExpr - Parsed the GNU __null expression, the token + /// for which is at position TokenLoc. + virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) { + return ExprEmpty(); + } + + //===------------------------- "Block" Extension ------------------------===// + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. The result pointer is passed into the block finalizers. + virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {} + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {} + + /// ActOnBlockError - If there is an error parsing a block, this callback + /// is invoked to pop the information about the block from the action impl. + virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {} + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, + StmtArg Body, + Scope *CurScope) { + return ExprEmpty(); + } + + //===------------------------- C++ Declarations -------------------------===// + + /// ActOnStartNamespaceDef - This is called at the start of a namespace + /// definition. + virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace) { + return DeclPtrTy(); + } + + /// ActOnFinishNamespaceDef - This callback is called after a namespace is + /// exited. Decl is returned by ActOnStartNamespaceDef. + virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) { + return; + } + + /// ActOnUsingDirective - This is called when using-directive is parsed. + virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList); + + /// ActOnNamespaceAliasDef - This is called when a namespace alias definition + /// is parsed. + virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident) { + return DeclPtrTy(); + } + + /// ActOnParamDefaultArgument - Parse default argument for function parameter + virtual void ActOnParamDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc, + ExprArg defarg) { + } + + /// ActOnParamUnparsedDefaultArgument - We've seen a default + /// argument for a function parameter, but we can't parse it yet + /// because we're inside a class definition. Note that this default + /// argument will be parsed later. + virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc) { } + + /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of + /// the default argument for the parameter param failed. + virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { } + + /// AddCXXDirectInitializerToDecl - This action is called immediately after + /// ActOnDeclarator, when a C++ direct initializer is present. + /// e.g: "int x(1);" + virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return; + } + + /// \brief Called when we re-enter a template parameter scope. + /// + /// This action occurs when we are going to parse an member + /// function's default arguments or inline definition after the + /// outermost class definition has been completed, and when one or + /// more of the class definitions enclosing the member function is a + /// template. The "entity" in the given scope will be set as it was + /// when we entered the scope of the template initially, and should + /// be used to, e.g., reintroduce the names of template parameters + /// into the current scope so that they can be found by name lookup. + /// + /// \param S The (new) template parameter scope. + /// + /// \param Template the class template declaration whose template + /// parameters should be reintroduced into the current scope. + virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template) { + } + + /// ActOnStartDelayedCXXMethodDeclaration - We have completed + /// parsing a top-level (non-nested) C++ class, and we are now + /// parsing those parts of the given Method declaration that could + /// not be parsed earlier (C++ [class.mem]p2), such as default + /// arguments. This action should enter the scope of the given + /// Method declaration as if we had just parsed the qualified method + /// name. However, it should not bring the parameters into scope; + /// that will be performed by ActOnDelayedCXXMethodParameter. + virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method) { + } + + /// ActOnDelayedCXXMethodParameter - We've already started a delayed + /// C++ method declaration. We're (re-)introducing the given + /// function parameter into scope for use in parsing later parts of + /// the method declaration. For example, we could see an + /// ActOnParamDefaultArgument event for this parameter. + virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) { + } + + /// ActOnFinishDelayedCXXMethodDeclaration - We have finished + /// processing the delayed method declaration for Method. The method + /// declaration is now considered finished. There may be a separate + /// ActOnStartOfFunctionDef action later (not necessarily + /// immediately!) for this method, if it was also defined inside the + /// class body. + virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method) { + } + + /// ActOnStaticAssertDeclaration - Parse a C++0x static_assert declaration. + virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + ExprArg AssertExpr, + ExprArg AssertMessageExpr) { + return DeclPtrTy(); + } + + /// ActOnFriendDecl - This action is called when a friend declaration is + /// encountered. Returns false on success. + virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, + DeclPtrTy Dcl) { + return false; + } + + + //===------------------------- C++ Expressions --------------------------===// + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. + virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + ExprArg Op, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + + /// ActOnCXXTypeidOfType - Parse typeid( type-id ). + virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + + /// ActOnCXXThis - Parse the C++ 'this' pointer. + virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) { + return ExprEmpty(); + } + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, + tok::TokenKind Kind) { + return ExprEmpty(); + } + + /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. + virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc) { + return ExprEmpty(); + } + + /// ActOnCXXThrow - Parse throw expressions. + virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) { + return ExprEmpty(); + } + + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// 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()"). + virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, + TypeTy *TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return ExprEmpty(); + } + + /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a + /// C++ if/switch/while/for statement. + /// e.g: "if (int x = f()) {...}" + virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, + SourceLocation StartLoc, + Declarator &D, + SourceLocation EqualLoc, + ExprArg AssignExprVal) { + return ExprEmpty(); + } + + /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the + /// new was qualified (::new). In a full new like + /// @code new (p1, p2) type(c1, c2) @endcode + /// the p1 and p2 expressions will be in PlacementArgs and the c1 and c2 + /// expressions in ConstructorArgs. The type is passed as a declarator. + virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, Declarator &D, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) { + return ExprEmpty(); + } + + /// ActOnCXXDelete - Parsed a C++ 'delete' expression. UseGlobal is true if + /// the delete was qualified (::delete). ArrayForm is true if the array form + /// was used (delete[]). + virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + ExprArg Operand) { + return ExprEmpty(); + } + + virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen) { + return ExprEmpty(); + } + + + /// ActOnFinishFullExpr - Called whenever a full expression has been parsed. + /// (C++ [intro.execution]p12). + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr) { + return move(Expr); + } + + //===---------------------------- C++ Classes ---------------------------===// + /// ActOnBaseSpecifier - Parsed a base specifier + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeTy *basetype, + SourceLocation BaseLoc) { + return BaseResult(); + } + + virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, + unsigned NumBases) { + } + + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member + /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth' + /// specifies the bitfield width if there is one and 'Init' specifies the + /// initializer if any. 'Deleted' is true if there's a =delete + /// specifier on the function. + virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, + Declarator &D, + ExprTy *BitfieldWidth, + ExprTy *Init, + bool Deleted = false) { + return DeclPtrTy(); + } + + virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorDecl, + Scope *S, + IdentifierInfo *MemberOrBase, + SourceLocation IdLoc, + SourceLocation LParenLoc, + ExprTy **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return true; + } + + /// ActOnMemInitializers - This is invoked when all of the member + /// initializers of a constructor have been parsed. ConstructorDecl + /// is the function declaration (which will be a C++ constructor in + /// a well-formed program), ColonLoc is the location of the ':' that + /// starts the constructor initializer, and MemInit/NumMemInits + /// contains the individual member (and base) initializers. + virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, + SourceLocation ColonLoc, + MemInitTy **MemInits, unsigned NumMemInits){ + } + + /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators + /// are parsed but *before* parsing of inline method definitions. + virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, + DeclPtrTy TagDecl, + SourceLocation LBrac, + SourceLocation RBrac) { + } + + //===---------------------------C++ Templates----------------------------===// + + /// ActOnTypeParameter - Called when a C++ template type parameter + /// (e.g., "typename T") has been parsed. Typename specifies whether + /// the keyword "typename" was used to declare the type parameter + /// (otherwise, "class" was used), and KeyLoc is the location of the + /// "class" or "typename" keyword. ParamName is the name of the + /// parameter (NULL indicates an unnamed template parameter) and + /// ParamNameLoc is the location of the parameter name (if any). + /// If the type parameter has a default argument, it will be added + /// later via ActOnTypeParameterDefault. Depth and Position provide + /// the number of enclosing templates (see + /// ActOnTemplateParameterList) and the number of previous + /// parameters within this template parameter list. + virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position) { + return DeclPtrTy(); + } + + /// ActOnTypeParameterDefault - Adds a default argument (the type + /// Default) to the given template type parameter (TypeParam). + virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *Default) { + } + + /// ActOnNonTypeTemplateParameter - Called when a C++ non-type + /// template parameter (e.g., "int Size" in "template<int Size> + /// class Array") has been parsed. S is the current scope and D is + /// the parsed declarator. Depth and Position provide the number of + /// enclosing templates (see + /// ActOnTemplateParameterList) and the number of previous + /// parameters within this template parameter list. + virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position) { + return DeclPtrTy(); + } + + /// \brief Adds a default argument to the given non-type template + /// parameter. + virtual void ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParam, + SourceLocation EqualLoc, + ExprArg Default) { + } + + /// ActOnTemplateTemplateParameter - Called when a C++ template template + /// parameter (e.g., "int T" in "template<template <typename> class T> class + /// Array") has been parsed. TmpLoc is the location of the "template" keyword, + /// TemplateParams is the sequence of parameters required by the template, + /// ParamName is the name of the parameter (null if unnamed), and ParamNameLoc + /// is the source location of the identifier (if given). + virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S, + SourceLocation TmpLoc, + TemplateParamsTy *Params, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, + unsigned Position) { + return DeclPtrTy(); + } + + /// \brief Adds a default argument to the given template template + /// parameter. + virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, + SourceLocation EqualLoc, + ExprArg Default) { + } + + /// ActOnTemplateParameterList - Called when a complete template + /// parameter list has been parsed, e.g., + /// + /// @code + /// export template<typename T, T Size> + /// @endcode + /// + /// Depth is the number of enclosing template parameter lists. This + /// value does not include templates from outer scopes. For example: + /// + /// @code + /// template<typename T> // depth = 0 + /// class A { + /// template<typename U> // depth = 0 + /// class B; + /// }; + /// + /// template<typename T> // depth = 0 + /// template<typename U> // depth = 1 + /// class A<T>::B { ... }; + /// @endcode + /// + /// ExportLoc, if valid, is the position of the "export" + /// keyword. Otherwise, "export" was not specified. + /// TemplateLoc is the position of the template keyword, LAngleLoc + /// is the position of the left angle bracket, and RAngleLoc is the + /// position of the corresponding right angle bracket. + /// Params/NumParams provides the template parameters that were + /// parsed as part of the template-parameter-list. + virtual TemplateParamsTy * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclPtrTy *Params, unsigned NumParams, + SourceLocation RAngleLoc) { + return 0; + } + + /// \brief Process the declaration or definition of a class template + /// with the given template parameter lists. + virtual DeclResult + ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists, + AccessSpecifier AS) { + return DeclResult(); + } + + /// \brief Form a type from a template and a list of template + /// arguments. + /// + /// This action merely forms the type for the template-id, possibly + /// checking well-formedness of the template arguments. It does not + /// imply the declaration of any entity. + /// + /// \param Template A template whose specialization results in a + /// type, e.g., a class template or template template parameter. + /// + /// \param IsSpecialization true when we are naming the class + /// template specialization as part of an explicit class + /// specialization or class template partial specialization. + virtual TypeResult ActOnTemplateIdType(TemplateTy Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + return TypeResult(); + }; + + /// \brief Form a dependent template name. + /// + /// This action forms a dependent template name given the template + /// name and its (presumably dependent) scope specifier. For + /// example, given "MetaFun::template apply", the scope specifier \p + /// SS will be "MetaFun::", \p TemplateKWLoc contains the location + /// of the "template" keyword, and "apply" is the \p Name. + virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, + const IdentifierInfo &Name, + SourceLocation NameLoc, + const CXXScopeSpec &SS) { + return TemplateTy(); + } + + /// \brief Process the declaration or definition of an explicit + /// class template specialization or a class template partial + /// specialization. + /// + /// This routine is invoked when an explicit class template + /// specialization or a class template partial specialization is + /// declared or defined, to introduce the (partial) specialization + /// and produce a declaration for it. In the following example, + /// ActOnClassTemplateSpecialization will be invoked for the + /// declarations at both A and B: + /// + /// \code + /// template<typename T> class X; + /// template<> class X<int> { }; // A: explicit specialization + /// template<typename T> class X<T*> { }; // B: partial specialization + /// \endcode + /// + /// Note that it is the job of semantic analysis to determine which + /// of the two cases actually occurred in the source code, since + /// they are parsed through the same path. The formulation of the + /// template parameter lists describes which case we are in. + /// + /// \param S the current scope + /// + /// \param TagSpec whether this declares a class, struct, or union + /// (template) + /// + /// \param TK whether this is a declaration or a definition + /// + /// \param KWLoc the location of the 'class', 'struct', or 'union' + /// keyword. + /// + /// \param SS the scope specifier preceding the template-id + /// + /// \param Template the declaration of the class template that we + /// are specializing. + /// + /// \param Attr attributes on the specialization + /// + /// \param TemplateParameterLists the set of template parameter + /// lists that apply to this declaration. In a well-formed program, + /// the number of template parameter lists will be one more than the + /// number of template-ids in the scope specifier. However, it is + /// common for users to provide the wrong number of template + /// parameter lists (such as a missing \c template<> prior to a + /// specialization); the parser does not check this condition. + virtual DeclResult + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists) { + return DeclResult(); + } + + /// \brief Process the explicit instantiation of a class template + /// specialization. + /// + /// This routine is invoked when an explicit instantiation of a + /// class template specialization is encountered. In the following + /// example, ActOnExplicitInstantiation will be invoked to force the + /// instantiation of X<int>: + /// + /// \code + /// template<typename T> class X { /* ... */ }; + /// template class X<int>; // explicit instantiation + /// \endcode + /// + /// \param S the current scope + /// + /// \param TemplateLoc the location of the 'template' keyword that + /// specifies that this is an explicit instantiation. + /// + /// \param TagSpec whether this declares a class, struct, or union + /// (template). + /// + /// \param KWLoc the location of the 'class', 'struct', or 'union' + /// keyword. + /// + /// \param SS the scope specifier preceding the template-id. + /// + /// \param Template the declaration of the class template that we + /// are instantiation. + /// + /// \param LAngleLoc the location of the '<' token in the template-id. + /// + /// \param TemplateArgs the template arguments used to form the + /// template-id. + /// + /// \param TemplateArgLocs the locations of the template arguments. + /// + /// \param RAngleLoc the location of the '>' token in the template-id. + /// + /// \param Attr attributes that apply to this instantiation. + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr) { + return DeclResult(); + } + + /// \brief Process the explicit instantiation of a member class of a + /// class template specialization. + /// + /// This routine is invoked when an explicit instantiation of a + /// member class of a class template specialization is + /// encountered. In the following example, + /// ActOnExplicitInstantiation will be invoked to force the + /// instantiation of X<int>::Inner: + /// + /// \code + /// template<typename T> class X { class Inner { /* ... */}; }; + /// template class X<int>::Inner; // explicit instantiation + /// \endcode + /// + /// \param S the current scope + /// + /// \param TemplateLoc the location of the 'template' keyword that + /// specifies that this is an explicit instantiation. + /// + /// \param TagSpec whether this declares a class, struct, or union + /// (template). + /// + /// \param KWLoc the location of the 'class', 'struct', or 'union' + /// keyword. + /// + /// \param SS the scope specifier preceding the template-id. + /// + /// \param Template the declaration of the class template that we + /// are instantiation. + /// + /// \param LAngleLoc the location of the '<' token in the template-id. + /// + /// \param TemplateArgs the template arguments used to form the + /// template-id. + /// + /// \param TemplateArgLocs the locations of the template arguments. + /// + /// \param RAngleLoc the location of the '>' token in the template-id. + /// + /// \param Attr attributes that apply to this instantiation. + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + AttributeList *Attr) { + return DeclResult(); + } + + /// \brief Called when the parser has parsed a C++ typename + /// specifier that ends in an identifier, e.g., "typename T::type". + /// + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + virtual TypeResult + ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc) { + return TypeResult(); + } + + /// \brief Called when the parser has parsed a C++ typename + /// specifier that ends in a template-id, e.g., + /// "typename MetaFun::template apply<T1, T2>". + /// + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \param Ty the type that the typename specifier refers to. + virtual TypeResult + ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + SourceLocation TemplateLoc, TypeTy *Ty) { + return TypeResult(); + } + + //===----------------------- Obj-C Declarations -------------------------===// + + // ActOnStartClassInterface - this action is called immediately after parsing + // the prologue for a class interface (before parsing the instance + // variables). Instance variables are processed by ActOnFields(). + virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList) { + return DeclPtrTy(); + } + + /// ActOnCompatiblityAlias - this action is called after complete parsing of + /// @compaatibility_alias declaration. It sets up the alias relationships. + virtual DeclPtrTy ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation) { + return DeclPtrTy(); + } + + // ActOnStartProtocolInterface - this action is called immdiately after + // parsing the prologue for a protocol interface. + virtual DeclPtrTy ActOnStartProtocolInterface(SourceLocation AtProtoLoc, + IdentifierInfo *ProtocolName, + SourceLocation ProtocolLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList) { + return DeclPtrTy(); + } + // ActOnStartCategoryInterface - this action is called immdiately after + // parsing the prologue for a category interface. + virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CategoryName, + SourceLocation CategoryLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + return DeclPtrTy(); + } + // ActOnStartClassImplementation - this action is called immdiately after + // parsing the prologue for a class implementation. Instance variables are + // processed by ActOnFields(). + virtual DeclPtrTy ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc) { + return DeclPtrTy(); + } + // ActOnStartCategoryImplementation - this action is called immdiately after + // parsing the prologue for a category implementation. + virtual DeclPtrTy ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CatName, + SourceLocation CatLoc) { + return DeclPtrTy(); + } + // ActOnPropertyImplDecl - called for every property implementation + virtual DeclPtrTy ActOnPropertyImplDecl( + SourceLocation AtLoc, // location of the @synthesize/@dynamic + SourceLocation PropertyNameLoc, // location for the property name + bool ImplKind, // true for @synthesize, false for + // @dynamic + DeclPtrTy ClassImplDecl, // class or category implementation + IdentifierInfo *propertyId, // name of property + IdentifierInfo *propertyIvar) { // name of the ivar + return DeclPtrTy(); + } + + struct ObjCArgInfo { + IdentifierInfo *Name; + SourceLocation NameLoc; + // The Type is null if no type was specified, and the DeclSpec is invalid + // in this case. + TypeTy *Type; + ObjCDeclSpec DeclSpec; + + /// ArgAttrs - Attribute list for this argument. + AttributeList *ArgAttrs; + }; + + // ActOnMethodDeclaration - called for all method declarations. + virtual DeclPtrTy ActOnMethodDeclaration( + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, // tok::minus for instance, tok::plus for class. + DeclPtrTy ClassDecl, // class this methods belongs to. + ObjCDeclSpec &ReturnQT, // for return type's in inout etc. + TypeTy *ReturnType, // the method return type. + Selector Sel, // a unique name for the method. + ObjCArgInfo *ArgInfo, // ArgInfo: Has 'Sel.getNumArgs()' entries. + llvm::SmallVectorImpl<Declarator> &Cdecls, // c-style args + AttributeList *MethodAttrList, // optional + // tok::objc_not_keyword, tok::objc_optional, tok::objc_required + tok::ObjCKeywordKind impKind, + bool isVariadic = false) { + return DeclPtrTy(); + } + // ActOnAtEnd - called to mark the @end. For declarations (interfaces, + // protocols, categories), the parser passes all methods/properties. + // For class implementations, these values default to 0. For implementations, + // methods are processed incrementally (by ActOnMethodDeclaration above). + virtual void ActOnAtEnd(SourceLocation AtEndLoc, + DeclPtrTy classDecl, + DeclPtrTy *allMethods = 0, + unsigned allNum = 0, + DeclPtrTy *allProperties = 0, + unsigned pNum = 0, + DeclGroupPtrTy *allTUVars = 0, + unsigned tuvNum = 0) { + } + // ActOnProperty - called to build one property AST + virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, ObjCDeclSpec &ODS, + Selector GetterSel, Selector SetterSel, + DeclPtrTy ClassCategory, + bool *OverridingProperty, + tok::ObjCKeywordKind MethodImplKind) { + return DeclPtrTy(); + } + + virtual OwningExprResult ActOnClassPropertyRefExpr( + IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation &receiverNameLoc, + SourceLocation &propertyNameLoc) { + return ExprEmpty(); + } + + // ActOnClassMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnClassMessage( + Scope *S, + IdentifierInfo *receivingClassName, + Selector Sel, + SourceLocation lbrac, SourceLocation receiverLoc, + SourceLocation selectorLoc, + SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs) { + return ExprResult(); + } + // ActOnInstanceMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnInstanceMessage( + ExprTy *receiver, Selector Sel, + SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs) { + return ExprResult(); + } + virtual DeclPtrTy ActOnForwardClassDeclaration( + SourceLocation AtClassLoc, + IdentifierInfo **IdentList, + unsigned NumElts) { + return DeclPtrTy(); + } + virtual DeclPtrTy ActOnForwardProtocolDeclaration( + SourceLocation AtProtocolLoc, + const IdentifierLocPair*IdentList, + unsigned NumElts, + AttributeList *AttrList) { + return DeclPtrTy(); + } + + /// FindProtocolDeclaration - This routine looks up protocols and + /// issues error if they are not declared. It returns list of valid + /// protocols found. + virtual void FindProtocolDeclaration(bool WarnOnDeclarations, + const IdentifierLocPair *ProtocolId, + unsigned NumProtocols, + llvm::SmallVectorImpl<DeclPtrTy> &ResProtos) { + } + + //===----------------------- Obj-C Expressions --------------------------===// + + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings) { + return ExprResult(); + } + + virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncLoc, + SourceLocation LParenLoc, + TypeTy *Ty, + SourceLocation RParenLoc) { + return ExprResult(); + } + + virtual ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return ExprResult(); + } + + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return ExprResult(); + } + + //===---------------------------- Pragmas -------------------------------===// + + enum PragmaPackKind { + PPK_Default, // #pragma pack([n]) + PPK_Show, // #pragma pack(show), only supported by MSVC. + PPK_Push, // #pragma pack(push, [identifier], [n]) + PPK_Pop // #pragma pack(pop, [identifier], [n]) + }; + + /// ActOnPragmaPack - Called on well formed #pragma pack(...). + virtual void ActOnPragmaPack(PragmaPackKind Kind, + IdentifierInfo *Name, + ExprTy *Alignment, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return; + } + + /// ActOnPragmaPack - Called on well formed #pragma pack(...). + virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return; + } +}; + +/// MinimalAction - Minimal actions are used by light-weight clients of the +/// parser that do not need name resolution or significant semantic analysis to +/// be performed. The actions implemented here are in the form of unresolved +/// identifiers. By using a simpler interface than the SemanticAction class, +/// the parser doesn't have to build complex data structures and thus runs more +/// quickly. +class MinimalAction : public Action { + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + IdentifierTable &Idents; + Preprocessor &PP; + void *TypeNameInfoTablePtr; +public: + MinimalAction(Preprocessor &pp); + ~MinimalAction(); + + /// getTypeName - This looks at the IdentifierInfo::FETokenInfo field to + /// determine whether the name is a typedef or not in this scope. + virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec *SS); + + /// isCurrentClassName - Always returns false, because MinimalAction + /// does not support C++ classes with constructors. + virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S, + const CXXScopeSpec *SS); + + virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + TemplateTy &Template, + const CXXScopeSpec *SS = 0); + + /// ActOnDeclarator - If this is a typedef declarator, we modify the + /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is + /// popped. + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D); + + /// ActOnPopScope - When a scope is popped, if any typedefs are now + /// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field. + virtual void ActOnPopScope(SourceLocation Loc, Scope *S); + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); + + virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, + unsigned NumElts); + + virtual DeclPtrTy ActOnStartClassInterface(SourceLocation interLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); +}; + +/// PrettyStackTraceActionsDecl - If a crash occurs in the parser while parsing +/// something related to a virtualized decl, include that virtualized decl in +/// the stack trace. +class PrettyStackTraceActionsDecl : public llvm::PrettyStackTraceEntry { + Action::DeclPtrTy TheDecl; + SourceLocation Loc; + Action &Actions; + SourceManager &SM; + const char *Message; +public: + PrettyStackTraceActionsDecl(Action::DeclPtrTy Decl, SourceLocation L, + Action &actions, SourceManager &sm, + const char *Msg) + : TheDecl(Decl), Loc(L), Actions(actions), SM(sm), Message(Msg) {} + + virtual void print(llvm::raw_ostream &OS) const; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h new file mode 100644 index 000000000000..8225c9d33abb --- /dev/null +++ b/include/clang/Parse/AttributeList.h @@ -0,0 +1,173 @@ +//===--- AttributeList.h ----------------------------------------*- 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 AttributeList class interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ATTRLIST_H +#define LLVM_CLANG_ATTRLIST_H + +#include "clang/Parse/Ownership.h" +#include "clang/Basic/SourceLocation.h" +#include <cassert> + +namespace clang { + class IdentifierInfo; + class Action; + +/// AttributeList - Represents GCC's __attribute__ declaration. There are +/// 4 forms of this construct...they are: +/// +/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused. +/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused. +/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used. +/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. +/// +class AttributeList { + IdentifierInfo *AttrName; + SourceLocation AttrLoc; + IdentifierInfo *ParmName; + SourceLocation ParmLoc; + ActionBase::ExprTy **Args; + unsigned NumArgs; + AttributeList *Next; + AttributeList(const AttributeList &); // DO NOT IMPLEMENT + void operator=(const AttributeList &); // DO NOT IMPLEMENT +public: + AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ParmName, SourceLocation ParmLoc, + ActionBase::ExprTy **args, unsigned numargs, + AttributeList *Next); + ~AttributeList(); + + enum Kind { // Please keep this list alphabetized. + AT_IBOutlet, // Clang-specific. + AT_address_space, + AT_alias, + AT_aligned, + AT_always_inline, + AT_analyzer_noreturn, + AT_annotate, + AT_blocks, + AT_cleanup, + AT_const, + AT_constructor, + AT_deprecated, + AT_destructor, + AT_dllexport, + AT_dllimport, + AT_ext_vector_type, + AT_fastcall, + AT_format, + AT_format_arg, + AT_gnu_inline, + AT_mode, + AT_nodebug, + AT_noinline, + AT_no_instrument_function, + AT_nonnull, + AT_noreturn, + AT_nothrow, + AT_nsobject, + AT_objc_exception, + AT_cf_returns_retained, // Clang-specific. + AT_ns_returns_retained, // Clang-specific. + AT_objc_gc, + AT_overloadable, // Clang-specific. + AT_packed, + AT_pure, + AT_regparm, + AT_section, + AT_sentinel, + AT_stdcall, + AT_transparent_union, + AT_unavailable, + AT_unused, + AT_used, + AT_vector_size, + AT_visibility, + AT_warn_unused_result, + AT_weak, + AT_weak_import, + IgnoredAttribute, + UnknownAttribute + }; + + IdentifierInfo *getName() const { return AttrName; } + SourceLocation getLoc() const { return AttrLoc; } + IdentifierInfo *getParameterName() const { return ParmName; } + + Kind getKind() const { return getKind(getName()); } + static Kind getKind(const IdentifierInfo *Name); + + AttributeList *getNext() const { return Next; } + void setNext(AttributeList *N) { Next = N; } + + void addAttributeList(AttributeList *alist) { + assert((alist != 0) && "addAttributeList(): alist is null"); + AttributeList *next = this, *prev; + do { + prev = next; + next = next->getNext(); + } while (next); + prev->setNext(alist); + } + + /// getNumArgs - Return the number of actual arguments to this attribute. + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + ActionBase::ExprTy *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return Args[Arg]; + } + + class arg_iterator { + ActionBase::ExprTy** X; + unsigned Idx; + public: + arg_iterator(ActionBase::ExprTy** x, unsigned idx) : X(x), Idx(idx) {} + + arg_iterator& operator++() { + ++Idx; + return *this; + } + + bool operator==(const arg_iterator& I) const { + assert (X == I.X && + "compared arg_iterators are for different argument lists"); + return Idx == I.Idx; + } + + bool operator!=(const arg_iterator& I) const { + return !operator==(I); + } + + ActionBase::ExprTy* operator*() const { + return X[Idx]; + } + + unsigned getArgNum() const { + return Idx+1; + } + }; + + arg_iterator arg_begin() const { + return arg_iterator(Args, 0); + } + + arg_iterator arg_end() const { + return arg_iterator(Args, NumArgs); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h new file mode 100644 index 000000000000..a0b9b1e7cc23 --- /dev/null +++ b/include/clang/Parse/DeclSpec.h @@ -0,0 +1,1086 @@ +//===--- SemaDeclSpec.h - Declaration Specifier Semantic Analys -*- 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 interfaces used for Declaration Specifiers and Declarators. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_DECLSPEC_H +#define LLVM_CLANG_PARSE_DECLSPEC_H + +#include "clang/Parse/AttributeList.h" +#include "clang/Lex/Token.h" +#include "clang/Basic/OperatorKinds.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class LangOptions; + class Diagnostic; + class IdentifierInfo; + class Preprocessor; + class Declarator; + +/// DeclSpec - This class captures information about "declaration specifiers", +/// which encompasses storage-class-specifiers, type-specifiers, +/// type-qualifiers, and function-specifiers. +class DeclSpec { +public: + // storage-class-specifier + enum SCS { + SCS_unspecified, + SCS_typedef, + SCS_extern, + SCS_static, + SCS_auto, + SCS_register, + SCS_private_extern, + SCS_mutable + }; + + // type-specifier + enum TSW { + TSW_unspecified, + TSW_short, + TSW_long, + TSW_longlong + }; + + enum TSC { + TSC_unspecified, + TSC_imaginary, + TSC_complex + }; + + enum TSS { + TSS_unspecified, + TSS_signed, + TSS_unsigned + }; + + enum TST { + TST_unspecified, + TST_void, + TST_char, + TST_wchar, // C++ wchar_t + TST_int, + TST_float, + TST_double, + TST_bool, // _Bool + TST_decimal32, // _Decimal32 + TST_decimal64, // _Decimal64 + TST_decimal128, // _Decimal128 + TST_enum, + TST_union, + TST_struct, + TST_class, // C++ class type + TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_typeofType, + TST_typeofExpr, + TST_error // erroneous type + }; + + // type-qualifiers + enum TQ { // NOTE: These flags must be kept in sync with QualType::TQ. + TQ_unspecified = 0, + TQ_const = 1, + TQ_restrict = 2, + TQ_volatile = 4 + }; + + /// ParsedSpecifiers - Flags to query which specifiers were applied. This is + /// returned by getParsedSpecifiers. + enum ParsedSpecifiers { + PQ_None = 0, + PQ_StorageClassSpecifier = 1, + PQ_TypeSpecifier = 2, + PQ_TypeQualifier = 4, + PQ_FunctionSpecifier = 8 + }; + +private: + + // storage-class-specifier + /*SCS*/unsigned StorageClassSpec : 3; + bool SCS_thread_specified : 1; + + // type-specifier + /*TSW*/unsigned TypeSpecWidth : 2; + /*TSC*/unsigned TypeSpecComplex : 2; + /*TSS*/unsigned TypeSpecSign : 2; + /*TST*/unsigned TypeSpecType : 5; + bool 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; + + // friend-specifier + bool Friend_specified : 1; + + /// TypeRep - This contains action-specific information about a specific TST. + /// For example, for a typedef or struct, it might contain the declaration for + /// these. + void *TypeRep; + + // attributes. + AttributeList *AttrList; + + // List of protocol qualifiers for objective-c classes. Used for + // protocol-qualified interfaces "NString<foo>" and protocol-qualified id + // "id<foo>". + const ActionBase::DeclPtrTy *ProtocolQualifiers; + unsigned NumProtocolQualifiers; + + // SourceLocation info. These are null if the item wasn't specified or if + // the setting was synthesized. + SourceRange Range; + + SourceLocation StorageClassSpecLoc, SCS_threadLoc; + SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; + SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; + SourceLocation FriendLoc; + + bool BadSpecifier(TST T, const char *&PrevSpec); + bool BadSpecifier(TQ T, const char *&PrevSpec); + bool BadSpecifier(TSS T, const char *&PrevSpec); + bool BadSpecifier(TSC T, const char *&PrevSpec); + bool BadSpecifier(TSW T, const char *&PrevSpec); + bool BadSpecifier(SCS T, const char *&PrevSpec); + + DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT + void operator=(const DeclSpec&); // DO NOT IMPLEMENT +public: + + DeclSpec() + : StorageClassSpec(SCS_unspecified), + SCS_thread_specified(false), + TypeSpecWidth(TSW_unspecified), + TypeSpecComplex(TSC_unspecified), + TypeSpecSign(TSS_unspecified), + TypeSpecType(TST_unspecified), + TypeSpecOwned(false), + TypeQualifiers(TSS_unspecified), + FS_inline_specified(false), + FS_virtual_specified(false), + FS_explicit_specified(false), + Friend_specified(false), + TypeRep(0), + AttrList(0), + ProtocolQualifiers(0), + NumProtocolQualifiers(0) { + } + ~DeclSpec() { + delete AttrList; + delete [] ProtocolQualifiers; + } + // storage-class-specifier + SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } + bool isThreadSpecified() const { return SCS_thread_specified; } + + SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } + SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; } + + void ClearStorageClassSpecs() { + StorageClassSpec = DeclSpec::SCS_unspecified; + SCS_thread_specified = false; + StorageClassSpecLoc = SourceLocation(); + SCS_threadLoc = SourceLocation(); + } + + // type-specifier + TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; } + TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } + TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; } + TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool isTypeSpecOwned() const { return TypeSpecOwned; } + void *getTypeRep() const { return TypeRep; } + + const SourceRange &getSourceRange() const { return Range; } + SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } + SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } + SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } + SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + + /// getSpecifierName - Turn a type-specifier-type into a string like "_Bool" + /// or "union". + static const char *getSpecifierName(DeclSpec::TST T); + static const char *getSpecifierName(DeclSpec::SCS S); + + // type-qualifiers + + /// getTypeQualifiers - Return a set of TQs. + unsigned getTypeQualifiers() const { return TypeQualifiers; } + SourceLocation getConstSpecLoc() const { return TQ_constLoc; } + SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } + SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } + + // function-specifier + bool isInlineSpecified() const { return FS_inline_specified; } + SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; } + + bool isVirtualSpecified() const { return FS_virtual_specified; } + SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } + + bool isExplicitSpecified() const { return FS_explicit_specified; } + SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + + void ClearFunctionSpecs() { + FS_inline_specified = false; + FS_inlineLoc = SourceLocation(); + FS_virtual_specified = false; + FS_virtualLoc = SourceLocation(); + FS_explicit_specified = false; + FS_explicitLoc = SourceLocation(); + } + + /// hasTypeSpecifier - Return true if any type-specifier has been found. + bool hasTypeSpecifier() const { + return getTypeSpecType() != DeclSpec::TST_unspecified || + getTypeSpecWidth() != DeclSpec::TSW_unspecified || + getTypeSpecComplex() != DeclSpec::TSC_unspecified || + getTypeSpecSign() != DeclSpec::TSS_unspecified; + } + + /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this + /// DeclSpec includes. + /// + unsigned getParsedSpecifiers() const; + + /// isEmpty - Return true if this declaration specifier is completely empty: + /// no tokens were parsed in the production of it. + bool isEmpty() const { + return getParsedSpecifiers() == DeclSpec::PQ_None; + } + + void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } + void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } + + /// These methods set the specified attribute of the DeclSpec, but return true + /// and ignore the request if invalid (e.g. "extern" then "auto" is + /// specified). The name of the previous specifier is returned in prevspec. + bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec); + bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + void *Rep = 0, bool Owned = false); + bool SetTypeSpecError(); + + bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + const LangOptions &Lang); + + bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec); + bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec); + bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec); + + bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec); + bool isFriendSpecified() const { return Friend_specified; } + SourceLocation getFriendSpecLoc() const { return FriendLoc; } + + /// AddAttributes - contatenates two attribute lists. + /// The GCC attribute syntax allows for the following: + /// + /// short __attribute__(( unused, deprecated )) + /// int __attribute__(( may_alias, aligned(16) )) var; + /// + /// This declares 4 attributes using 2 lists. The following syntax is + /// also allowed and equivalent to the previous declaration. + /// + /// short __attribute__((unused)) __attribute__((deprecated)) + /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; + /// + void AddAttributes(AttributeList *alist) { + if (!alist) + return; // we parsed __attribute__(()) or had a syntax error + + if (AttrList) + alist->addAttributeList(AttrList); + AttrList = alist; + } + void SetAttributes(AttributeList *AL) { AttrList = AL; } + const AttributeList *getAttributes() const { return AttrList; } + AttributeList *getAttributes() { return AttrList; } + + /// TakeAttributes - Return the current attribute list and remove them from + /// the DeclSpec so that it doesn't own them. + AttributeList *TakeAttributes() { + AttributeList *AL = AttrList; + AttrList = 0; + return AL; + } + + typedef const ActionBase::DeclPtrTy *ProtocolQualifierListTy; + ProtocolQualifierListTy getProtocolQualifiers() const { + return ProtocolQualifiers; + } + unsigned getNumProtocolQualifiers() const { + return NumProtocolQualifiers; + } + void setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP) { + if (NP == 0) return; + ProtocolQualifiers = new ActionBase::DeclPtrTy[NP]; + memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP); + NumProtocolQualifiers = NP; + } + + /// Finish - This does final analysis of the declspec, issuing diagnostics for + /// things like "_Imaginary" (lacking an FP type). After calling this method, + /// DeclSpec is guaranteed self-consistent, even if an error occurred. + void Finish(Diagnostic &D, Preprocessor &PP); + + /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, + /// without a Declarator. Only tag declspecs can stand alone. + bool isMissingDeclaratorOk(); +}; + +/// ObjCDeclSpec - This class captures information about +/// "declaration specifiers" specific to objective-c +class ObjCDeclSpec { +public: + /// ObjCDeclQualifier - Qualifier used on types in method declarations + enum ObjCDeclQualifier { + DQ_None = 0x0, + DQ_In = 0x1, + DQ_Inout = 0x2, + DQ_Out = 0x4, + DQ_Bycopy = 0x8, + DQ_Byref = 0x10, + DQ_Oneway = 0x20 + }; + + /// PropertyAttributeKind - list of property attributes. + enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0, + DQ_PR_readonly = 0x01, + DQ_PR_getter = 0x02, + DQ_PR_assign = 0x04, + DQ_PR_readwrite = 0x08, + DQ_PR_retain = 0x10, + DQ_PR_copy = 0x20, + DQ_PR_nonatomic = 0x40, + DQ_PR_setter = 0x80 + }; + + + ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), + GetterName(0), SetterName(0) + {} + ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) + { objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); } + + ObjCPropertyAttributeKind getPropertyAttributes() const + { return ObjCPropertyAttributeKind(PropertyAttributes); } + void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { + PropertyAttributes = + (ObjCPropertyAttributeKind) (PropertyAttributes | PRVal); + } + + const IdentifierInfo *getGetterName() const { return GetterName; } + IdentifierInfo *getGetterName() { return GetterName; } + void setGetterName(IdentifierInfo *name) { GetterName = name; } + + const IdentifierInfo *getSetterName() const { return SetterName; } + IdentifierInfo *getSetterName() { return SetterName; } + void setSetterName(IdentifierInfo *name) { SetterName = name; } +private: + // FIXME: These two are unrelated and mutially exclusive. So perhaps + // we can put them in a union to reflect their mutual exclusiveness + // (space saving is negligible). + ObjCDeclQualifier objcDeclQualifier : 6; + + // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind + unsigned PropertyAttributes : 8; + IdentifierInfo *GetterName; // getter name of NULL if no getter + IdentifierInfo *SetterName; // setter name of NULL if no setter +}; + +/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope +/// specifier. +class CXXScopeSpec { + SourceRange Range; + void *ScopeRep; + +public: + CXXScopeSpec() : Range(), ScopeRep() { } + + const SourceRange &getRange() const { return Range; } + void setRange(const SourceRange &R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; } + void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; } + + bool isEmpty() const { return !Range.isValid(); } + bool isNotEmpty() const { return !isEmpty(); } + + /// isInvalid - An error occured during parsing of the scope specifier. + bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } + + /// isSet - A scope specifier was resolved to a valid C++ scope. + bool isSet() const { return ScopeRep != 0; } + + void clear() { + Range = SourceRange(); + ScopeRep = 0; + } +}; + +/// CachedTokens - A set of tokens that has been cached for later +/// parsing. +typedef llvm::SmallVector<Token, 4> CachedTokens; + +/// DeclaratorChunk - One instance of this struct is used for each type in a +/// declarator that is parsed. +/// +/// This is intended to be a small value object. +struct DeclaratorChunk { + enum { + Pointer, Reference, Array, Function, BlockPointer, MemberPointer + } Kind; + + /// Loc - The place where this type was defined. + SourceLocation Loc; + + struct PointerTypeInfo { + /// The type qualifiers: const/volatile/restrict. + unsigned TypeQuals : 3; + AttributeList *AttrList; + void destroy() { + delete AttrList; + } + }; + + struct ReferenceTypeInfo { + /// 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 { + /// The type qualifiers for the array: const/volatile/restrict. + unsigned TypeQuals : 3; + + /// True if this dimension included the 'static' keyword. + bool hasStatic : 1; + + /// True if this dimension was [*]. In this case, NumElts is null. + bool isStar : 1; + + /// This is the size of the array, or null if [] or [*] was specified. + /// Since the parser is multi-purpose, and we don't want to impose a root + /// expression class on all clients, NumElts is untyped. + ActionBase::ExprTy *NumElts; + void destroy() {} + }; + + /// ParamInfo - An array of paraminfo objects is allocated whenever a function + /// declarator is parsed. There are two interesting styles of arguments here: + /// K&R-style identifier lists and parameter type lists. K&R-style identifier + /// lists will have information about the identifier, but no type information. + /// Parameter type lists will have type info (if the actions module provides + /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. + struct ParamInfo { + IdentifierInfo *Ident; + SourceLocation IdentLoc; + ActionBase::DeclPtrTy Param; + + /// DefaultArgTokens - When the parameter's default argument + /// cannot be parsed immediately (because it occurs within the + /// declaration of a member function), it will be stored here as a + /// sequence of tokens to be parsed once the class definition is + /// complete. Non-NULL indicates that there is a default argument. + CachedTokens *DefaultArgTokens; + + ParamInfo() {} + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, + ActionBase::DeclPtrTy param, + CachedTokens *DefArgTokens = 0) + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(DefArgTokens) {} + }; + + struct TypeAndRange { + ActionBase::TypeTy *Ty; + SourceRange Range; + }; + + struct FunctionTypeInfo { + /// 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; + + /// 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; + + /// 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; + + /// hasAnyExceptionSpec - True if the function has a throw(...) specifier. + bool hasAnyExceptionSpec : 1; + + /// DeleteArgInfo - If this is true, we need to delete[] ArgInfo. + bool DeleteArgInfo : 1; + + /// When isVariadic is true, the location of the ellipsis in the source. + unsigned EllipsisLoc; + + /// NumArgs - This is the number of formal arguments provided for the + /// declarator. + unsigned NumArgs; + + /// NumExceptions - This is the number of types in the exception-decl, if + /// the function has one. + unsigned NumExceptions; + + /// ThrowLoc - When hasExceptionSpec is true, the location of the throw + /// keyword introducing the spec. + unsigned ThrowLoc; + + /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that + /// describe the arguments for this function declarator. This is null if + /// there are no arguments specified. + ParamInfo *ArgInfo; + + /// Exceptions - This is a pointer to a new[]'d array of TypeAndRange + /// objects that contain the types in the function's exception + /// specification and their locations. + TypeAndRange *Exceptions; + + /// freeArgs - reset the argument list to having zero arguments. This is + /// used in various places for error recovery. + void freeArgs() { + if (DeleteArgInfo) { + delete[] ArgInfo; + DeleteArgInfo = false; + } + NumArgs = 0; + } + + void destroy() { + if (DeleteArgInfo) + delete[] ArgInfo; + delete[] Exceptions; + } + + SourceLocation getEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(EllipsisLoc); + } + SourceLocation getThrowLoc() const { + return SourceLocation::getFromRawEncoding(ThrowLoc); + } + }; + + struct BlockPointerTypeInfo { + /// 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 { + /// 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 { + void *Aligner; + char Mem[sizeof(CXXScopeSpec)]; + } ScopeMem; + CXXScopeSpec &Scope() { + return *reinterpret_cast<CXXScopeSpec*>(ScopeMem.Mem); + } + const CXXScopeSpec &Scope() const { + return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem); + } + void destroy() { + delete AttrList; + Scope().~CXXScopeSpec(); + } + }; + + union { + PointerTypeInfo Ptr; + ReferenceTypeInfo Ref; + ArrayTypeInfo Arr; + FunctionTypeInfo Fun; + BlockPointerTypeInfo Cls; + MemberPointerTypeInfo Mem; + }; + + void destroy() { + switch (Kind) { + default: assert(0 && "Unknown decl type!"); + case DeclaratorChunk::Function: return Fun.destroy(); + case DeclaratorChunk::Pointer: return Ptr.destroy(); + case DeclaratorChunk::BlockPointer: return Cls.destroy(); + case DeclaratorChunk::Reference: return Ref.destroy(); + case DeclaratorChunk::Array: return Arr.destroy(); + case DeclaratorChunk::MemberPointer: return Mem.destroy(); + } + } + + /// 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; + } + } + + + /// getPointer - Return a DeclaratorChunk for a pointer. + /// + static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, + AttributeList *AL) { + DeclaratorChunk I; + I.Kind = Pointer; + I.Loc = Loc; + I.Ptr.TypeQuals = TypeQuals; + I.Ptr.AttrList = AL; + return I; + } + + /// getReference - Return a DeclaratorChunk for a reference. + /// + static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, + AttributeList *AL, 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; + return I; + } + + /// getArray - Return a DeclaratorChunk for an array. + /// + static DeclaratorChunk getArray(unsigned TypeQuals, bool isStatic, + bool isStar, void *NumElts, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = Array; + I.Loc = Loc; + I.Arr.TypeQuals = TypeQuals; + I.Arr.hasStatic = isStatic; + I.Arr.isStar = isStar; + I.Arr.NumElts = NumElts; + return I; + } + + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. + /// "TheDeclarator" is the declarator that this will be added to. + static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, + SourceLocation EllipsisLoc, + ParamInfo *ArgInfo, unsigned NumArgs, + unsigned TypeQuals, bool hasExceptionSpec, + SourceLocation ThrowLoc, + bool hasAnyExceptionSpec, + ActionBase::TypeTy **Exceptions, + SourceRange *ExceptionRanges, + unsigned NumExceptions, SourceLocation Loc, + Declarator &TheDeclarator); + + /// getBlockPointer - Return a DeclaratorChunk for a block. + /// + static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc, + AttributeList *AL) { + DeclaratorChunk I; + I.Kind = BlockPointer; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + I.Cls.AttrList = AL; + return I; + } + + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, + unsigned TypeQuals, + SourceLocation Loc, + AttributeList *AL) { + DeclaratorChunk I; + I.Kind = MemberPointer; + I.Loc = Loc; + I.Mem.TypeQuals = TypeQuals; + I.Mem.AttrList = AL; + new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS); + return I; + } +}; + +/// Declarator - Information about one declarator, including the parsed type +/// information and the identifier. When the declarator is fully formed, this +/// is turned into the appropriate Decl object. +/// +/// Declarators come in two types: normal declarators and abstract declarators. +/// Abstract declarators are used when parsing types, and don't have an +/// identifier. Normal declarators do have ID's. +/// +/// Instances of this class should be a transient object that lives on the +/// stack, not objects that are allocated in large quantities on the heap. +class Declarator { +public: + enum TheContext { + FileContext, // File scope declaration. + PrototypeContext, // Within a function prototype. + KNRTypeListContext, // K&R type definition list for formals. + TypeNameContext, // Abstract declarator for types. + MemberContext, // Struct/Union field. + BlockContext, // Declaration within a block in a function. + ForContext, // Declaration within first part of a for loop. + 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. + }; + + /// DeclaratorKind - The kind of declarator this represents. + enum DeclaratorKind { + DK_Abstract, // An abstract declarator (has no identifier) + DK_Normal, // A normal declarator (has an identifier). + DK_Constructor, // A C++ constructor (identifier is the class name) + DK_Destructor, // A C++ destructor (identifier is ~class name) + DK_Operator, // A C++ overloaded operator name + DK_Conversion // A C++ conversion function (identifier is + // "operator " then the type name) + }; + +private: + const DeclSpec &DS; + CXXScopeSpec SS; + IdentifierInfo *Identifier; + SourceLocation IdentifierLoc; + SourceRange Range; + + /// Context - Where we are parsing this declarator. + /// + TheContext Context; + + /// Kind - What kind of declarator this is. + DeclaratorKind Kind; + + /// DeclTypeInfo - This holds each type that the declarator includes as it is + /// parsed. This is pushed from the identifier out, which means that element + /// #0 will be the most closely bound to the identifier, and + /// DeclTypeInfo.back() will be the least closely bound. + llvm::SmallVector<DeclaratorChunk, 8> DeclTypeInfo; + + /// InvalidType - Set by Sema::GetTypeForDeclarator(). + bool InvalidType : 1; + + /// GroupingParens - Set by Parser::ParseParenDeclarator(). + bool GroupingParens : 1; + + /// AttrList - Attributes. + AttributeList *AttrList; + + /// AsmLabel - The asm label, if specified. + ActionBase::ExprTy *AsmLabel; + + union { + // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the + // type associated with the constructor, destructor, or conversion + // operator. + ActionBase::TypeTy *Type; + + /// When Kind is DK_Operator, this is the actual overloaded + /// operator that this declarator names. + OverloadedOperatorKind OperatorKind; + }; + + /// InlineParams - This is a local array used for the first function decl + /// chunk to avoid going to the heap for the common case when we have one + /// function chunk in the declarator. + DeclaratorChunk::ParamInfo InlineParams[16]; + bool InlineParamsUsed; + + friend struct DeclaratorChunk; + +public: + Declarator(const DeclSpec &ds, TheContext C) + : DS(ds), Identifier(0), Range(ds.getSourceRange()), Context(C), + Kind(DK_Abstract), + InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), + GroupingParens(false), AttrList(0), AsmLabel(0), Type(0), + InlineParamsUsed(false) { + } + + ~Declarator() { + clear(); + } + + /// getDeclSpec - Return the declaration-specifier that this declarator was + /// declared with. + const DeclSpec &getDeclSpec() const { return DS; } + + /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This + /// should be used with extreme care: declspecs can often be shared between + /// multiple declarators, so mutating the DeclSpec affects all of the + /// Declarators. This should only be done when the declspec is known to not + /// be shared or when in error recovery etc. + DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); } + + /// getCXXScopeSpec - Return the C++ scope specifier (global scope or + /// nested-name-specifier) that is part of the declarator-id. + const CXXScopeSpec &getCXXScopeSpec() const { return SS; } + CXXScopeSpec &getCXXScopeSpec() { return SS; } + + TheContext getContext() const { return Context; } + DeclaratorKind getKind() const { return Kind; } + + /// getSourceRange - Get the source range that spans this declarator. + const SourceRange &getSourceRange() const { return Range; } + + void SetSourceRange(SourceRange R) { Range = R; } + /// SetRangeBegin - Set the start of the source range to Loc, unless it's + /// invalid. + void SetRangeBegin(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setBegin(Loc); + } + /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid. + void SetRangeEnd(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setEnd(Loc); + } + /// ExtendWithDeclSpec - Extend the declarator source range to include the + /// given declspec, unless its location is invalid. Adopts the range start if + /// the current range start is invalid. + void ExtendWithDeclSpec(const DeclSpec &DS) { + const SourceRange &SR = DS.getSourceRange(); + if (Range.getBegin().isInvalid()) + Range.setBegin(SR.getBegin()); + if (!SR.getEnd().isInvalid()) + Range.setEnd(SR.getEnd()); + } + + /// clear - Reset the contents of this Declarator. + void clear() { + SS.clear(); + Identifier = 0; + IdentifierLoc = SourceLocation(); + Range = DS.getSourceRange(); + Kind = DK_Abstract; + + for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) + DeclTypeInfo[i].destroy(); + DeclTypeInfo.clear(); + delete AttrList; + AttrList = 0; + AsmLabel = 0; + Type = 0; + InlineParamsUsed = false; + } + + /// mayOmitIdentifier - Return true if the identifier is either optional or + /// not allowed. This is true for typenames, prototypes, and template + /// parameter lists. + bool mayOmitIdentifier() const { + return Context == TypeNameContext || Context == PrototypeContext || + Context == TemplateParamContext || Context == CXXCatchContext || + Context == BlockLiteralContext; + } + + /// 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; + } + + /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be + /// followed by a C++ direct initializer, e.g. "int x(1);". + bool mayBeFollowedByCXXDirectInit() const { + return !hasGroupingParens() && + (Context == FileContext || + Context == BlockContext || + Context == ForContext); + } + + /// isPastIdentifier - Return true if we have parsed beyond the point where + /// the + bool isPastIdentifier() const { return IdentifierLoc.isValid(); } + + /// hasName - Whether this declarator has a name, which might be an + /// identifier (accessible via getIdentifier()) or some kind of + /// special C++ name (constructor, destructor, etc.). + bool hasName() const { return getKind() != DK_Abstract; } + + IdentifierInfo *getIdentifier() const { return Identifier; } + SourceLocation getIdentifierLoc() const { return IdentifierLoc; } + + void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) { + Identifier = ID; + IdentifierLoc = Loc; + if (ID) + Kind = DK_Normal; + else + Kind = DK_Abstract; + SetRangeEnd(Loc); + } + + /// setConstructor - Set this declarator to be a C++ constructor + /// declarator. Also extends the range. + void setConstructor(ActionBase::TypeTy *Ty, SourceLocation Loc) { + IdentifierLoc = Loc; + Kind = DK_Constructor; + Type = Ty; + SetRangeEnd(Loc); + } + + /// setDestructor - Set this declarator to be a C++ destructor + /// declarator. Also extends the range to End, which should be the identifier + /// token. + void setDestructor(ActionBase::TypeTy *Ty, SourceLocation Loc, + SourceLocation EndLoc) { + IdentifierLoc = Loc; + Kind = DK_Destructor; + Type = Ty; + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// setConversionFunction - Set this declarator to be a C++ + /// conversion function declarator (e.g., @c operator int const *). + /// Also extends the range to EndLoc, which should be the last token of the + /// type name. + void setConversionFunction(ActionBase::TypeTy *Ty, SourceLocation Loc, + SourceLocation EndLoc) { + Identifier = 0; + IdentifierLoc = Loc; + Kind = DK_Conversion; + Type = Ty; + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// setOverloadedOperator - Set this declaration to be a C++ + /// overloaded operator declarator (e.g., @c operator+). + /// Also extends the range to EndLoc, which should be the last token of the + /// operator. + void setOverloadedOperator(OverloadedOperatorKind Op, SourceLocation Loc, + SourceLocation EndLoc) { + IdentifierLoc = Loc; + Kind = DK_Operator; + OperatorKind = Op; + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to + /// EndLoc, which should be the last token of the chunk. + void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { + DeclTypeInfo.push_back(TI); + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// getNumTypeObjects() - Return the number of types applied to this + /// declarator. + unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } + + /// Return the specified TypeInfo from this declarator. TypeInfo #0 is + /// closest to the identifier. + const DeclaratorChunk &getTypeObject(unsigned i) const { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + DeclaratorChunk &getTypeObject(unsigned i) { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, + /// this method returns true if the identifier is a function declarator. + bool isFunctionDeclarator() const { + return !DeclTypeInfo.empty() && + DeclTypeInfo[0].Kind == DeclaratorChunk::Function; + } + + /// AddAttributes - simply adds the attribute list to the Declarator. + /// These examples both add 3 attributes to "var": + /// short int var __attribute__((aligned(16),common,deprecated)); + /// short int x, __attribute__((aligned(16)) var + /// __attribute__((common,deprecated)); + /// + /// Also extends the range of the declarator. + void AddAttributes(AttributeList *alist, SourceLocation LastLoc) { + if (!alist) + return; // we parsed __attribute__(()) or had a syntax error + + if (AttrList) + alist->addAttributeList(AttrList); + AttrList = alist; + + if (!LastLoc.isInvalid()) + SetRangeEnd(LastLoc); + } + + const AttributeList *getAttributes() const { return AttrList; } + AttributeList *getAttributes() { return AttrList; } + + void setAsmLabel(ActionBase::ExprTy *E) { AsmLabel = E; } + ActionBase::ExprTy *getAsmLabel() const { return AsmLabel; } + + ActionBase::TypeTy *getDeclaratorIdType() const { return Type; } + + OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; } + + void setInvalidType(bool Val = true) { InvalidType = Val; } + bool isInvalidType() const { + return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; + } + + void setGroupingParens(bool flag) { GroupingParens = flag; } + bool hasGroupingParens() const { return GroupingParens; } +}; + +/// FieldDeclarator - This little struct is used to capture information about +/// structure field declarators, which is basically just a bitfield size. +struct FieldDeclarator { + Declarator D; + ActionBase::ExprTy *BitfieldSize; + explicit FieldDeclarator(DeclSpec &DS) : D(DS, Declarator::MemberContext) { + BitfieldSize = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Designator.h b/include/clang/Parse/Designator.h new file mode 100644 index 000000000000..026286d318fb --- /dev/null +++ b/include/clang/Parse/Designator.h @@ -0,0 +1,239 @@ +//===--- Designator.h - Initialization Designator ---------------*- 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 interfaces used to represent Designators in the parser and +// is the input to Actions module. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_DESIGNATOR_H +#define LLVM_CLANG_PARSE_DESIGNATOR_H + +#include "clang/Parse/Action.h" + +namespace clang { + +/// Designator - This class is a discriminated union which holds the various +/// different sorts of designators possible. A Designation is an array of +/// these. An example of a designator are things like this: +/// [8] .field [47] // C99 designation: 3 designators +/// [8 ... 47] field: // GNU extensions: 2 designators +/// These occur in initializers, e.g.: +/// int a[10] = {2, 4, [8]=9, 10}; +/// +class Designator { +public: + enum DesignatorKind { + FieldDesignator, ArrayDesignator, ArrayRangeDesignator + }; +private: + DesignatorKind Kind; + + struct FieldDesignatorInfo { + const IdentifierInfo *II; + unsigned DotLoc; + unsigned NameLoc; + }; + struct ArrayDesignatorInfo { + ActionBase::ExprTy *Index; + unsigned LBracketLoc; + mutable unsigned RBracketLoc; + }; + struct ArrayRangeDesignatorInfo { + ActionBase::ExprTy *Start, *End; + unsigned LBracketLoc, EllipsisLoc; + mutable unsigned RBracketLoc; + }; + + union { + FieldDesignatorInfo FieldInfo; + ArrayDesignatorInfo ArrayInfo; + ArrayRangeDesignatorInfo ArrayRangeInfo; + }; + +public: + + DesignatorKind getKind() const { return Kind; } + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + const IdentifierInfo *getField() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.II; + } + + SourceLocation getDotLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc); + } + + ActionBase::ExprTy *getArrayIndex() const { + assert(isArrayDesignator() && "Invalid accessor"); + return ArrayInfo.Index; + } + + ActionBase::ExprTy *getArrayRangeStart() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.Start; + } + ActionBase::ExprTy *getArrayRangeEnd() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.End; + } + + SourceLocation getLBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc); + } + + static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc, + SourceLocation NameLoc) { + Designator D; + D.Kind = FieldDesignator; + D.FieldInfo.II = II; + D.FieldInfo.DotLoc = DotLoc.getRawEncoding(); + D.FieldInfo.NameLoc = NameLoc.getRawEncoding(); + return D; + } + + static Designator getArray(ActionBase::ExprTy *Index, + SourceLocation LBracketLoc) { + Designator D; + D.Kind = ArrayDesignator; + D.ArrayInfo.Index = Index; + D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayInfo.RBracketLoc = 0; + return D; + } + + static Designator getArrayRange(ActionBase::ExprTy *Start, + ActionBase::ExprTy *End, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc) { + Designator D; + D.Kind = ArrayRangeDesignator; + D.ArrayRangeInfo.Start = Start; + D.ArrayRangeInfo.End = End; + D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding(); + D.ArrayRangeInfo.RBracketLoc = 0; + return D; + } + + void setRBracketLoc(SourceLocation RBracketLoc) const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + else + ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Action &Actions) { + switch (Kind) { + case FieldDesignator: return; + case ArrayDesignator: + ArrayInfo.Index = 0; + return; + case ArrayRangeDesignator: + ArrayRangeInfo.Start = 0; + ArrayRangeInfo.End = 0; + return; + } + } + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designator. + void FreeExprs(Action &Actions) { + switch (Kind) { + case FieldDesignator: return; // nothing to free. + case ArrayDesignator: + Actions.DeleteExpr(getArrayIndex()); + return; + case ArrayRangeDesignator: + Actions.DeleteExpr(getArrayRangeStart()); + Actions.DeleteExpr(getArrayRangeEnd()); + return; + } + } +}; + + +/// Designation - Represent a full designation, which is a sequence of +/// designators. This class is mostly a helper for InitListDesignations. +class Designation { + /// InitIndex - The index of the initializer expression this is for. For + /// example, if the initializer were "{ A, .foo=B, C }" a Designation would + /// exist with InitIndex=1, because element #1 has a designation. + unsigned InitIndex; + + /// Designators - The actual designators for this initializer. + llvm::SmallVector<Designator, 2> Designators; + + Designation(unsigned Idx) : InitIndex(Idx) {} +public: + Designation() : InitIndex(4000) {} + + /// AddDesignator - Add a designator to the end of this list. + void AddDesignator(Designator D) { + Designators.push_back(D); + } + + bool empty() const { return Designators.empty(); } + + unsigned getNumDesignators() const { return Designators.size(); } + const Designator &getDesignator(unsigned Idx) const { + assert(Idx < Designators.size()); + return Designators[Idx]; + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Action &Actions) { + for (unsigned i = 0, e = Designators.size(); i != e; ++i) + Designators[i].ClearExprs(Actions); + } + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designation. + void FreeExprs(Action &Actions) { + for (unsigned i = 0, e = Designators.size(); i != e; ++i) + Designators[i].FreeExprs(Actions); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h new file mode 100644 index 000000000000..59517930de95 --- /dev/null +++ b/include/clang/Parse/Ownership.h @@ -0,0 +1,830 @@ +//===--- Ownership.h - Parser Ownership Helpers -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains classes for managing ownership of Stmt and Expr nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_OWNERSHIP_H +#define LLVM_CLANG_PARSE_OWNERSHIP_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/PointerIntPair.h" + +//===----------------------------------------------------------------------===// +// OpaquePtr +//===----------------------------------------------------------------------===// + +namespace clang { + class ActionBase; + + /// OpaquePtr - This is a very simple POD type that wraps a pointer that the + /// Parser doesn't know about but that Sema or another client does. The UID + /// template argument is used to make sure that "Decl" pointers are not + /// compatible with "Type" pointers for example. + template<int UID> + class OpaquePtr { + void *Ptr; + public: + OpaquePtr() : Ptr(0) {} + + template <typename T> + T* getAs() const { + return llvm::PointerLikeTypeTraits<T*>::getFromVoidPointer(Ptr); + } + + template <typename T> + T getAsVal() const { + return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(Ptr); + } + + void *get() const { return Ptr; } + + template<typename T> + static OpaquePtr make(T P) { + OpaquePtr R; R.set(P); return R; + } + + template<typename T> + void set(T P) { + Ptr = llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(P); + } + + operator bool() const { return Ptr != 0; } + }; +} + +namespace llvm { + template <int UID> + class PointerLikeTypeTraits<clang::OpaquePtr<UID> > { + public: + static inline void *getAsVoidPointer(clang::OpaquePtr<UID> P) { + // FIXME: Doesn't work? return P.getAs< void >(); + return P.get(); + } + static inline clang::OpaquePtr<UID> getFromVoidPointer(void *P) { + return clang::OpaquePtr<UID>::make(P); + } + enum { NumLowBitsAvailable = 3 }; + }; +} + + + +// -------------------------- About Move Emulation -------------------------- // +// The smart pointer classes in this file attempt to emulate move semantics +// as they appear in C++0x with rvalue references. Since C++03 doesn't have +// rvalue references, some tricks are needed to get similar results. +// Move semantics in C++0x have the following properties: +// 1) "Moving" means transferring the value of an object to another object, +// similar to copying, but without caring what happens to the old object. +// In particular, this means that the new object can steal the old object's +// resources instead of creating a copy. +// 2) Since moving can modify the source object, it must either be explicitly +// requested by the user, or the modifications must be unnoticeable. +// 3) As such, C++0x moving is only allowed in three contexts: +// * By explicitly using std::move() to request it. +// * From a temporary object, since that object cannot be accessed +// afterwards anyway, thus making the state unobservable. +// * On function return, since the object is not observable afterwards. +// +// To sum up: moving from a named object should only be possible with an +// explicit std::move(), or on function return. Moving from a temporary should +// be implicitly done. Moving from a const object is forbidden. +// +// The emulation is not perfect, and has the following shortcomings: +// * move() is not in namespace std. +// * move() is required on function return. +// * There are difficulties with implicit conversions. +// * Microsoft's compiler must be given the /Za switch to successfully compile. +// +// -------------------------- Implementation -------------------------------- // +// The move emulation relies on the peculiar reference binding semantics of +// C++03: as a rule, a non-const reference may not bind to a temporary object, +// except for the implicit object parameter in a member function call, which +// can refer to a temporary even when not being const. +// The moveable object has five important functions to facilitate moving: +// * A private, unimplemented constructor taking a non-const reference to its +// own class. This constructor serves a two-fold purpose. +// - It prevents the creation of a copy constructor that takes a const +// reference. Temporaries would be able to bind to the argument of such a +// constructor, and that would be bad. +// - Named objects will bind to the non-const reference, but since it's +// private, this will fail to compile. This prevents implicit moving from +// named objects. +// There's also a copy assignment operator for the same purpose. +// * An implicit, non-const conversion operator to a special mover type. This +// type represents the rvalue reference of C++0x. Being a non-const member, +// its implicit this parameter can bind to temporaries. +// * A constructor that takes an object of this mover type. This constructor +// performs the actual move operation. There is an equivalent assignment +// operator. +// There is also a free move() function that takes a non-const reference to +// an object and returns a temporary. Internally, this function uses explicit +// constructor calls to move the value from the referenced object to the return +// value. +// +// There are now three possible scenarios of use. +// * Copying from a const object. Constructor overload resolution will find the +// non-const copy constructor, and the move constructor. The first is not +// viable because the const object cannot be bound to the non-const reference. +// The second fails because the conversion to the mover object is non-const. +// Moving from a const object fails as intended. +// * Copying from a named object. Constructor overload resolution will select +// the non-const copy constructor, but fail as intended, because this +// constructor is private. +// * Copying from a temporary. Constructor overload resolution cannot select +// the non-const copy constructor, because the temporary cannot be bound to +// the non-const reference. It thus selects the move constructor. The +// temporary can be bound to the implicit this parameter of the conversion +// operator, because of the special binding rule. Construction succeeds. +// Note that the Microsoft compiler, as an extension, allows binding +// temporaries against non-const references. The compiler thus selects the +// non-const copy constructor and fails, because the constructor is private. +// Passing /Za (disable extensions) disables this behaviour. +// The free move() function is used to move from a named object. +// +// Note that when passing an object of a different type (the classes below +// have OwningResult and OwningPtr, which should be mixable), you get a problem. +// Argument passing and function return use copy initialization rules. The +// effect of this is that, when the source object is not already of the target +// type, the compiler will first seek a way to convert the source object to the +// target type, and only then attempt to copy the resulting object. This means +// that when passing an OwningResult where an OwningPtr is expected, the +// compiler will first seek a conversion from OwningResult to OwningPtr, then +// copy the OwningPtr. The resulting conversion sequence is: +// OwningResult object -> ResultMover -> OwningResult argument to +// OwningPtr(OwningResult) -> OwningPtr -> PtrMover -> final OwningPtr +// This conversion sequence is too complex to be allowed. Thus the special +// move_* functions, which help the compiler out with some explicit +// conversions. + +// Flip this switch to measure performance impact of the smart pointers. +//#define DISABLE_SMART_POINTERS + +namespace llvm { + template<> + class PointerLikeTypeTraits<clang::ActionBase*> { + typedef clang::ActionBase* PT; + public: + static inline void *getAsVoidPointer(PT P) { return P; } + static inline PT getFromVoidPointer(void *P) { + return static_cast<PT>(P); + } + enum { NumLowBitsAvailable = 2 }; + }; +} + +namespace clang { + // Basic + class DiagnosticBuilder; + + // Determines whether the low bit of the result pointer for the + // given UID is always zero. If so, ActionResult will use that bit + // for it's "invalid" flag. + template<unsigned UID> + struct IsResultPtrLowBitFree { + static const bool value = false; + }; + + /// ActionBase - A small part split from Action because of the horrible + /// definition order dependencies between Action and the smart pointers. + class ActionBase { + public: + /// Out-of-line virtual destructor to provide home for this class. + virtual ~ActionBase(); + + // Types - Though these don't actually enforce strong typing, they document + // what types are required to be identical for the actions. + typedef OpaquePtr<0> DeclPtrTy; + typedef OpaquePtr<1> DeclGroupPtrTy; + typedef OpaquePtr<2> TemplateTy; + typedef void AttrTy; + typedef void BaseTy; + typedef void MemInitTy; + typedef void ExprTy; + typedef void StmtTy; + typedef void TemplateParamsTy; + typedef void CXXScopeTy; + typedef void TypeTy; // FIXME: Change TypeTy to use OpaquePtr<N>. + + /// ActionResult - This structure is used while parsing/acting on + /// expressions, stmts, etc. It encapsulates both the object returned by + /// the action, plus a sense of whether or not it is valid. + /// When CompressInvalid is true, the "invalid" flag will be + /// stored in the low bit of the Val pointer. + template<unsigned UID, + typename PtrTy = void*, + bool CompressInvalid = IsResultPtrLowBitFree<UID>::value> + class ActionResult { + PtrTy Val; + bool Invalid; + + public: + ActionResult(bool Invalid = false) : Val(PtrTy()), Invalid(Invalid) {} + template<typename ActualExprTy> + ActionResult(ActualExprTy val) : Val(val), Invalid(false) {} + ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {} + + PtrTy get() const { return Val; } + void set(PtrTy V) { Val = V; } + bool isInvalid() const { return Invalid; } + + const ActionResult &operator=(PtrTy RHS) { + Val = RHS; + Invalid = false; + return *this; + } + }; + + // This ActionResult partial specialization places the "invalid" + // flag into the low bit of the pointer. + template<unsigned UID, typename PtrTy> + class ActionResult<UID, PtrTy, true> { + // A pointer whose low bit is 1 if this result is invalid, 0 + // otherwise. + uintptr_t PtrWithInvalid; + typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits; + public: + ActionResult(bool Invalid = false) + : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { } + + template<typename ActualExprTy> + ActionResult(ActualExprTy *val) { + PtrTy V(val); + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + ActionResult(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { } + + PtrTy get() const { + void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); + return PtrTraits::getFromVoidPointer(VP); + } + + void set(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + bool isInvalid() const { return PtrWithInvalid & 0x01; } + + const ActionResult &operator=(PtrTy RHS) { + void *VP = PtrTraits::getAsVoidPointer(RHS); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + return *this; + } + }; + + /// Deletion callbacks - Since the parser doesn't know the concrete types of + /// the AST nodes being generated, it must do callbacks to delete objects + /// when recovering from errors. These are in ActionBase because the smart + /// pointers need access to them. + virtual void DeleteExpr(ExprTy *E) {} + virtual void DeleteStmt(StmtTy *S) {} + virtual void DeleteTemplateParams(TemplateParamsTy *P) {} + }; + + /// ASTDestroyer - The type of an AST node destruction function pointer. + typedef void (ActionBase::*ASTDestroyer)(void *); + + /// For the transition phase: translate from an ASTDestroyer to its + /// ActionResult UID. + template <ASTDestroyer Destroyer> struct DestroyerToUID; + template <> struct DestroyerToUID<&ActionBase::DeleteExpr> { + static const unsigned UID = 0; + }; + template <> struct DestroyerToUID<&ActionBase::DeleteStmt> { + static const unsigned UID = 1; + }; + /// ASTOwningResult - A moveable smart pointer for AST nodes that also + /// has an extra flag to indicate an additional success status. + template <ASTDestroyer Destroyer> class ASTOwningResult; + + /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns + /// the individual pointers, not the array holding them. + template <ASTDestroyer Destroyer> class ASTMultiPtr; + +#if !defined(DISABLE_SMART_POINTERS) + namespace moving { + /// Move emulation helper for ASTOwningResult. NEVER EVER use this class + /// directly if you don't know what you're doing. + template <ASTDestroyer Destroyer> + class ASTResultMover + { + ASTOwningResult<Destroyer> &Moved; + + public: + ASTResultMover(ASTOwningResult<Destroyer> &moved) : Moved(moved) {} + + ASTOwningResult<Destroyer> * operator ->() { return &Moved; } + }; + + /// Move emulation helper for ASTMultiPtr. NEVER EVER use this class + /// directly if you don't know what you're doing. + template <ASTDestroyer Destroyer> + class ASTMultiMover + { + ASTMultiPtr<Destroyer> &Moved; + + public: + ASTMultiMover(ASTMultiPtr<Destroyer> &moved) : Moved(moved) {} + + ASTMultiPtr<Destroyer> * operator ->() { return &Moved; } + + /// Reset the moved object's internal structures. + void release(); + }; + } +#else + + /// Kept only as a type-safe wrapper for a void pointer, when smart pointers + /// are disabled. When they are enabled, ASTOwningResult takes over. + template <ASTDestroyer Destroyer> + class ASTOwningPtr + { + void *Node; + + public: + explicit ASTOwningPtr(ActionBase &) : Node(0) {} + ASTOwningPtr(ActionBase &, void *node) : Node(node) {} + // Normal copying operators are defined implicitly. + ASTOwningPtr(const ASTOwningResult<Destroyer> &o); + + ASTOwningPtr & operator =(void *raw) { + Node = raw; + return *this; + } + + /// Access to the raw pointer. + void * get() const { return Node; } + + /// Release the raw pointer. + void * take() { + return Node; + } + + /// Take outside ownership of the raw pointer and cast it down. + template<typename T> + T *takeAs() { + return static_cast<T*>(Node); + } + + /// Alias for interface familiarity with unique_ptr. + void * release() { + return take(); + } + }; +#endif + + // Important: There are two different implementations of + // ASTOwningResult below, depending on whether + // DISABLE_SMART_POINTERS is defined. If you make changes that + // affect the interface, be sure to compile and test both ways! + +#if !defined(DISABLE_SMART_POINTERS) + template <ASTDestroyer Destroyer> + class ASTOwningResult + { + llvm::PointerIntPair<ActionBase*, 1, bool> ActionInv; + void *Ptr; + + friend class moving::ASTResultMover<Destroyer>; + + ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT + ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT + + void destroy() { + if (Ptr) { + assert(ActionInv.getPointer() && + "Smart pointer has node but no action."); + (ActionInv.getPointer()->*Destroyer)(Ptr); + Ptr = 0; + } + } + + public: + typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult; + + explicit ASTOwningResult(ActionBase &actions, bool invalid = false) + : ActionInv(&actions, invalid), Ptr(0) {} + ASTOwningResult(ActionBase &actions, void *node) + : ActionInv(&actions, false), Ptr(node) {} + ASTOwningResult(ActionBase &actions, const DumbResult &res) + : ActionInv(&actions, res.isInvalid()), Ptr(res.get()) {} + /// Move from another owning result + ASTOwningResult(moving::ASTResultMover<Destroyer> mover) + : ActionInv(mover->ActionInv), + Ptr(mover->Ptr) { + mover->Ptr = 0; + } + + ~ASTOwningResult() { + destroy(); + } + + /// Move assignment from another owning result + ASTOwningResult &operator=(moving::ASTResultMover<Destroyer> mover) { + destroy(); + ActionInv = mover->ActionInv; + Ptr = mover->Ptr; + mover->Ptr = 0; + return *this; + } + + /// Assignment from a raw pointer. Takes ownership - beware! + ASTOwningResult &operator=(void *raw) { + destroy(); + Ptr = raw; + ActionInv.setInt(false); + return *this; + } + + /// Assignment from an ActionResult. Takes ownership - beware! + ASTOwningResult &operator=(const DumbResult &res) { + destroy(); + Ptr = res.get(); + ActionInv.setInt(res.isInvalid()); + return *this; + } + + /// Access to the raw pointer. + void *get() const { return Ptr; } + + bool isInvalid() const { return ActionInv.getInt(); } + + /// Does this point to a usable AST node? To be usable, the node must be + /// valid and non-null. + bool isUsable() const { return !isInvalid() && get(); } + + /// Take outside ownership of the raw pointer. + void *take() { + if (isInvalid()) + return 0; + void *tmp = Ptr; + Ptr = 0; + return tmp; + } + + /// Take outside ownership of the raw pointer and cast it down. + template<typename T> + T *takeAs() { + return static_cast<T*>(take()); + } + + /// Alias for interface familiarity with unique_ptr. + void *release() { return take(); } + + /// Pass ownership to a classical ActionResult. + DumbResult result() { + if (isInvalid()) + return true; + return take(); + } + + /// Move hook + operator moving::ASTResultMover<Destroyer>() { + return moving::ASTResultMover<Destroyer>(*this); + } + }; +#else + template <ASTDestroyer Destroyer> + class ASTOwningResult + { + public: + typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult; + + private: + DumbResult Result; + + public: + explicit ASTOwningResult(ActionBase &actions, bool invalid = false) + : Result(invalid) { } + ASTOwningResult(ActionBase &actions, void *node) : Result(node) { } + ASTOwningResult(ActionBase &actions, const DumbResult &res) : Result(res) { } + // Normal copying semantics are defined implicitly. + ASTOwningResult(const ASTOwningPtr<Destroyer> &o) : Result(o.get()) { } + + /// Assignment from a raw pointer. Takes ownership - beware! + ASTOwningResult & operator =(void *raw) + { + Result = raw; + return *this; + } + + /// Assignment from an ActionResult. Takes ownership - beware! + ASTOwningResult & operator =(const DumbResult &res) { + Result = res; + return *this; + } + + /// Access to the raw pointer. + void * get() const { return Result.get(); } + + bool isInvalid() const { return Result.isInvalid(); } + + /// Does this point to a usable AST node? To be usable, the node must be + /// valid and non-null. + bool isUsable() const { return !Result.isInvalid() && get(); } + + /// Take outside ownership of the raw pointer. + void * take() { + return Result.get(); + } + + /// Take outside ownership of the raw pointer and cast it down. + template<typename T> + T *takeAs() { + return static_cast<T*>(take()); + } + + /// Alias for interface familiarity with unique_ptr. + void * release() { return take(); } + + /// Pass ownership to a classical ActionResult. + DumbResult result() { return Result; } + }; +#endif + + template <ASTDestroyer Destroyer> + class ASTMultiPtr + { +#if !defined(DISABLE_SMART_POINTERS) + ActionBase &Actions; +#endif + void **Nodes; + unsigned Count; + +#if !defined(DISABLE_SMART_POINTERS) + friend class moving::ASTMultiMover<Destroyer>; + + ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT + // Reference member prevents copy assignment. + + void destroy() { + assert((Count == 0 || Nodes) && "No nodes when count is not zero."); + for (unsigned i = 0; i < Count; ++i) { + if (Nodes[i]) + (Actions.*Destroyer)(Nodes[i]); + } + } +#endif + + public: +#if !defined(DISABLE_SMART_POINTERS) + explicit ASTMultiPtr(ActionBase &actions) + : Actions(actions), Nodes(0), Count(0) {} + ASTMultiPtr(ActionBase &actions, void **nodes, unsigned count) + : Actions(actions), Nodes(nodes), Count(count) {} + /// Move constructor + ASTMultiPtr(moving::ASTMultiMover<Destroyer> mover) + : Actions(mover->Actions), Nodes(mover->Nodes), Count(mover->Count) { + mover.release(); + } +#else + // Normal copying implicitly defined + explicit ASTMultiPtr(ActionBase &) : Nodes(0), Count(0) {} + ASTMultiPtr(ActionBase &, void **nodes, unsigned count) + : Nodes(nodes), Count(count) {} + // Fake mover in Parse/AstGuard.h needs this: + ASTMultiPtr(void **nodes, unsigned count) : Nodes(nodes), Count(count) {} +#endif + +#if !defined(DISABLE_SMART_POINTERS) + /// Move assignment + ASTMultiPtr & operator =(moving::ASTMultiMover<Destroyer> mover) { + destroy(); + Nodes = mover->Nodes; + Count = mover->Count; + mover.release(); + return *this; + } +#endif + + /// Access to the raw pointers. + void ** get() const { return Nodes; } + + /// Access to the count. + unsigned size() const { return Count; } + + void ** release() { +#if !defined(DISABLE_SMART_POINTERS) + void **tmp = Nodes; + Nodes = 0; + Count = 0; + return tmp; +#else + return Nodes; +#endif + } + +#if !defined(DISABLE_SMART_POINTERS) + /// Move hook + operator moving::ASTMultiMover<Destroyer>() { + return moving::ASTMultiMover<Destroyer>(*this); + } +#endif + }; + + class ASTTemplateArgsPtr { +#if !defined(DISABLE_SMART_POINTERS) + ActionBase &Actions; +#endif + void **Args; + bool *ArgIsType; + mutable unsigned Count; + +#if !defined(DISABLE_SMART_POINTERS) + void destroy() { + if (!Count) + return; + + for (unsigned i = 0; i != Count; ++i) + if (Args[i] && !ArgIsType[i]) + Actions.DeleteExpr((ActionBase::ExprTy *)Args[i]); + + Count = 0; + } +#endif + + public: + ASTTemplateArgsPtr(ActionBase &actions, void **args, bool *argIsType, + unsigned count) : +#if !defined(DISABLE_SMART_POINTERS) + Actions(actions), +#endif + Args(args), ArgIsType(argIsType), Count(count) { } + + // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'. + ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) : +#if !defined(DISABLE_SMART_POINTERS) + Actions(Other.Actions), +#endif + Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) { +#if !defined(DISABLE_SMART_POINTERS) + Other.Count = 0; +#endif + } + + // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'. + ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) { +#if !defined(DISABLE_SMART_POINTERS) + Actions = Other.Actions; +#endif + Args = Other.Args; + ArgIsType = Other.ArgIsType; + Count = Other.Count; +#if !defined(DISABLE_SMART_POINTERS) + Other.Count = 0; +#endif + return *this; + } + +#if !defined(DISABLE_SMART_POINTERS) + ~ASTTemplateArgsPtr() { destroy(); } +#endif + + void **getArgs() const { return Args; } + bool *getArgIsType() const {return ArgIsType; } + unsigned size() const { return Count; } + + void reset(void **args, bool *argIsType, unsigned count) { +#if !defined(DISABLE_SMART_POINTERS) + destroy(); +#endif + Args = args; + ArgIsType = argIsType; + Count = count; + } + + void *operator[](unsigned Arg) const { return Args[Arg]; } + + void **release() const { +#if !defined(DISABLE_SMART_POINTERS) + Count = 0; +#endif + return Args; + } + }; + + /// \brief A small vector that owns a set of AST nodes. + template <ASTDestroyer Destroyer, unsigned N = 8> + class ASTOwningVector : public llvm::SmallVector<void *, N> { +#if !defined(DISABLE_SMART_POINTERS) + ActionBase &Actions; + bool Owned; +#endif + + ASTOwningVector(ASTOwningVector &); // do not implement + ASTOwningVector &operator=(ASTOwningVector &); // do not implement + + public: + explicit ASTOwningVector(ActionBase &Actions) +#if !defined(DISABLE_SMART_POINTERS) + : Actions(Actions), Owned(true) +#endif + { } + +#if !defined(DISABLE_SMART_POINTERS) + ~ASTOwningVector() { + if (!Owned) + return; + + for (unsigned I = 0, Last = this->size(); I != Last; ++I) + (Actions.*Destroyer)((*this)[I]); + } +#endif + + void **take() { +#if !defined(DISABLE_SMART_POINTERS) + Owned = false; +#endif + return &this->front(); + } + + template<typename T> T **takeAs() { return (T**)take(); } + +#if !defined(DISABLE_SMART_POINTERS) + ActionBase &getActions() const { return Actions; } +#endif + }; + + /// A SmallVector of statements, with stack size 32 (as that is the only one + /// used.) + typedef ASTOwningVector<&ActionBase::DeleteStmt, 32> StmtVector; + /// A SmallVector of expressions, with stack size 12 (the maximum used.) + typedef ASTOwningVector<&ActionBase::DeleteExpr, 12> ExprVector; + + template <ASTDestroyer Destroyer, unsigned N> inline + ASTMultiPtr<Destroyer> move_arg(ASTOwningVector<Destroyer, N> &vec) { +#if !defined(DISABLE_SMART_POINTERS) + return ASTMultiPtr<Destroyer>(vec.getActions(), vec.take(), vec.size()); +#else + return ASTMultiPtr<Destroyer>(vec.take(), vec.size()); +#endif + } + +#if !defined(DISABLE_SMART_POINTERS) + + // Out-of-line implementations due to definition dependencies + + template <ASTDestroyer Destroyer> inline + void moving::ASTMultiMover<Destroyer>::release() { + Moved.Nodes = 0; + Moved.Count = 0; + } + + // Move overloads. + + template <ASTDestroyer Destroyer> inline + ASTOwningResult<Destroyer> move(ASTOwningResult<Destroyer> &ptr) { + return ASTOwningResult<Destroyer>(moving::ASTResultMover<Destroyer>(ptr)); + } + + template <ASTDestroyer Destroyer> inline + ASTMultiPtr<Destroyer> move(ASTMultiPtr<Destroyer> &ptr) { + return ASTMultiPtr<Destroyer>(moving::ASTMultiMover<Destroyer>(ptr)); + } + +#else + + template <ASTDestroyer Destroyer> inline + ASTOwningPtr<Destroyer>::ASTOwningPtr(const ASTOwningResult<Destroyer> &o) + : Node(o.get()) + {} + + // These versions are hopefully no-ops. + template <ASTDestroyer Destroyer> inline + ASTOwningResult<Destroyer>& move(ASTOwningResult<Destroyer> &ptr) { + return ptr; + } + + template <ASTDestroyer Destroyer> inline + ASTOwningPtr<Destroyer>& move(ASTOwningPtr<Destroyer> &ptr) { + return ptr; + } + + template <ASTDestroyer Destroyer> inline + ASTMultiPtr<Destroyer>& move(ASTMultiPtr<Destroyer> &ptr) { + return ptr; + } +#endif +} + +#endif diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h new file mode 100644 index 000000000000..a85c6ad6ca7a --- /dev/null +++ b/include/clang/Parse/ParseDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticParse.h - Diagnostics for libparse -----------*- 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_DIAGNOSTICPARSE_H +#define LLVM_CLANG_DIAGNOSTICPARSE_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define PARSESTART +#include "clang/Basic/DiagnosticParseKinds.inc" +#undef DIAG + NUM_BUILTIN_PARSE_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h new file mode 100644 index 000000000000..26e37e2806a0 --- /dev/null +++ b/include/clang/Parse/Parser.h @@ -0,0 +1,1208 @@ +//===--- Parser.h - C Language Parser ---------------------------*- 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 Parser interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSER_H +#define LLVM_CLANG_PARSE_PARSER_H + +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/AccessSpecifier.h" +#include "clang/Parse/Action.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/ADT/OwningPtr.h" +#include <stack> +#include <list> + +namespace clang { + class AttributeList; + class PragmaHandler; + class Scope; + class DiagnosticBuilder; + class Parser; + class PragmaUnusedHandler; + +/// PrettyStackTraceParserEntry - If a crash happens while the parser is active, +/// an entry is printed for it. +class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { + const Parser &P; +public: + PrettyStackTraceParserEntry(const Parser &p) : P(p) {} + virtual void print(llvm::raw_ostream &OS) const; +}; + + +/// Parser - This implements a parser for the C family of languages. After +/// parsing units of the grammar, productions are invoked to handle whatever has +/// been read. +/// +class Parser { + friend class PragmaUnusedHandler; + PrettyStackTraceParserEntry CrashInfo; + + Preprocessor &PP; + + /// Tok - The current token we are peeking ahead. All parsing methods assume + /// that this is valid. + Token Tok; + + // PrevTokLocation - The location of the token we previously + // consumed. This token is used for diagnostics where we expected to + // see a token following another token (e.g., the ';' at the end of + // a statement). + SourceLocation PrevTokLocation; + + unsigned short ParenCount, BracketCount, BraceCount; + + /// Actions - These are the callbacks we invoke as we parse various constructs + /// in the file. This refers to the common base class between MinimalActions + /// and SemaActions for those uses that don't matter. + Action &Actions; + + Scope *CurScope; + Diagnostic &Diags; + + /// ScopeCache - Cache scopes to reduce malloc traffic. + enum { ScopeCacheSize = 16 }; + unsigned NumCachedScopes; + Scope *ScopeCache[ScopeCacheSize]; + + /// Ident_super - IdentifierInfo for "super", to support fast + /// comparison. + IdentifierInfo *Ident_super; + + llvm::OwningPtr<PragmaHandler> PackHandler; + llvm::OwningPtr<PragmaHandler> UnusedHandler; + + /// Whether the '>' token acts as an operator or not. This will be + /// true except when we are parsing an expression within a C++ + /// template argument list, where the '>' closes the template + /// argument list. + bool GreaterThanIsOperator; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + struct GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + +public: + Parser(Preprocessor &PP, Action &Actions); + ~Parser(); + + const LangOptions &getLang() const { return PP.getLangOptions(); } + TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } + Preprocessor &getPreprocessor() const { return PP; } + Action &getActions() const { return Actions; } + + const Token &getCurToken() const { return Tok; } + + // Type forwarding. All of these are statically 'void*', but they may all be + // different actual classes based on the actions in place. + typedef Action::ExprTy ExprTy; + typedef Action::StmtTy StmtTy; + typedef Action::DeclPtrTy DeclPtrTy; + typedef Action::DeclGroupPtrTy DeclGroupPtrTy; + typedef Action::TypeTy TypeTy; + typedef Action::BaseTy BaseTy; + typedef Action::MemInitTy MemInitTy; + typedef Action::CXXScopeTy CXXScopeTy; + typedef Action::TemplateParamsTy TemplateParamsTy; + typedef Action::TemplateTy TemplateTy; + + typedef llvm::SmallVector<TemplateParamsTy *, 4> TemplateParameterLists; + + typedef Action::ExprResult ExprResult; + typedef Action::StmtResult StmtResult; + typedef Action::BaseResult BaseResult; + typedef Action::MemInitResult MemInitResult; + typedef Action::TypeResult TypeResult; + + typedef Action::OwningExprResult OwningExprResult; + typedef Action::OwningStmtResult OwningStmtResult; + + typedef Action::ExprArg ExprArg; + typedef Action::MultiStmtArg MultiStmtArg; + typedef Action::FullExprArg FullExprArg; + + /// Adorns a ExprResult with Actions to make it an OwningExprResult + OwningExprResult Owned(ExprResult res) { + return OwningExprResult(Actions, res); + } + /// Adorns a StmtResult with Actions to make it an OwningStmtResult + OwningStmtResult Owned(StmtResult res) { + return OwningStmtResult(Actions, res); + } + + OwningExprResult ExprError() { return OwningExprResult(Actions, true); } + OwningStmtResult StmtError() { return OwningStmtResult(Actions, true); } + + OwningExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); } + OwningStmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); } + + OwningExprResult ExprEmpty() { return OwningExprResult(Actions, false); } + + // Parsing methods. + + /// ParseTranslationUnit - All in one method that initializes parses, and + /// shuts down the parser. + void ParseTranslationUnit(); + + /// Initialize - Warm up the parser. + /// + void Initialize(); + + /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if + /// the EOF was encountered. + bool ParseTopLevelDecl(DeclGroupPtrTy &Result); + +private: + //===--------------------------------------------------------------------===// + // Low-Level token peeking and consumption methods. + // + + /// isTokenParen - Return true if the cur token is '(' or ')'. + bool isTokenParen() const { + return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren; + } + /// isTokenBracket - Return true if the cur token is '[' or ']'. + bool isTokenBracket() const { + return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square; + } + /// isTokenBrace - Return true if the cur token is '{' or '}'. + bool isTokenBrace() const { + return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace; + } + + /// isTokenStringLiteral - True if this token is a string-literal. + /// + bool isTokenStringLiteral() const { + return Tok.getKind() == tok::string_literal || + Tok.getKind() == tok::wide_string_literal; + } + + /// 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 + /// location of the consumed token. + SourceLocation ConsumeToken() { + assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() && + !isTokenBrace() && + "Should consume special tokens with Consume*Token"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the + /// current token type. This should only be used in cases where the type of + /// the token really isn't known, e.g. in error recovery. + SourceLocation ConsumeAnyToken() { + if (isTokenParen()) + return ConsumeParen(); + else if (isTokenBracket()) + return ConsumeBracket(); + else if (isTokenBrace()) + return ConsumeBrace(); + else if (isTokenStringLiteral()) + return ConsumeStringToken(); + else + return ConsumeToken(); + } + + /// ConsumeParen - This consume method keeps the paren count up-to-date. + /// + SourceLocation ConsumeParen() { + assert(isTokenParen() && "wrong consume method"); + if (Tok.getKind() == tok::l_paren) + ++ParenCount; + else if (ParenCount) + --ParenCount; // Don't let unbalanced )'s drive the count negative. + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBracket - This consume method keeps the bracket count up-to-date. + /// + SourceLocation ConsumeBracket() { + assert(isTokenBracket() && "wrong consume method"); + if (Tok.getKind() == tok::l_square) + ++BracketCount; + else if (BracketCount) + --BracketCount; // Don't let unbalanced ]'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBrace - This consume method keeps the brace count up-to-date. + /// + SourceLocation ConsumeBrace() { + assert(isTokenBrace() && "wrong consume method"); + if (Tok.getKind() == tok::l_brace) + ++BraceCount; + else if (BraceCount) + --BraceCount; // Don't let unbalanced }'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeStringToken - Consume the current 'peek token', lexing a new one + /// and returning the token kind. This method is specific to strings, as it + /// handles string literal concatenation, as per C99 5.1.1.2, translation + /// phase #6. + SourceLocation ConsumeStringToken() { + assert(isTokenStringLiteral() && + "Should only consume string literals with this method"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// GetLookAheadToken - This peeks ahead N tokens and returns that token + /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) + /// returns the token after Tok, etc. + /// + /// Note that this differs from the Preprocessor's LookAhead method, because + /// the Parser always has one token lexed that the preprocessor doesn't. + /// + const Token &GetLookAheadToken(unsigned N) { + if (N == 0 || Tok.is(tok::eof)) return Tok; + return PP.LookAhead(N-1); + } + + /// NextToken - This peeks ahead one token and returns it without + /// consuming it. + const Token &NextToken() { + return PP.LookAhead(0); + } + + /// TryAnnotateTypeOrScopeToken - If the current token position is on a + /// typename (possibly qualified in C++) or a C++ scope specifier not followed + /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens + /// with a single annotation token representing the typename or C++ scope + /// respectively. + /// This simplifies handling of C++ scope specifiers and allows efficient + /// backtracking without the need to re-parse and resolve nested-names and + /// typenames. + /// It will mainly be called when we expect to treat identifiers as typenames + /// (if they are typenames). For example, in C we do not expect identifiers + /// inside expressions to be treated as typenames so it will not be called + /// for expressions in C. + /// + /// This returns true if the token was annotated. + bool TryAnnotateTypeOrScopeToken(); + + /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only + /// annotates C++ scope specifiers. This returns true if the token was + /// annotated. + bool TryAnnotateCXXScopeToken(); + + /// TentativeParsingAction - An object that is used as a kind of "tentative + /// parsing transaction". It gets instantiated to mark the token position and + /// after the token consumption is done, Commit() or Revert() is called to + /// either "commit the consumed tokens" or revert to the previously marked + /// token position. Example: + /// + /// TentativeParsingAction TPA; + /// ConsumeToken(); + /// .... + /// TPA.Revert(); + /// + class TentativeParsingAction { + Parser &P; + Token PrevTok; + bool isActive; + + public: + explicit TentativeParsingAction(Parser& p) : P(p) { + PrevTok = P.Tok; + P.PP.EnableBacktrackAtThisPos(); + isActive = true; + } + void Commit() { + assert(isActive && "Parsing action was finished!"); + P.PP.CommitBacktrackedTokens(); + isActive = false; + } + void Revert() { + assert(isActive && "Parsing action was finished!"); + P.PP.Backtrack(); + P.Tok = PrevTok; + isActive = false; + } + ~TentativeParsingAction() { + assert(!isActive && "Forgot to call Commit or Revert!"); + } + }; + + + /// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), + /// this helper function matches and consumes the specified RHS token if + /// present. If not present, it emits the specified diagnostic indicating + /// that the parser failed to match the RHS of the token at LHSLoc. LHSName + /// should be the name of the unmatched LHS token. This returns the location + /// of the consumed token. + SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok, + SourceLocation LHSLoc); + + /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the + /// input. If so, it is consumed and false is returned. + /// + /// If the input is malformed, this emits the specified diagnostic. Next, if + /// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is + /// returned. + bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag, + const char *DiagMsg = "", + tok::TokenKind SkipToTok = tok::unknown); + + //===--------------------------------------------------------------------===// + // Scope manipulation + + /// ParseScope - Introduces a new scope for parsing. The kind of + /// scope is determined by ScopeFlags. Objects of this type should + /// be created on the stack to coincide with the position where the + /// parser enters the new scope, and this object's constructor will + /// create that new scope. Similarly, once the object is destroyed + /// the parser will exit the scope. + class ParseScope { + Parser *Self; + ParseScope(const ParseScope&); // do not implement + ParseScope& operator=(const ParseScope&); // do not implement + + public: + // ParseScope - Construct a new object to manage a scope in the + // parser Self where the new Scope is created with the flags + // ScopeFlags, but only when ManageScope is true (the default). If + // ManageScope is false, this object does nothing. + ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) + : Self(Self) { + if (ManageScope) + Self->EnterScope(ScopeFlags); + else + this->Self = 0; + } + + // Exit - Exit the scope associated with this object now, rather + // than waiting until the object is destroyed. + void Exit() { + if (Self) { + Self->ExitScope(); + Self = 0; + } + } + + ~ParseScope() { + Exit(); + } + }; + + /// EnterScope - Start a new scope. + void EnterScope(unsigned ScopeFlags); + + /// ExitScope - Pop a scope off the scope stack. + void ExitScope(); + + //===--------------------------------------------------------------------===// + // Diagnostic Emission and Error recovery. + + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); + + void SuggestParentheses(SourceLocation Loc, unsigned DK, + SourceRange ParenRange); + + /// SkipUntil - Read tokens until we get to the specified token, then consume + /// it (unless DontConsume is true). Because we cannot guarantee that the + /// token will ever occur, this skips to the next token, or to some likely + /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' + /// character. + /// + /// If SkipUntil finds the specified token, it returns true, otherwise it + /// returns false. + bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, + bool DontConsume = false) { + return SkipUntil(&T, 1, StopAtSemi, DontConsume); + } + bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true, + bool DontConsume = false) { + tok::TokenKind TokArray[] = {T1, T2}; + return SkipUntil(TokArray, 2, StopAtSemi, DontConsume); + } + bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, + bool StopAtSemi = true, bool DontConsume = false); + + //===--------------------------------------------------------------------===// + // Lexing and parsing of C++ inline methods. + + struct LexedMethod { + Action::DeclPtrTy D; + CachedTokens Toks; + explicit LexedMethod(Action::DeclPtrTy MD) : D(MD) {} + }; + + /// LateParsedDefaultArgument - Keeps track of a parameter that may + /// have a default argument that cannot be parsed yet because it + /// occurs within a member function declaration inside the class + /// (C++ [class.mem]p2). + struct LateParsedDefaultArgument { + explicit LateParsedDefaultArgument(Action::DeclPtrTy P, + CachedTokens *Toks = 0) + : Param(P), Toks(Toks) { } + + /// Param - The parameter declaration for this parameter. + Action::DeclPtrTy Param; + + /// Toks - The sequence of tokens that comprises the default + /// argument expression, not including the '=' or the terminating + /// ')' or ','. This will be NULL for parameters that have no + /// default argument. + CachedTokens *Toks; + }; + + /// LateParsedMethodDeclaration - A method declaration inside a class that + /// contains at least one entity whose parsing needs to be delayed + /// until the class itself is completely-defined, such as a default + /// argument (C++ [class.mem]p2). + struct LateParsedMethodDeclaration { + explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) : Method(M) { } + + /// Method - The method declaration. + Action::DeclPtrTy Method; + + /// DefaultArgs - Contains the parameters of the function and + /// their default arguments. At least one of the parameters will + /// have a default argument, but all of the parameters of the + /// method will be stored so that they can be reintroduced into + /// scope at the appropriate times. + 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 + /// 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; + + /// \brief Representation of a class that has been parsed, including + /// any member function declarations or definitions that need to be + /// parsed after the corresponding top-level class is complete. + struct ParsingClass { + ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass) + : TopLevelClass(TopLevelClass), TemplateScope(false), + TagOrTemplate(TagOrTemplate) { } + + /// \brief Whether this is a "top-level" class, meaning that it is + /// not nested within another class. + bool TopLevelClass : 1; + + /// \brief Whether this class had an associated template + /// scope. When true, TagOrTemplate is a template declaration; + /// othewise, it is a tag declaration. + bool TemplateScope : 1; + + /// \brief The class or class template whose definition we are parsing. + DeclPtrTy 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; + }; + + /// \brief The stack of classes that is currently being + /// parsed. Nested and local classes will be pushed onto this stack + /// when they are parsed, and removed afterward. + std::stack<ParsingClass *> ClassStack; + + ParsingClass &getCurrentClass() { + assert(!ClassStack.empty() && "No lexed method stacks!"); + return *ClassStack.top(); + } + + /// \brief RAII object used to + class ParsingClassDefinition { + Parser &P; + bool Popped; + + public: + ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass) + : P(P), Popped(false) { + 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(); + } + + ~ParsingClassDefinition() { + if (!Popped) + P.PopParsingClass(); + } + }; + + void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); + void DeallocateParsedClasses(ParsingClass *Class); + void PopParsingClass(); + + DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D); + void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDefs(ParsingClass &Class); + bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + tok::TokenKind EarlyAbortIf = tok::unknown, + bool ConsumeFinalToken = true); + + /// \brief Contains information about any template-specific + /// information that has been parsed prior to parsing declaration + /// specifiers. + struct ParsedTemplateInfo { + ParsedTemplateInfo() + : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } + + ParsedTemplateInfo(TemplateParameterLists *TemplateParams, + bool isSpecialization) + : Kind(isSpecialization? ExplicitSpecialization : Template), + TemplateParams(TemplateParams) { } + + explicit ParsedTemplateInfo(SourceLocation TemplateLoc) + : Kind(ExplicitInstantiation), TemplateParams(0), + TemplateLoc(TemplateLoc) { } + + /// \brief The kind of template we are parsing. + enum { + /// \brief We are not parsing a template at all. + NonTemplate = 0, + /// \brief We are parsing a template declaration. + Template, + /// \brief We are parsing an explicit specialization. + ExplicitSpecialization, + /// \brief We are parsing an explicit instantiation. + ExplicitInstantiation + } Kind; + + /// \brief The template parameter lists, for template declarations + /// and explicit specializations. + TemplateParameterLists *TemplateParams; + + /// \brief The location of the 'template' keyword, for an explicit + /// instantiation. + SourceLocation TemplateLoc; + }; + + //===--------------------------------------------------------------------===// + // C99 6.9: External Definitions. + DeclGroupPtrTy ParseExternalDeclaration(); + bool isDeclarationAfterDeclarator(); + bool isStartOfFunctionDefinition(); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + AccessSpecifier AS = AS_none); + + DeclPtrTy ParseFunctionDefinition(Declarator &D); + void ParseKNRParamDeclarations(Declarator &D); + // EndLoc, if non-NULL, is filled with the location of the last token of + // the simple-asm. + OwningExprResult ParseSimpleAsm(SourceLocation *EndLoc = 0); + OwningExprResult ParseAsmStringLiteral(); + + // Objective-C External Declarations + DeclPtrTy ParseObjCAtDirectives(); + DeclPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); + DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, + AttributeList *prefixAttrs = 0); + void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, + SourceLocation atLoc); + bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &P, + bool WarnOnDeclarations, + SourceLocation &EndProtoLoc); + void ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, + tok::ObjCKeywordKind contextKey); + DeclPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, + AttributeList *prefixAttrs = 0); + + DeclPtrTy ObjCImpDecl; + + DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc); + DeclPtrTy ParseObjCAtEndDeclaration(SourceLocation atLoc); + DeclPtrTy ParseObjCAtAliasDeclaration(SourceLocation atLoc); + DeclPtrTy ParseObjCPropertySynthesize(SourceLocation atLoc); + DeclPtrTy ParseObjCPropertyDynamic(SourceLocation atLoc); + + IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); + // Definitions for Objective-c context sensitive keywords recognition. + enum ObjCTypeQual { + objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref, + objc_NumQuals + }; + IdentifierInfo *ObjCTypeQuals[objc_NumQuals]; + + bool isTokIdentifier_in() const; + + TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS); + void ParseObjCMethodRequirement(); + DeclPtrTy ParseObjCMethodPrototype(DeclPtrTy classOrCat, + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); + DeclPtrTy ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, + DeclPtrTy classDecl, + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); + void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); + + DeclPtrTy ParseObjCMethodDefinition(); + + //===--------------------------------------------------------------------===// + // C99 6.5: Expressions. + + OwningExprResult ParseExpression(); + OwningExprResult ParseConstantExpression(); + // Expr that doesn't include commas. + OwningExprResult ParseAssignmentExpression(); + + OwningExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); + + OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); + + OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS, + unsigned MinPrec); + OwningExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand, + bool &NotCastExpr); + OwningExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand = false); + OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS); + OwningExprResult ParseSizeofAlignofExpression(); + OwningExprResult ParseBuiltinPrimaryExpression(); + + OwningExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, + bool &isCastExpr, + TypeTy *&CastTy, + SourceRange &CastRange); + + static const unsigned ExprListSize = 12; + typedef llvm::SmallVector<ExprTy*, ExprListSize> ExprListTy; + typedef llvm::SmallVector<SourceLocation, ExprListSize> CommaLocsTy; + + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. + bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs); + + /// ParenParseOption - Control what ParseParenExpression will parse. + enum ParenParseOption { + SimpleExpr, // Only parse '(' expression ')' + CompoundStmt, // Also allow '(' compound-statement ')' + CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}' + CastExpr // Also allow '(' type-name ')' <anything> + }; + OwningExprResult ParseParenExpression(ParenParseOption &ExprType, + bool stopIfCastExpr, + TypeTy *&CastTy, + SourceLocation &RParenLoc); + + OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, + TypeTy *&CastTy, + SourceLocation LParenLoc, + SourceLocation &RParenLoc); + + OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + OwningExprResult ParseStringLiteralExpression(); + + //===--------------------------------------------------------------------===// + // C++ Expressions + OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); + + /// ParseOptionalCXXScopeSpecifier - Parse global scope or + /// nested-name-specifier if present. Returns true if a nested-name-specifier + /// was parsed from the token stream. Note that this routine will not parse + /// ::new or ::delete, it will just leave them in the token stream. + /// + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Casts + OwningExprResult ParseCXXCasts(); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Type Identification + OwningExprResult ParseCXXTypeid(); + + //===--------------------------------------------------------------------===// + // C++ 9.3.2: C++ 'this' pointer + OwningExprResult ParseCXXThis(); + + //===--------------------------------------------------------------------===// + // C++ 15: C++ Throw Expression + OwningExprResult ParseThrowExpression(); + // EndLoc is filled with the location of the last token of the specification. + bool ParseExceptionSpecification(SourceLocation &EndLoc, + llvm::SmallVector<TypeTy*, 2> &Exceptions, + llvm::SmallVector<SourceRange, 2> &Ranges, + bool &hasAnyExceptionSpec); + + //===--------------------------------------------------------------------===// + // C++ 2.13.5: C++ Boolean Literals + OwningExprResult ParseCXXBoolLiteral(); + + //===--------------------------------------------------------------------===// + // C++ 5.2.3: Explicit type conversion (functional notation) + OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); + + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. + /// This should only be called when the current token is known to be part of + /// simple-type-specifier. + void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); + + bool ParseCXXTypeSpecifierSeq(DeclSpec &DS); + + //===--------------------------------------------------------------------===// + // C++ 5.3.4 and 5.3.5: C++ new and delete + bool ParseExpressionListOrTypeId(ExprListTy &Exprs, Declarator &D); + void ParseDirectNewDeclarator(Declarator &D); + OwningExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start); + OwningExprResult ParseCXXDeleteExpression(bool UseGlobal, + SourceLocation Start); + + //===--------------------------------------------------------------------===// + // C++ if/switch/while/for condition expression. + OwningExprResult ParseCXXCondition(); + + //===--------------------------------------------------------------------===// + // C++ types + + //===--------------------------------------------------------------------===// + // C99 6.7.8: Initialization. + + /// ParseInitializer + /// initializer: [C99 6.7.8] + /// assignment-expression + /// '{' ... + OwningExprResult ParseInitializer() { + if (Tok.isNot(tok::l_brace)) + return ParseAssignmentExpression(); + return ParseBraceInitializer(); + } + OwningExprResult ParseBraceInitializer(); + OwningExprResult ParseInitializerWithPotentialDesignator(); + + //===--------------------------------------------------------------------===// + // clang Expressions + + OwningExprResult ParseBlockLiteralExpression(); // ^{...} + + //===--------------------------------------------------------------------===// + // Objective-C Expressions + + bool isTokObjCMessageIdentifierReceiver() const { + if (!Tok.is(tok::identifier)) + return false; + + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (Actions.getTypeName(*II, Tok.getLocation(), CurScope)) + return true; + + return II == Ident_super; + } + + OwningExprResult ParseObjCAtExpression(SourceLocation AtLocation); + OwningExprResult ParseObjCStringLiteral(SourceLocation AtLoc); + OwningExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); + OwningExprResult ParseObjCSelectorExpression(SourceLocation AtLoc); + OwningExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); + OwningExprResult ParseObjCMessageExpression(); + OwningExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, + SourceLocation NameLoc, + IdentifierInfo *ReceiverName, + ExprArg ReceiverExpr); + OwningExprResult ParseAssignmentExprWithObjCMessageExprStart( + SourceLocation LBracloc, SourceLocation NameLoc, + IdentifierInfo *ReceiverName, ExprArg ReceiverExpr); + + //===--------------------------------------------------------------------===// + // C99 6.8: Statements and Blocks. + + OwningStmtResult ParseStatement() { + return ParseStatementOrDeclaration(true); + } + OwningStmtResult ParseStatementOrDeclaration(bool OnlyStatement = false); + OwningStmtResult ParseLabeledStatement(); + OwningStmtResult ParseCaseStatement(); + OwningStmtResult ParseDefaultStatement(); + OwningStmtResult ParseCompoundStatement(bool isStmtExpr = false); + OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false); + bool ParseParenExprOrCondition(OwningExprResult &CondExp, + bool OnlyAllowCondition = false); + OwningStmtResult ParseIfStatement(); + OwningStmtResult ParseSwitchStatement(); + OwningStmtResult ParseWhileStatement(); + OwningStmtResult ParseDoStatement(); + OwningStmtResult ParseForStatement(); + OwningStmtResult ParseGotoStatement(); + OwningStmtResult ParseContinueStatement(); + OwningStmtResult ParseBreakStatement(); + OwningStmtResult ParseReturnStatement(); + OwningStmtResult ParseAsmStatement(bool &msAsm); + OwningStmtResult FuzzyParseMicrosoftAsmStatement(); + bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, + llvm::SmallVectorImpl<ExprTy*> &Constraints, + llvm::SmallVectorImpl<ExprTy*> &Exprs); + + //===--------------------------------------------------------------------===// + // C++ 6: Statements and Blocks + + OwningStmtResult ParseCXXTryBlock(); + OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); + OwningStmtResult ParseCXXCatchBlock(); + + //===--------------------------------------------------------------------===// + // Objective-C Statements + + OwningStmtResult ParseObjCAtStatement(SourceLocation atLoc); + OwningStmtResult ParseObjCTryStmt(SourceLocation atLoc); + OwningStmtResult ParseObjCThrowStmt(SourceLocation atLoc); + OwningStmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); + + + //===--------------------------------------------------------------------===// + // C99 6.7: Declarations. + + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); + DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, + SourceLocation &DeclEnd, + bool RequireSemi = true); + DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D); + DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); + DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl); + DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl); + + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS); + void ParseDeclarationSpecifiers(DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + AccessSpecifier AS = AS_none); + bool ParseOptionalTypeSpecifier(DeclSpec &DS, int &isInvalid, + const char *&PrevSpec, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + + void ParseSpecifierQualifierList(DeclSpec &DS); + + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS); + + void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, + AccessSpecifier AS = AS_none); + void ParseEnumBody(SourceLocation StartLoc, DeclPtrTy TagDecl); + void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, + DeclPtrTy TagDecl); + void ParseStructDeclaration(DeclSpec &DS, + llvm::SmallVectorImpl<FieldDeclarator> &Fields); + + bool isDeclarationSpecifier(); + bool isTypeSpecifierQualifier(); + bool isTypeQualifier() const; + + /// isDeclarationStatement - Disambiguates between a declaration or an + /// expression statement, when parsing function bodies. + /// Returns true for declaration, false for expression. + bool isDeclarationStatement() { + if (getLang().CPlusPlus) + return isCXXDeclarationStatement(); + return isDeclarationSpecifier(); + } + + /// isSimpleDeclaration - Disambiguates between a declaration or an + /// expression, mainly used for the C 'clause-1' or the C++ + // 'for-init-statement' part of a 'for' statement. + /// Returns true for declaration, false for expression. + bool isSimpleDeclaration() { + if (getLang().CPlusPlus) + return isCXXSimpleDeclaration(); + return isDeclarationSpecifier(); + } + + /// \brief Specifies the context in which type-id/expression + /// disambiguation will occur. + enum TentativeCXXTypeIdContext { + TypeIdInParens, + TypeIdAsTemplateArgument + }; + + + /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know + /// whether the parens contain an expression or a type-id. + /// Returns true for a type-id and false for an expression. + bool isTypeIdInParens(bool &isAmbiguous) { + if (getLang().CPlusPlus) + return isCXXTypeId(TypeIdInParens, isAmbiguous); + isAmbiguous = false; + return isTypeSpecifierQualifier(); + } + bool isTypeIdInParens() { + bool isAmbiguous; + return isTypeIdInParens(isAmbiguous); + } + + /// isCXXDeclarationStatement - C++-specialized function that disambiguates + /// between a declaration or an expression statement, when parsing function + /// bodies. Returns true for declaration, false for expression. + bool isCXXDeclarationStatement(); + + /// isCXXSimpleDeclaration - C++-specialized function that disambiguates + /// between a simple-declaration or an expression-statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + /// Returns false if the statement is disambiguated as expression. + bool isCXXSimpleDeclaration(); + + /// isCXXFunctionDeclarator - Disambiguates between a function declarator or + /// a constructor-style initializer, when parsing declaration statements. + /// Returns true for function declarator and false for constructor-style + /// initializer. If 'warnIfAmbiguous' is true a warning will be emitted to + /// indicate that the parens were disambiguated as function declarator. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXFunctionDeclarator(bool warnIfAmbiguous); + + /// isCXXConditionDeclaration - Disambiguates between a declaration or an + /// expression for a condition of a if/switch/while/for statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXConditionDeclaration(); + + bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous); + bool isCXXTypeId(TentativeCXXTypeIdContext Context) { + bool isAmbiguous; + return isCXXTypeId(Context, isAmbiguous); + } + + /// TPResult - Used as the result value for functions whose purpose is to + /// disambiguate C++ constructs by "tentatively parsing" them. + /// This is a class instead of a simple enum because the implicit enum-to-bool + /// conversions may cause subtle bugs. + class TPResult { + enum Result { + TPR_true, + TPR_false, + TPR_ambiguous, + TPR_error + }; + Result Res; + TPResult(Result result) : Res(result) {} + public: + static TPResult True() { return TPR_true; } + static TPResult False() { return TPR_false; } + static TPResult Ambiguous() { return TPR_ambiguous; } + static TPResult Error() { return TPR_error; } + + bool operator==(const TPResult &RHS) const { return Res == RHS.Res; } + bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; } + }; + + /// 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 + /// function-style cast, and TPResult::Error() if a parsing error was + /// 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 + // resolved and tentative parsing may stop. TPResult::Ambiguous() indicates + // that more tentative parsing is necessary for disambiguation. + // They all consume tokens, so backtracking should be used after calling them. + + TPResult TryParseDeclarationSpecifier(); + TPResult TryParseSimpleDeclaration(); + TPResult TryParseTypeofSpecifier(); + TPResult TryParseInitDeclaratorList(); + TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); + TPResult TryParseParameterDeclarationClause(); + TPResult TryParseFunctionDeclarator(); + TPResult TryParseBracketDeclarator(); + + TypeResult ParseTypeName(SourceRange *Range = 0); + void ParseBlockId(); + // EndLoc, if non-NULL, is filled with the location of the last token of + // the attribute list. + AttributeList *ParseAttributes(SourceLocation *EndLoc = 0); + void FuzzyParseMicrosoftDeclSpec(); + void ParseTypeofSpecifier(DeclSpec &DS); + + /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to + /// enter a new C++ declarator scope and exit it when the function is + /// finished. + class DeclaratorScopeObj { + Parser &P; + CXXScopeSpec &SS; + public: + DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {} + + void EnterDeclaratorScope() { + if (SS.isSet()) + P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS); + } + + ~DeclaratorScopeObj() { + if (SS.isSet()) + P.Actions.ActOnCXXExitDeclaratorScope(P.CurScope, SS); + } + }; + + /// ParseDeclarator - Parse and verify a newly-initialized declarator. + void ParseDeclarator(Declarator &D); + /// A function that parses a variant of direct-declarator. + typedef void (Parser::*DirectDeclParseFunction)(Declarator&); + void ParseDeclaratorInternal(Declarator &D, + DirectDeclParseFunction DirectDeclParser); + void ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed = true); + void ParseDirectDeclarator(Declarator &D); + void ParseParenDeclarator(Declarator &D); + void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, + AttributeList *AttrList = 0, + bool RequiresArg = false); + void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, + Declarator &D); + void ParseBracketDeclarator(Declarator &D); + + //===--------------------------------------------------------------------===// + // C++ 7: Declarations [dcl.dcl] + + DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); + DeclPtrTy ParseLinkage(unsigned Context); + DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, + SourceLocation &DeclEnd); + DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, + SourceLocation &DeclEnd); + DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, + SourceLocation &DeclEnd); + DeclPtrTy ParseStaticAssertDeclaration(SourceLocation &DeclEnd); + DeclPtrTy ParseNamespaceAlias(SourceLocation NamespaceLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + SourceLocation &DeclEnd); + + //===--------------------------------------------------------------------===// + // C++ 9: classes [class] and C structs/unions. + TypeResult ParseClassName(SourceLocation &EndLocation, + const CXXScopeSpec *SS = 0); + void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, + DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + AccessSpecifier AS = AS_none); + void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, + DeclPtrTy TagDecl); + void ParseCXXClassMemberDeclaration(AccessSpecifier AS); + void ParseConstructorInitializer(DeclPtrTy ConstructorDecl); + MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl); + + //===--------------------------------------------------------------------===// + // C++ 10: Derived classes [class.derived] + void ParseBaseClause(DeclPtrTy ClassDecl); + BaseResult ParseBaseSpecifier(DeclPtrTy ClassDecl); + AccessSpecifier getAccessSpecifierIfPresent() const; + + //===--------------------------------------------------------------------===// + // C++ 13.5: Overloaded operators [over.oper] + // EndLoc, if non-NULL, is filled with the location of the last token of + // the ID. + OverloadedOperatorKind TryParseOperatorFunctionId(SourceLocation *EndLoc = 0); + TypeTy *ParseConversionFunctionId(SourceLocation *EndLoc = 0); + + //===--------------------------------------------------------------------===// + // C++ 14: Templates [temp] + typedef llvm::SmallVector<DeclPtrTy, 4> TemplateParameterList; + + // C++ 14.1: Template Parameters [temp.param] + DeclPtrTy ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none); + DeclPtrTy ParseTemplateDeclarationOrSpecialization(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS); + DeclPtrTy ParseSingleDeclarationAfterTemplate( + unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd, + AccessSpecifier AS=AS_none); + bool ParseTemplateParameters(unsigned Depth, + TemplateParameterList &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc); + bool ParseTemplateParameterList(unsigned Depth, + TemplateParameterList &TemplateParams); + DeclPtrTy ParseTemplateParameter(unsigned Depth, unsigned Position); + DeclPtrTy ParseTypeParameter(unsigned Depth, unsigned Position); + DeclPtrTy ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); + DeclPtrTy ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); + // C++ 14.3: Template arguments [temp.arg] + typedef llvm::SmallVector<void *, 16> TemplateArgList; + typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList; + typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList; + + bool ParseTemplateIdAfterTemplateName(TemplateTy Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec *SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + TemplateArgIsTypeList &TemplateArgIsType, + TemplateArgLocationList &TemplateArgLocations, + SourceLocation &RAngleLoc); + + void AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc = SourceLocation(), + bool AllowTypeAnnotation = true); + void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0); + bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs, + TemplateArgIsTypeList &TemplateArgIsType, + TemplateArgLocationList &TemplateArgLocations); + void *ParseTemplateArgument(bool &ArgIsType); + DeclPtrTy ParseExplicitInstantiation(SourceLocation TemplateLoc, + SourceLocation &DeclEnd); + + //===--------------------------------------------------------------------===// + // GNU G++: Type Traits [Type-Traits.html in the GCC manual] + OwningExprResult ParseUnaryTypeTrait(); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h new file mode 100644 index 000000000000..84cc5d5c3461 --- /dev/null +++ b/include/clang/Parse/Scope.h @@ -0,0 +1,310 @@ +//===--- Scope.h - Scope 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 Scope interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_SCOPE_H +#define LLVM_CLANG_PARSE_SCOPE_H + +#include "clang/Parse/Action.h" +#include "llvm/ADT/SmallPtrSet.h" + +namespace clang { + +/// Scope - A scope is a transient data structure that is used while parsing the +/// program. It assists with resolving identifiers to the appropriate +/// declaration. +/// +class Scope { +public: + /// ScopeFlags - These are bitfields that are or'd together when creating a + /// scope, which defines the sorts of things the scope contains. + enum ScopeFlags { + /// FnScope - This indicates that the scope corresponds to a function, which + /// means that labels are set here. + FnScope = 0x01, + + /// BreakScope - This is a while,do,switch,for, etc that can have break + /// stmts embedded into it. + BreakScope = 0x02, + + /// ContinueScope - This is a while,do,for, which can have continue + /// stmt embedded into it. + ContinueScope = 0x04, + + /// DeclScope - This is a scope that can contain a declaration. Some scopes + /// just contain loop constructs but don't contain decls. + DeclScope = 0x08, + + /// ControlScope - The controlling scope in a if/switch/while/for statement. + ControlScope = 0x10, + + /// ClassScope - The scope of a struct/union/class definition. + ClassScope = 0x20, + + /// BlockScope - This is a scope that corresponds to a block object. + /// Blocks serve as top-level scopes for some objects like labels, they + /// also prevent things like break and continue. BlockScopes have the + /// other flags set as well. + BlockScope = 0x40, + + /// TemplateParamScope - This is a scope that corresponds to the + /// template parameters of a C++ template. Template parameter + /// scope starts at the 'template' keyword and ends when the + /// template declaration ends. + TemplateParamScope = 0x80, + + /// FunctionPrototypeScope - This is a scope that corresponds to the + /// parameters within a function prototype. + FunctionPrototypeScope = 0x100, + + /// AtCatchScope - This is a scope that corresponds to the Objective-C + /// @catch statement. + AtCatchScope = 0x200 + }; +private: + /// The parent scope for this scope. This is null for the translation-unit + /// scope. + Scope *AnyParent; + + /// Depth - This is the depth of this scope. The translation-unit scope has + /// depth 0. + unsigned Depth : 16; + + /// Flags - This contains a set of ScopeFlags, which indicates how the scope + /// interrelates with other control flow statements. + unsigned Flags : 10; + + /// WithinElse - Whether this scope is part of the "else" branch in + /// its parent ControlScope. + bool WithinElse : 1; + + /// FnParent - If this scope has a parent scope that is a function body, this + /// pointer is non-null and points to it. This is used for label processing. + Scope *FnParent; + + /// BreakParent/ContinueParent - This is a direct link to the immediately + /// preceeding BreakParent/ContinueParent if this scope is not one, or null if + /// there is no containing break/continue scope. + Scope *BreakParent, *ContinueParent; + + /// ControlParent - This is a direct link to the immediately + /// preceeding ControlParent if this scope is not one, or null if + /// there is no containing control scope. + Scope *ControlParent; + + /// BlockParent - This is a direct link to the immediately containing + /// BlockScope if this scope is not one, or null if there is none. + Scope *BlockParent; + + /// TemplateParamParent - This is a direct link to the + /// immediately containing template parameter scope. In the + /// case of nested templates, template parameter scopes can have + /// other template parameter scopes as parents. + Scope *TemplateParamParent; + + /// DeclsInScope - This keeps track of all declarations in this scope. When + /// the declaration is added to the scope, it is set as the current + /// declaration for the identifier in the IdentifierTable. When the scope is + /// popped, these declarations are removed from the IdentifierTable's notion + /// of current declaration. It is up to the current Action implementation to + /// implement these semantics. + typedef llvm::SmallPtrSet<Action::DeclPtrTy, 32> DeclSetTy; + DeclSetTy DeclsInScope; + + /// Entity - The entity with which this scope is associated. For + /// example, the entity of a class scope is the class itself, the + /// entity of a function scope is a function, etc. This field is + /// maintained by the Action implementation. + void *Entity; + + typedef llvm::SmallVector<Action::DeclPtrTy, 2> UsingDirectivesTy; + UsingDirectivesTy UsingDirectives; + +public: + Scope(Scope *Parent, unsigned ScopeFlags) { + Init(Parent, ScopeFlags); + } + + /// getFlags - Return the flags for this scope. + /// + unsigned getFlags() const { return Flags; } + + /// isBlockScope - Return true if this scope does not correspond to a + /// closure. + bool isBlockScope() const { return Flags & BlockScope; } + + /// getParent - Return the scope that this is nested in. + /// + const Scope *getParent() const { return AnyParent; } + Scope *getParent() { return AnyParent; } + + /// getFnParent - Return the closest scope that is a function body. + /// + const Scope *getFnParent() const { return FnParent; } + Scope *getFnParent() { return FnParent; } + + /// getContinueParent - Return the closest scope that a continue statement + /// would be affected by. If the closest scope is a closure scope, we know + /// that there is no loop *inside* the closure. + Scope *getContinueParent() { + if (ContinueParent && !ContinueParent->isBlockScope()) + return ContinueParent; + return 0; + } + + const Scope *getContinueParent() const { + return const_cast<Scope*>(this)->getContinueParent(); + } + + /// getBreakParent - Return the closest scope that a break statement + /// would be affected by. If the closest scope is a block scope, we know + /// that there is no loop *inside* the block. + Scope *getBreakParent() { + if (BreakParent && !BreakParent->isBlockScope()) + return BreakParent; + return 0; + } + const Scope *getBreakParent() const { + return const_cast<Scope*>(this)->getBreakParent(); + } + + Scope *getControlParent() { return ControlParent; } + const Scope *getControlParent() const { return ControlParent; } + + Scope *getBlockParent() { return BlockParent; } + const Scope *getBlockParent() const { return BlockParent; } + + Scope *getTemplateParamParent() { return TemplateParamParent; } + const Scope *getTemplateParamParent() const { return TemplateParamParent; } + + typedef DeclSetTy::iterator decl_iterator; + decl_iterator decl_begin() const { return DeclsInScope.begin(); } + decl_iterator decl_end() const { return DeclsInScope.end(); } + bool decl_empty() const { return DeclsInScope.empty(); } + + void AddDecl(Action::DeclPtrTy D) { + DeclsInScope.insert(D); + } + + void RemoveDecl(Action::DeclPtrTy D) { + DeclsInScope.erase(D); + } + + /// isDeclScope - Return true if this is the scope that the specified decl is + /// declared in. + bool isDeclScope(Action::DeclPtrTy D) { + return DeclsInScope.count(D) != 0; + } + + void* getEntity() const { return Entity; } + void setEntity(void *E) { Entity = E; } + + /// isClassScope - Return true if this scope is a class/struct/union scope. + bool isClassScope() const { + return (getFlags() & Scope::ClassScope); + } + + /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline + /// method scope or is inside one. + bool isInCXXInlineMethodScope() const { + if (const Scope *FnS = getFnParent()) { + assert(FnS->getParent() && "TUScope not created?"); + return FnS->getParent()->isClassScope(); + } + return false; + } + + /// isTemplateParamScope - Return true if this scope is a C++ + /// template parameter scope. + bool isTemplateParamScope() const { + return getFlags() & Scope::TemplateParamScope; + } + + /// isFunctionPrototypeScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionPrototypeScope() const { + return getFlags() & Scope::FunctionPrototypeScope; + } + + /// isAtCatchScope - Return true if this scope is @catch. + bool isAtCatchScope() const { + return getFlags() & Scope::AtCatchScope; + } + + /// isWithinElse - Whether we are within the "else" of the + /// ControlParent (if any). + bool isWithinElse() const { return WithinElse; } + + void setWithinElse(bool WE) { WithinElse = WE; } + + typedef UsingDirectivesTy::iterator udir_iterator; + typedef UsingDirectivesTy::const_iterator const_udir_iterator; + + void PushUsingDirective(Action::DeclPtrTy UDir) { + UsingDirectives.push_back(UDir); + } + + udir_iterator using_directives_begin() { + return UsingDirectives.begin(); + } + + udir_iterator using_directives_end() { + return UsingDirectives.end(); + } + + const_udir_iterator using_directives_begin() const { + return UsingDirectives.begin(); + } + + const_udir_iterator using_directives_end() const { + return UsingDirectives.end(); + } + + /// Init - This is used by the parser to implement scope caching. + /// + void Init(Scope *Parent, unsigned ScopeFlags) { + AnyParent = Parent; + Depth = AnyParent ? AnyParent->Depth+1 : 0; + Flags = ScopeFlags; + + if (AnyParent) { + FnParent = AnyParent->FnParent; + BreakParent = AnyParent->BreakParent; + ContinueParent = AnyParent->ContinueParent; + ControlParent = AnyParent->ControlParent; + BlockParent = AnyParent->BlockParent; + TemplateParamParent = AnyParent->TemplateParamParent; + WithinElse = AnyParent->WithinElse; + + } else { + FnParent = BreakParent = ContinueParent = BlockParent = 0; + ControlParent = 0; + TemplateParamParent = 0; + WithinElse = false; + } + + // If this scope is a function or contains breaks/continues, remember it. + if (Flags & FnScope) FnParent = this; + if (Flags & BreakScope) BreakParent = this; + if (Flags & ContinueScope) ContinueParent = this; + if (Flags & ControlScope) ControlParent = this; + if (Flags & BlockScope) BlockParent = this; + if (Flags & TemplateParamScope) TemplateParamParent = this; + DeclsInScope.clear(); + UsingDirectives.clear(); + Entity = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/DeltaTree.h new file mode 100644 index 000000000000..7bf9305e2877 --- /dev/null +++ b/include/clang/Rewrite/DeltaTree.h @@ -0,0 +1,48 @@ +//===--- DeltaTree.h - B-Tree for Rewrite Delta tracking --------*- 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 DeltaTree class. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_REWRITE_DELTATREE_H +#define CLANG_REWRITE_DELTATREE_H + +namespace clang { + + /// DeltaTree - a multiway search tree (BTree) structure with some fancy + /// features. B-Trees are are generally more memory and cache efficient than + /// binary trees, because they store multiple keys/values in each node. This + /// implements a key/value mapping from index to delta, and allows fast lookup + /// on index. However, an added (important) bonus is that it can also + /// efficiently tell us the full accumulated delta for a specific file offset + /// as well, without traversing the whole tree. + class DeltaTree { + void *Root; // "DeltaTreeNode *" + void operator=(const DeltaTree&); // DO NOT IMPLEMENT + public: + DeltaTree(); + + // Note: Currently we only support copying when the RHS is empty. + DeltaTree(const DeltaTree &RHS); + ~DeltaTree(); + + /// getDeltaAt - Return the accumulated delta at the specified file offset. + /// This includes all insertions or delections that occurred *before* the + /// specified file index. + int getDeltaAt(unsigned FileIndex) const; + + /// AddDelta - When a change is made that shifts around the text buffer, + /// this method is used to record that info. It inserts a delta of 'Delta' + /// into the current DeltaTree at offset FileIndex. + void AddDelta(unsigned FileIndex, int Delta); + }; +} // end namespace clang + +#endif diff --git a/include/clang/Rewrite/HTMLRewrite.h b/include/clang/Rewrite/HTMLRewrite.h new file mode 100644 index 000000000000..f49d49e710c9 --- /dev/null +++ b/include/clang/Rewrite/HTMLRewrite.h @@ -0,0 +1,82 @@ +//==- HTMLRewrite.h - Translate source code into prettified HTML ---*- 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 a set of functions used for translating source code +// into beautified HTML. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_HTMLREWRITER_H +#define LLVM_CLANG_HTMLREWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include <string> + +namespace clang { + +class Rewriter; +class RewriteBuffer; +class Preprocessor; +class PreprocessorFactory; + +namespace html { + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. B/E must be in the same file. This ensures that + /// start/end tags are placed at the start/end of each line if the range is + /// multiline. + void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, + const char *StartTag, const char *EndTag); + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. The Start/end of the range must be in the same file. + /// This ensures that start/end tags are placed at the start/end of each line + /// if the range is multiline. + inline void HighlightRange(Rewriter &R, SourceRange Range, + const char *StartTag, const char *EndTag) { + HighlightRange(R, Range.getBegin(), Range.getEnd(), StartTag, EndTag); + } + + /// HighlightRange - This is the same as the above method, but takes + /// decomposed file locations. + void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, + const char *BufferStart, + const char *StartTag, const char *EndTag); + + /// EscapeText - HTMLize a specified file so that special characters are + /// are translated so that they are not interpreted as HTML tags. + void EscapeText(Rewriter& R, FileID FID, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + /// EscapeText - HTMLized the provided string so that special characters + /// in 's' are not interpreted as HTML tags. Unlike the version of + /// EscapeText that rewrites a file, this version by default replaces tabs + /// with spaces. + std::string EscapeText(const std::string& s, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + void AddLineNumbers(Rewriter& R, FileID FID); + + void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, + const char *title = NULL); + + /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with + /// information about keywords, comments, etc. + void SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP); + + /// HighlightMacros - This uses the macro table state from the end of the + /// file, to reexpand macros and insert (into the HTML) information about the + /// macro expansions. This won't be perfectly perfect, but it will be + /// reasonably close. + void HighlightMacros(Rewriter &R, FileID FID, Preprocessor &PP); + void HighlightMacros(Rewriter &R, FileID FID, PreprocessorFactory &PPF); +} // end html namespace +} // end clang namespace + +#endif diff --git a/include/clang/Rewrite/RewriteRope.h b/include/clang/Rewrite/RewriteRope.h new file mode 100644 index 000000000000..7faa451290e4 --- /dev/null +++ b/include/clang/Rewrite/RewriteRope.h @@ -0,0 +1,230 @@ +//===--- RewriteRope.h - Rope specialized for rewriter ----------*- 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 RewriteRope class, which is a powerful string class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITEROPE_H +#define LLVM_CLANG_REWRITEROPE_H + +#include "llvm/ADT/iterator.h" +#include <cstring> +#include <cassert> + +namespace clang { + //===--------------------------------------------------------------------===// + // RopeRefCountString Class + //===--------------------------------------------------------------------===// + + /// RopeRefCountString - This struct is allocated with 'new char[]' from the + /// heap, and represents a reference counted chunk of string data. When its + /// ref count drops to zero, it is delete[]'d. This is primarily managed + /// through the RopePiece class below. + struct RopeRefCountString { + unsigned RefCount; + char Data[1]; // Variable sized. + + void addRef() { + if (this) ++RefCount; + } + + void dropRef() { + if (this && --RefCount == 0) + delete [] (char*)this; + } + }; + + //===--------------------------------------------------------------------===// + // RopePiece Class + //===--------------------------------------------------------------------===// + + /// RopePiece - This class represents a view into a RopeRefCountString object. + /// This allows references to string data to be efficiently chopped up and + /// moved around without having to push around the string data itself. + /// + /// For example, we could have a 1M RopePiece and want to insert something + /// into the middle of it. To do this, we split it into two RopePiece objects + /// that both refer to the same underlying RopeRefCountString (just with + /// different offsets) which is a nice constant time operation. + struct RopePiece { + RopeRefCountString *StrData; + unsigned StartOffs; + unsigned EndOffs; + + RopePiece() : StrData(0), StartOffs(0), EndOffs(0) {} + + RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End) + : StrData(Str), StartOffs(Start), EndOffs(End) { + StrData->addRef(); + } + RopePiece(const RopePiece &RP) + : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) { + StrData->addRef(); + } + + ~RopePiece() { + StrData->dropRef(); + } + + void operator=(const RopePiece &RHS) { + if (StrData != RHS.StrData) { + StrData->dropRef(); + StrData = RHS.StrData; + StrData->addRef(); + } + StartOffs = RHS.StartOffs; + EndOffs = RHS.EndOffs; + } + + const char &operator[](unsigned Offset) const { + return StrData->Data[Offset+StartOffs]; + } + char &operator[](unsigned Offset) { + return StrData->Data[Offset+StartOffs]; + } + + unsigned size() const { return EndOffs-StartOffs; } + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTreeIterator Class + //===--------------------------------------------------------------------===// + + /// RopePieceBTreeIterator - This class provides read-only forward iteration + /// over bytes that are in a RopePieceBTree. This first iterates over bytes + /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf, + /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree. + class RopePieceBTreeIterator : + public forward_iterator<const char, ptrdiff_t> { + /// CurNode - The current B+Tree node that we are inspecting. + const void /*RopePieceBTreeLeaf*/ *CurNode; + /// CurPiece - The current RopePiece in the B+Tree node that we're + /// inspecting. + const RopePiece *CurPiece; + /// CurChar - The current byte in the RopePiece we are pointing to. + unsigned CurChar; + public: + // begin iterator. + RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N); + // end iterator + RopePieceBTreeIterator() : CurNode(0), CurPiece(0), CurChar(0) {} + + char operator*() const { + return (*CurPiece)[CurChar]; + } + + bool operator==(const RopePieceBTreeIterator &RHS) const { + return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar; + } + bool operator!=(const RopePieceBTreeIterator &RHS) const { + return !operator==(RHS); + } + + RopePieceBTreeIterator& operator++() { // Preincrement + if (CurChar+1 < CurPiece->size()) + ++CurChar; + else + MoveToNextPiece(); + return *this; + } + inline RopePieceBTreeIterator operator++(int) { // Postincrement + RopePieceBTreeIterator tmp = *this; ++*this; return tmp; + } + private: + void MoveToNextPiece(); + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTree Class + //===--------------------------------------------------------------------===// + + class RopePieceBTree { + void /*RopePieceBTreeNode*/ *Root; + void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT + public: + RopePieceBTree(); + RopePieceBTree(const RopePieceBTree &RHS); + ~RopePieceBTree(); + + typedef RopePieceBTreeIterator iterator; + iterator begin() const { return iterator(Root); } + iterator end() const { return iterator(); } + unsigned size() const; + unsigned empty() const { return size() == 0; } + + void clear(); + + void insert(unsigned Offset, const RopePiece &R); + + void erase(unsigned Offset, unsigned NumBytes); + }; + + //===--------------------------------------------------------------------===// + // RewriteRope Class + //===--------------------------------------------------------------------===// + +/// RewriteRope - A powerful string class. This class supports extremely +/// efficient insertions and deletions into the middle of it, even for +/// ridiculously long strings. +class RewriteRope { + RopePieceBTree Chunks; + + /// We allocate space for string data out of a buffer of size AllocChunkSize. + /// This keeps track of how much space is left. + RopeRefCountString *AllocBuffer; + unsigned AllocOffs; + enum { AllocChunkSize = 4080 }; + +public: + RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {} + RewriteRope(const RewriteRope &RHS) + : Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) { + } + + ~RewriteRope() { + // If we had an allocation buffer, drop our reference to it. + AllocBuffer->dropRef(); + } + + typedef RopePieceBTree::iterator iterator; + typedef RopePieceBTree::iterator const_iterator; + iterator begin() const { return Chunks.begin(); } + iterator end() const { return Chunks.end(); } + unsigned size() const { return Chunks.size(); } + + void clear() { + Chunks.clear(); + } + + void assign(const char *Start, const char *End) { + clear(); + if (Start != End) + Chunks.insert(0, MakeRopeString(Start, End)); + } + + void insert(unsigned Offset, const char *Start, const char *End) { + assert(Offset <= size() && "Invalid position to insert!"); + if (Start == End) return; + Chunks.insert(Offset, MakeRopeString(Start, End)); + } + + void erase(unsigned Offset, unsigned NumBytes) { + assert(Offset+NumBytes <= size() && "Invalid region to erase!"); + if (NumBytes == 0) return; + Chunks.erase(Offset, NumBytes); + } + +private: + RopePiece MakeRopeString(const char *Start, const char *End); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h new file mode 100644 index 000000000000..c3ee0175c36f --- /dev/null +++ b/include/clang/Rewrite/Rewriter.h @@ -0,0 +1,238 @@ +//===--- Rewriter.h - Code rewriting 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 Rewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITER_H +#define LLVM_CLANG_REWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Rewrite/RewriteRope.h" +#include <map> +#include <vector> +#include <cstring> +#include <string> +#include "clang/Rewrite/DeltaTree.h" + +namespace clang { + class SourceManager; + class LangOptions; + class Rewriter; + class Stmt; + +/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original +/// input with modifications get a new RewriteBuffer associated with them. The +/// RewriteBuffer captures the modified text itself as well as information used +/// to map between SourceLocation's in the original input and offsets in the +/// RewriteBuffer. For example, if text is inserted into the buffer, any +/// locations after the insertion point have to be mapped. +class RewriteBuffer { + friend class Rewriter; + /// Deltas - Keep track of all the deltas in the source code due to insertions + /// and deletions. + DeltaTree Deltas; + + /// Buffer - This is the actual buffer itself. Note that using a vector or + /// string is a horribly inefficient way to do this, we should use a rope + /// instead. + typedef RewriteRope BufferTy; + BufferTy Buffer; +public: + typedef BufferTy::const_iterator iterator; + iterator begin() const { return Buffer.begin(); } + iterator end() const { return Buffer.end(); } + unsigned size() const { return Buffer.size(); } + + /// RemoveText - Remove the specified text. + void RemoveText(unsigned OrigOffset, unsigned Size); + + /// InsertText - Insert some text at the specified point, where the offset in + /// the buffer is specified relative to the original SourceBuffer. The + /// text is inserted after the specified location. + /// + void InsertText(unsigned OrigOffset, const char *StrData, unsigned StrLen, + bool InsertAfter = true); + + + /// InsertTextBefore - Insert some text before the specified point, + /// where the offset in the buffer is specified relative to the original + /// SourceBuffer. + /// + void InsertTextBefore(unsigned OrigOffset, const char *StrData, + unsigned StrLen) { + InsertText(OrigOffset, StrData, StrLen, false); + } + + /// InsertText - Insert some text at the specified point, where the offset in + /// the buffer is specified relative to the original SourceBuffer. The + /// text is inserted after the specified location. This is method is the + /// same as InsertText with "InsertAfter == false". + void InsertTextAfter(unsigned OrigOffset, const char *StrData, + unsigned StrLen) { + InsertText(OrigOffset, StrData, StrLen); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + void ReplaceText(unsigned OrigOffset, unsigned OrigLength, + const char *NewStr, unsigned NewLength); + +private: // Methods only usable by Rewriter. + + /// Initialize - Start this rewrite buffer out with a copy of the unmodified + /// input buffer. + void Initialize(const char *BufStart, const char *BufEnd) { + Buffer.assign(BufStart, BufEnd); + } + + /// getMappedOffset - Given an offset into the original SourceBuffer that this + /// RewriteBuffer is based on, map it into the offset space of the + /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a + /// position where text is inserted, the location returned will be after any + /// inserted text at the position. + unsigned getMappedOffset(unsigned OrigOffset, + bool AfterInserts = false) const{ + return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; + } + + /// AddInsertDelta - When an insertion is made at a position, this + /// method is used to record that information. + void AddInsertDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset, Change); + } + + /// AddReplaceDelta - When a replacement/deletion is made at a position, this + /// method is used to record that information. + void AddReplaceDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset+1, Change); + } +}; + + +/// Rewriter - This is the main interface to the rewrite buffers. Its primary +/// job is to dispatch high-level requests to the low-level RewriteBuffers that +/// are involved. +class Rewriter { + SourceManager *SourceMgr; + const LangOptions *LangOpts; + std::map<FileID, RewriteBuffer> RewriteBuffers; +public: + explicit Rewriter(SourceManager &SM, const LangOptions &LO) + : SourceMgr(&SM), LangOpts(&LO) {} + explicit Rewriter() : SourceMgr(0), LangOpts(0) {} + + void setSourceMgr(SourceManager &SM, const LangOptions &LO) { + SourceMgr = &SM; + LangOpts = &LO; + } + SourceManager &getSourceMgr() { return *SourceMgr; } + const LangOptions &getLangOpts() { return *LangOpts; } + + /// isRewritable - Return true if this location is a raw file location, which + /// is rewritable. Locations from macros, etc are not rewritable. + static bool isRewritable(SourceLocation Loc) { + return Loc.isFileID(); + } + + /// getRangeSize - Return the size in bytes of the specified range if they + /// are in the same file. If not, this returns -1. + int getRangeSize(SourceRange Range) const; + + /// getRewritenText - Return the rewritten form of the text in the specified + /// range. If the start or end of the range was unrewritable or if they are + /// in different buffers, this returns an empty string. + /// + /// Note that this method is not particularly efficient. + /// + std::string getRewritenText(SourceRange Range) const; + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. + bool InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen, + bool InsertAfter = true); + + /// InsertTextAfter - Insert the specified string at the specified location in + /// the original buffer. This method returns true (and does nothing) if + /// the input location was not rewritable, false otherwise. Text is + /// inserted after any other text that has been previously inserted + /// at the some point (the default behavior for InsertText). + bool InsertTextAfter(SourceLocation Loc, const char *StrData, + unsigned StrLen) { + return InsertText(Loc, StrData, StrLen); + } + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. Text is + /// inserted before any other text that has been previously inserted + /// at the some point. + bool InsertTextBefore(SourceLocation Loc, const char *StrData, + unsigned StrLen) { + return InsertText(Loc, StrData, StrLen, false); + } + + + bool InsertCStrBefore(SourceLocation Loc, const char* Str) { + return InsertTextBefore(Loc, Str, strlen(Str)); + } + + + bool InsertCStrAfter(SourceLocation Loc, const char* Str) { + return InsertTextAfter(Loc, Str, strlen(Str)); + } + + bool InsertStrBefore(SourceLocation Loc, const std::string& S) { + return S.empty() ? false : InsertTextBefore(Loc, &S[0], S.size()); + } + + bool InsertStrAfter(SourceLocation Loc, const std::string& S) { + return S.empty() ? false : InsertTextAfter(Loc, &S[0], S.size()); + } + + + /// RemoveText - Remove the specified text region. + bool RemoveText(SourceLocation Start, unsigned Length); + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceLocation Start, unsigned OrigLength, + const char *NewStr, unsigned NewLength); + + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty + /// printer to generate the replacement code. This returns true if the input + /// could not be rewritten, or false if successful. + bool ReplaceStmt(Stmt *From, Stmt *To); + + /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. + /// If no modification has been made to it, return null. + const RewriteBuffer *getRewriteBufferFor(FileID FID) const { + std::map<FileID, RewriteBuffer>::const_iterator I = + RewriteBuffers.find(FID); + return I == RewriteBuffers.end() ? 0 : &I->second; + } + + /// getEditBuffer - This is like getRewriteBufferFor, but always returns a + /// buffer, and allows you to write on it directly. This is useful if you + /// want efficient low-level access to apis for scribbling on one specific + /// FileID's buffer. + RewriteBuffer &getEditBuffer(FileID FID); + +private: + unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Rewrite/TokenRewriter.h b/include/clang/Rewrite/TokenRewriter.h new file mode 100644 index 000000000000..c8fd0f532c25 --- /dev/null +++ b/include/clang/Rewrite/TokenRewriter.h @@ -0,0 +1,79 @@ +//===--- TokenRewriter.h - Token-based Rewriter -----------------*- 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 TokenRewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENREWRITER_H +#define LLVM_CLANG_TOKENREWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/OwningPtr.h" +#include <list> +#include <map> + +namespace clang { + class Token; + class LangOptions; + class ScratchBuffer; + + class TokenRewriter { + /// TokenList - This is the list of raw tokens that make up this file. Each + /// of these tokens has a unique SourceLocation, which is a FileID. + std::list<Token> TokenList; + + /// TokenRefTy - This is the type used to refer to a token in the TokenList. + typedef std::list<Token>::iterator TokenRefTy; + + /// TokenAtLoc - This map indicates which token exists at a specific + /// SourceLocation. Since each token has a unique SourceLocation, this is a + /// one to one map. The token can return its own location directly, to map + /// backwards. + std::map<SourceLocation, TokenRefTy> TokenAtLoc; + + /// ScratchBuf - This is the buffer that we create scratch tokens from. + /// + llvm::OwningPtr<ScratchBuffer> ScratchBuf; + + TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT + void operator=(const TokenRewriter&); // DO NOT IMPLEMENT. + public: + /// TokenRewriter - This creates a TokenRewriter for the file with the + /// specified FileID. + TokenRewriter(FileID FID, SourceManager &SM, const LangOptions &LO); + ~TokenRewriter(); + + typedef std::list<Token>::const_iterator token_iterator; + token_iterator token_begin() const { return TokenList.begin(); } + token_iterator token_end() const { return TokenList.end(); } + + + token_iterator AddTokenBefore(token_iterator I, const char *Val); + token_iterator AddTokenAfter(token_iterator I, const char *Val) { + assert(I != token_end() && "Cannot insert after token_end()!"); + return AddTokenBefore(++I, Val); + } + + private: + /// RemapIterator - Convert from token_iterator (a const iterator) to + /// TokenRefTy (a non-const iterator). + TokenRefTy RemapIterator(token_iterator I); + + /// AddToken - Add the specified token into the Rewriter before the other + /// position. + TokenRefTy AddToken(const Token &T, TokenRefTy Where); + }; + + + +} // end namespace clang + +#endif diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h new file mode 100644 index 000000000000..0f0d375e9c30 --- /dev/null +++ b/include/clang/Sema/ExternalSemaSource.h @@ -0,0 +1,56 @@ +//===--- ExternalSemaSource.h - External Sema 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 ExternalSemaSource interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H +#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExternalASTSource.h" + +namespace clang { + +class Sema; + +/// \brief An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class ExternalSemaSource : public ExternalASTSource { +public: + ExternalSemaSource() { + ExternalASTSource::SemaSource = true; + } + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// \brief Load the contents of the global method pool for a given + /// selector. + /// + /// \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>(); + } + + // isa/cast/dyn_cast support + static bool classof(const ExternalASTSource *Source) { + return Source->SemaSource; + } + static bool classof(const ExternalSemaSource *) { return true; } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h new file mode 100644 index 000000000000..bdce5e95effb --- /dev/null +++ b/include/clang/Sema/ParseAST.h @@ -0,0 +1,37 @@ +//===--- ParseAST.h - Define the ParseAST method ----------------*- 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 clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PARSEAST_H +#define LLVM_CLANG_SEMA_PARSEAST_H + +namespace clang { + class Preprocessor; + class ASTConsumer; + class ASTContext; + + /// \brief Parse the entire file specified, notifying the ASTConsumer as + /// the file is parsed. + /// + /// This operation inserts the parsed decls into the translation + /// unit held by Ctx. + /// + /// \param CompleteTranslationUnit When true, the parsed file is + /// considered to be a complete translation unit, and any + /// end-of-translation-unit wrapup will be performed. + void ParseAST(Preprocessor &pp, ASTConsumer *C, + ASTContext &Ctx, bool PrintStats = false, + bool CompleteTranslationUnit = true); + +} // end namespace clang + +#endif diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h new file mode 100644 index 000000000000..e821947035c4 --- /dev/null +++ b/include/clang/Sema/SemaConsumer.h @@ -0,0 +1,45 @@ +//===--- SemaConsumer.h - Abstract interface for AST semantics --*- 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 SemaConsumer class, a subclass of +// ASTConsumer that is used by AST clients that also require +// additional semantic analysis. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMACONSUMER_H +#define LLVM_CLANG_SEMA_SEMACONSUMER_H + +#include "clang/AST/ASTConsumer.h" + +namespace clang { + class Sema; + + /// \brief An abstract interface that should be implemented by + /// clients that read ASTs and then require further semantic + /// analysis of the entities in those ASTs. + class SemaConsumer : public ASTConsumer { + public: + SemaConsumer() { + ASTConsumer::SemaConsumer = true; + } + + /// \brief Initialize the semantic consumer with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + // isa/cast/dyn_cast support + static bool classof(const ASTConsumer *Consumer) { + return Consumer->SemaConsumer; + } + static bool classof(const SemaConsumer *) { return true; } + }; +} + +#endif diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h new file mode 100644 index 000000000000..e215ed48fbe5 --- /dev/null +++ b/include/clang/Sema/SemaDiagnostic.h @@ -0,0 +1,27 @@ +//===--- DiagnosticSema.h - Diagnostics for libsema -------------*- 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_DIAGNOSTICSEMA_H +#define LLVM_CLANG_DIAGNOSTICSEMA_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define SEMASTART +#include "clang/Basic/DiagnosticSemaKinds.inc" +#undef DIAG + NUM_BUILTIN_SEMA_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif |