diff options
206 files changed, 7730 insertions, 3527 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 3178017..44cbe0e 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -99,18 +99,84 @@ typedef struct { } CXCursor; /* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */ -typedef void *CXEntity; +typedef void *CXEntity; -CXIndex clang_createIndex(); +/** + * \brief clang_createIndex() provides a shared context for creating + * translation units. It provides two options: + * + * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" + * declarations (when loading any new translation units). A "local" declaration + * is one that belongs in the translation unit itself and not in a precompiled + * header that was used by the translation unit. If zero, all declarations + * will be enumerated. + * + * - displayDiagnostics: when non-zero, diagnostics will be output. If zero, + * diagnostics will be ignored. + * + * Here is an example: + * + * // excludeDeclsFromPCH = 1, displayDiagnostics = 1 + * Idx = clang_createIndex(1, 1); + * + * // IndexTest.pch was produced with the following command: + * // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" + * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); + * + * // This will load all the symbols from 'IndexTest.pch' + * clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * + * // This will load all the symbols from 'IndexTest.c', excluding symbols + * // from 'IndexTest.pch'. + * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch", 0 }; + * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args); + * clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * + * This process of creating the 'pch', loading it separately, and using it (via + * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks + * (which gives the indexer the same performance benefit as the compiler). + */ +CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics); void clang_disposeIndex(CXIndex); const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); +/* + * \brief Create a translation unit from an AST file (-emit-ast). + */ CXTranslationUnit clang_createTranslationUnit( CXIndex, const char *ast_filename ); +/** + * \brief Destroy the specified CXTranslationUnit object. + */ void clang_disposeTranslationUnit(CXTranslationUnit); +/** + * \brief Return the CXTranslationUnit for a given source file and the provided + * command line arguments one would pass to the compiler. + * + * Note: The 'source_filename' argument is optional. If the caller provides a NULL pointer, + * the name of the source file is expected to reside in the specified command line arguments. + * + * Note: When encountered in 'clang_command_line_args', the following options are ignored: + * + * '-c' + * '-emit-ast' + * '-fsyntax-only' + * '-o <output file>' (both '-o' and '<output file>' are ignored) + * + */ +CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, + const char *source_filename /* specify NULL if the source file is in clang_command_line_args */, + int num_clang_command_line_args, + const char **clang_command_line_args +); + /* Usage: clang_loadTranslationUnit(). Will load the toplevel declarations within a translation unit, issuing a 'callback' for each one. @@ -182,9 +248,28 @@ const char *clang_getDeclSource(CXDecl); /* * CXCursor Operations. */ +/** + Usage: clang_getCursor() will translate a source/line/column position + into an AST cursor (to derive semantic information from the source code). + */ CXCursor clang_getCursor(CXTranslationUnit, const char *source_name, unsigned line, unsigned column); +/** + Usage: clang_getCursorWithHint() provides the same functionality as + clang_getCursor() except that it takes an option 'hint' argument. + The 'hint' is a temporary CXLookupHint object (whose lifetime is managed by + the caller) that should be initialized with clang_initCXLookupHint(). + + FIXME: Add a better comment once getCursorWithHint() has more functionality. + */ +typedef CXCursor CXLookupHint; +CXCursor clang_getCursorWithHint(CXTranslationUnit, const char *source_name, + unsigned line, unsigned column, + CXLookupHint *hint); + +void clang_initCXLookupHint(CXLookupHint *hint); + enum CXCursorKind clang_getCursorKind(CXCursor); unsigned clang_isDeclaration(enum CXCursorKind); unsigned clang_isReference(enum CXCursorKind); diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 106d568..30896c9 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -81,12 +81,12 @@ class ASTContext { llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes; llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; llvm::FoldingSet<TypenameType> TypenameTypes; llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes; llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; - llvm::FoldingSet<ObjCProtocolListType> ObjCProtocolListTypes; llvm::FoldingSet<ElaboratedType> ElaboratedTypes; llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; @@ -143,6 +143,12 @@ class ASTContext { /// \brief The type for the C sigjmp_buf type. TypeDecl *sigjmp_bufDecl; + /// \brief Type for the Block descriptor for Blocks CodeGen. + RecordDecl *BlockDescriptorType; + + /// \brief Type for the Block descriptor for Blocks CodeGen. + RecordDecl *BlockDescriptorExtendedType; + /// \brief Keeps track of all declaration attributes. /// /// Since so few decls have attrs, we keep them in a hash map instead of @@ -390,9 +396,47 @@ public: /// of the specified type. QualType getBlockPointerType(QualType T); + /// This gets the struct used to keep track of the descriptor for pointer to + /// blocks. + QualType getBlockDescriptorType(); + + // Set the type for a Block descriptor type. + void setBlockDescriptorType(QualType T); + /// Get the BlockDescriptorType type, or NULL if it hasn't yet been built. + QualType getRawBlockdescriptorType() { + if (BlockDescriptorType) + return getTagDeclType(BlockDescriptorType); + return QualType(); + } + + /// This gets the struct used to keep track of the extended descriptor for + /// pointer to blocks. + QualType getBlockDescriptorExtendedType(); + + // Set the type for a Block descriptor extended type. + void setBlockDescriptorExtendedType(QualType T); + /// Get the BlockDescriptorExtendedType type, or NULL if it hasn't yet been + /// built. + QualType getRawBlockdescriptorExtendedType() { + if (BlockDescriptorExtendedType) + return getTagDeclType(BlockDescriptorExtendedType); + return QualType(); + } + + /// This gets the struct used to keep track of pointer to blocks, complete + /// with captured variables. + QualType getBlockParmType(bool BlockHasCopyDispose, + llvm::SmallVector<const Expr *, 8> &BDRDs); + + /// This builds the struct used for __block variables. + QualType BuildByRefType(const char *DeclName, QualType Ty); + + /// Returns true iff we need copy/dispose helpers for the given type. + bool BlockRequiresCopying(QualType Ty); + /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. - QualType getLValueReferenceType(QualType T); + QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true); /// getRValueReferenceType - Return the uniqued reference to the type for an /// rvalue reference to the specified type. @@ -431,22 +475,6 @@ public: ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals); - /// getConstantArrayWithExprType - Return a reference to the type for a - /// constant array of the specified element type. - QualType getConstantArrayWithExprType(QualType EltTy, - const llvm::APInt &ArySize, - Expr *ArySizeExpr, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets); - - /// getConstantArrayWithoutExprType - Return a reference to the type - /// for a constant array of the specified element type. - QualType getConstantArrayWithoutExprType(QualType EltTy, - const llvm::APInt &ArySize, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals); - /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. QualType getVectorType(QualType VectorType, unsigned NumElts); @@ -485,6 +513,9 @@ public: /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, + QualType Replacement); + QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, IdentifierInfo *Name = 0); @@ -515,10 +546,6 @@ public: ObjCProtocolDecl **ProtocolList = 0, unsigned NumProtocols = 0); - QualType getObjCProtocolListType(QualType T, - ObjCProtocolDecl **Protocols, - unsigned NumProtocols); - /// getTypeOfType - GCC extension. QualType getTypeOfExprType(Expr *e); QualType getTypeOfType(QualType t); @@ -815,6 +842,12 @@ public: return T->getCanonicalTypeInternal().getTypePtr(); } + /// getCanonicalParamType - Return the canonical parameter type + /// corresponding to the specific potentially non-canonical one. + /// Qualifiers are stripped off, functions are turned into function + /// pointers, and arrays decay one level into pointers. + CanQualType getCanonicalParamType(QualType T); + /// \brief Determine whether the given types are equivalent. bool hasSameType(QualType T1, QualType T2) { return getCanonicalType(T1) == getCanonicalType(T2); @@ -1047,7 +1080,10 @@ public: /// \param T the type that will be the basis for type source info. This type /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. - DeclaratorInfo *CreateDeclaratorInfo(QualType T); + /// + /// \param Size the size of the type info to create, or 0 if the size + /// should be calculated based on the type. + DeclaratorInfo *CreateDeclaratorInfo(QualType T, unsigned Size = 0); private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 6a5e366..f7a4736 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -185,7 +185,6 @@ class AlignedAttr : public Attr { public: AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} - // FIXME: Should use addressable units, not bits, to match llvm /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index a57bcc1..7c826fe 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -63,7 +63,8 @@ struct CXXBasePathElement { /// structure, which captures both the link from a derived class to one of its /// direct bases and identification describing which base class /// subobject is being used. -struct CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> { +class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> { +public: /// \brief The set of declarations found inside this base class /// subobject. DeclContext::lookup_result Decls; diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index d7ac76d..8b84bc2 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -487,30 +487,6 @@ struct CanProxyAdaptor<ConstantArrayType> }; template<> -struct CanProxyAdaptor<ConstantArrayWithExprType> - : public CanProxyBase<ConstantArrayWithExprType> { - LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, - getSizeModifier) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) -}; - -template<> -struct CanProxyAdaptor<ConstantArrayWithoutExprType> - : public CanProxyBase<ConstantArrayWithoutExprType> { - LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, - getSizeModifier) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) -}; - -template<> struct CanProxyAdaptor<IncompleteArrayType> : public CanProxyBase<IncompleteArrayType> { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) @@ -684,7 +660,7 @@ CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) { template<typename T> CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) { - assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || Other.isCanonical()) && "Type is not canonical!"); assert((Other.isNull() || isa<T>(Other.getTypePtr())) && "Dynamic type does not meet the static type's requires"); CanQual<T> Result; diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f21541c..72ce0d8 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -47,6 +47,9 @@ class DeclaratorInfo { friend class ASTContext; DeclaratorInfo(QualType ty) : Ty(ty) { } public: + /// \brief Return the type wrapped by this type source info. + QualType getType() const { return Ty; } + /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc getTypeLoc() const; }; @@ -93,28 +96,43 @@ public: /// name (C++ constructor, Objective-C selector, etc.). IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); } + /// getName - Get the name of identifier for this declaration as a StringRef. + /// This requires that the declaration have a name and that it be a simple + /// identifier. + llvm::StringRef getName() const { + assert(Name.isIdentifier() && "Name is not a simple identifier"); + return getIdentifier() ? getIdentifier()->getName() : ""; + } + /// 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. + // + // FIXME: Deprecated, move clients to getName(). const char *getNameAsCString() const { - assert(getIdentifier() && "Name is not a simple identifier"); - return getIdentifier()->getName(); + assert(Name.isIdentifier() && "Name is not a simple identifier"); + return getIdentifier() ? getIdentifier()->getNameStart() : ""; } - /// 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. + // + // FIXME: This function should be renamed to indicate that it is not just an + // alternate form of getName(), and clients should move as appropriate. + // + // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } + /// 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; } + /// 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, @@ -604,7 +622,8 @@ public: /// \brief For a static data member that was instantiated from a static /// data member of a class template, set the template specialiation kind. - void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); /// isFileVarDecl - Returns true for file scoped variable declaration. bool isFileVarDecl() const { @@ -1170,7 +1189,16 @@ public: /// \brief Determine what kind of template instantiation this function /// represents. - void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief Retrieve the (first) point of instantiation of a function template + /// specialization or a member of a class template specialization. + /// + /// \returns the first point of instantiation, if this function was + /// instantiated from a template; otherwie, returns an invalid source + /// location. + SourceLocation getPointOfInstantiation() const; /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a member function. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 9e88871..10db703 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -166,6 +166,15 @@ private: bool Used : 1; 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; + + // PCHLevel - the "level" of precompiled header/AST file from which this + // declaration was built. + unsigned PCHLevel : 2; + /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 16; @@ -177,16 +186,13 @@ private: #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), Used(false), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) { + Access(AS_none), PCHLevel(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { if (Decl::CollectingStats()) addDeclKind(DK); } @@ -274,6 +280,26 @@ public: bool isUsed() const { return Used; } void setUsed(bool U = true) { Used = U; } + /// \brief Retrieve the level of precompiled header from which this + /// declaration was generated. + /// + /// The PCH level of a declaration describes where the declaration originated + /// from. A PCH level of 0 indicates that the declaration was not from a + /// precompiled header. A PCH level of 1 indicates that the declaration was + /// from a top-level precompiled header; 2 indicates that the declaration + /// comes from a precompiled header on which the top-level precompiled header + /// depends, and so on. + unsigned getPCHLevel() const { return PCHLevel; } + + /// \brief The maximum PCH level that any declaration may have. + static const unsigned MaxPCHLevel = 3; + + /// \brief Set the PCH level of this declaration. + void setPCHLevel(unsigned Level) { + assert(Level < MaxPCHLevel && "PCH level exceeds the maximum"); + PCHLevel = Level; + } + unsigned getIdentifierNamespace() const { return IdentifierNamespace; } diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 2b12bb5..729a2f1 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -944,16 +944,29 @@ public: ObjCCategoryDecl *getCategoryClass() const; + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean + // something different. + llvm::StringRef getName() const { + return Id ? Id->getNameStart() : ""; + } + /// getNameAsCString - Get the name of identifier for the class /// interface associated with this implementation as a C string /// (const char*). + // + // FIXME: Deprecated, move clients to getName(). const char *getNameAsCString() const { - return Id ? Id->getName() : ""; + return Id ? Id->getNameStart() : ""; } /// @brief Get the name of the class associated with this interface. + // + // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { - return Id ? Id->getName() : ""; + return getName(); } static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;} @@ -995,17 +1008,30 @@ public: return getClassInterface()->getIdentifier(); } + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean + // something different. + llvm::StringRef getName() const { + assert(getIdentifier() && "Name is not a simple identifier"); + return getIdentifier()->getName(); + } + /// getNameAsCString - Get the name of identifier for the class /// interface associated with this implementation as a C string /// (const char*). + // + // FIXME: Move to StringRef API. const char *getNameAsCString() const { - assert(getIdentifier() && "Name is not a simple identifier"); - return getIdentifier()->getName(); + return getName().data(); } /// @brief Get the name of the class associated with this interface. + // + // FIXME: Move to StringRef API. std::string getNameAsString() const { - return getClassInterface()->getNameAsString(); + return getName(); } const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index d5dff50..0d09ea3 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1399,7 +1399,27 @@ public: CK_IntegralToPointer, /// CK_PointerToIntegral - Pointer to integral - CK_PointerToIntegral + CK_PointerToIntegral, + + /// CK_ToVoid - Cast to void. + CK_ToVoid, + + /// CK_VectorSplat - Casting from an integer/floating type to an extended + /// vector type with the same element type as the src type. Splats the + /// src expression into the destination expression. + CK_VectorSplat, + + /// CK_IntegralCast - Casting between integral types of different size. + CK_IntegralCast, + + /// CK_IntegralToFloating - Integral to floating point. + CK_IntegralToFloating, + + /// CK_FloatingToIntegral - Floating point to integral. + CK_FloatingToIntegral, + + /// CK_FloatingCast - Casting between floating types of different size. + CK_FloatingCast }; private: @@ -1665,7 +1685,8 @@ public: /// 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; } + static bool isShiftOp(Opcode Opc) { return Opc == Shl || Opc == Shr; } + bool isShiftOp() const { return isShiftOp(Opc); } bool isBitwiseOp() const { return Opc >= And && Opc <= Or; } static bool isRelationalOp(Opcode Opc) { return Opc >= LT && Opc <= GE; } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 89776b9..db02a68 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -443,6 +443,9 @@ public: return getTypePtr(); } + bool isCanonical() const; + bool isCanonicalAsParam() const; + /// isNull - Return true if this QualType doesn't point to a type yet. bool isNull() const { return Value.getPointer().isNull(); @@ -702,7 +705,9 @@ protected: public: TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); } - bool isCanonical() const { return CanonicalType.getTypePtr() == this; } + bool isCanonicalUnqualified() const { + return CanonicalType.getTypePtr() == this; + } /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. @@ -1089,19 +1094,50 @@ public: class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; + /// True if the type was originally spelled with an lvalue sigil. + /// This is never true of rvalue references but can also be false + /// on lvalue references because of C++0x [dcl.typedef]p9, + /// as follows: + /// + /// typedef int &ref; // lvalue, spelled lvalue + /// typedef int &&rvref; // rvalue + /// ref &a; // lvalue, inner ref, spelled lvalue + /// ref &&a; // lvalue, inner ref + /// rvref &a; // lvalue, inner ref, spelled lvalue + /// rvref &&a; // rvalue, inner ref + bool SpelledAsLValue; + + /// True if the inner type is a reference type. This only happens + /// in non-canonical forms. + bool InnerRef; + protected: - ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef) : + ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : Type(tc, CanonicalRef, Referencee->isDependentType()), - PointeeType(Referencee) { + PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue), + InnerRef(Referencee->isReferenceType()) { } public: - QualType getPointeeType() const { return PointeeType; } + bool isSpelledAsLValue() const { return SpelledAsLValue; } + + QualType getPointeeTypeAsWritten() const { return PointeeType; } + QualType getPointeeType() const { + // FIXME: this might strip inner qualifiers; okay? + const ReferenceType *T = this; + while (T->InnerRef) + T = T->PointeeType->getAs<ReferenceType>(); + return T->PointeeType; + } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType()); + Profile(ID, PointeeType, SpelledAsLValue); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee) { + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Referencee, + bool SpelledAsLValue) { ID.AddPointer(Referencee.getAsOpaquePtr()); + ID.AddBoolean(SpelledAsLValue); } static bool classof(const Type *T) { @@ -1114,9 +1150,10 @@ public: /// LValueReferenceType - C++ [dcl.ref] - Lvalue reference /// class LValueReferenceType : public ReferenceType { - LValueReferenceType(QualType Referencee, QualType CanonicalRef) : - ReferenceType(LValueReference, Referencee, CanonicalRef) { - } + LValueReferenceType(QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : + ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) + {} friend class ASTContext; // ASTContext creates these public: virtual void getAsStringInternal(std::string &InnerString, @@ -1135,7 +1172,7 @@ public: /// class RValueReferenceType : public ReferenceType { RValueReferenceType(QualType Referencee, QualType CanonicalRef) : - ReferenceType(RValueReference, Referencee, CanonicalRef) { + ReferenceType(RValueReference, Referencee, CanonicalRef, false) { } friend class ASTContext; // ASTContext creates these public: @@ -1239,8 +1276,6 @@ public: static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || - T->getTypeClass() == ConstantArrayWithExpr || - T->getTypeClass() == ConstantArrayWithoutExpr || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || T->getTypeClass() == DependentSizedArray; @@ -1285,86 +1320,11 @@ public: ID.AddInteger(TypeQuals); } static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray || - T->getTypeClass() == ConstantArrayWithExpr || - T->getTypeClass() == ConstantArrayWithoutExpr; + return T->getTypeClass() == ConstantArray; } static bool classof(const ConstantArrayType *) { return true; } }; -/// ConstantArrayWithExprType - This class represents C arrays with a -/// constant size specified by means of an integer constant expression. -/// For example 'int A[sizeof(int)]' has ConstantArrayWithExprType where -/// the element type is 'int' and the size expression is 'sizeof(int)'. -/// These types are non-canonical. -class ConstantArrayWithExprType : public ConstantArrayType { - /// SizeExpr - The ICE occurring in the concrete syntax. - Expr *SizeExpr; - /// Brackets - The left and right array brackets. - SourceRange Brackets; - - ConstantArrayWithExprType(QualType et, QualType can, - const llvm::APInt &size, Expr *e, - ArraySizeModifier sm, unsigned tq, - SourceRange brackets) - : ConstantArrayType(ConstantArrayWithExpr, et, can, size, sm, tq), - SizeExpr(e), Brackets(brackets) {} - friend class ASTContext; // ASTContext creates these. - virtual void Destroy(ASTContext& C); - -public: - Expr *getSizeExpr() const { return SizeExpr; } - SourceRange getBracketsRange() const { return Brackets; } - SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } - SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } - - virtual void getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArrayWithExpr; - } - static bool classof(const ConstantArrayWithExprType *) { return true; } - - void Profile(llvm::FoldingSetNodeID &ID) { - assert(0 && "Cannot unique ConstantArrayWithExprTypes."); - } -}; - -/// ConstantArrayWithoutExprType - This class represents C arrays with a -/// constant size that was not specified by an integer constant expression, -/// but inferred by static semantics. -/// For example 'int A[] = { 0, 1, 2 }' has ConstantArrayWithoutExprType. -/// These types are non-canonical: the corresponding canonical type, -/// having the size specified in an APInt object, is a ConstantArrayType. -class ConstantArrayWithoutExprType : public ConstantArrayType { - - ConstantArrayWithoutExprType(QualType et, QualType can, - const llvm::APInt &size, - ArraySizeModifier sm, unsigned tq) - : ConstantArrayType(ConstantArrayWithoutExpr, et, can, size, sm, tq) {} - friend class ASTContext; // ASTContext creates these. - -public: - virtual void getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArrayWithoutExpr; - } - static bool classof(const ConstantArrayWithoutExprType *) { return true; } - - void Profile(llvm::FoldingSetNodeID &ID) { - assert(0 && "Cannot unique ConstantArrayWithoutExprTypes."); - } -}; - /// IncompleteArrayType - This class represents C arrays with an unspecified /// size. For example 'int A[]' has an IncompleteArrayType where the element /// type is 'int' and the size is unspecified. @@ -2219,6 +2179,59 @@ public: static bool classof(const TemplateTypeParmType *T) { return true; } }; +/// \brief Represents the result of substituting a type for a template +/// type parameter. +/// +/// Within an instantiated template, all template type parameters have +/// been replaced with these. They are used solely to record that a +/// type was originally written as a template type parameter; +/// therefore they are never canonical. +class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // The original type parameter. + const TemplateTypeParmType *Replaced; + + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType()), + Replaced(Param) { } + + friend class ASTContext; + +public: + IdentifierInfo *getName() const { return Replaced->getName(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + /// Gets the type that was substituted for the template + /// parameter. + QualType getReplacementType() const { + return getCanonicalTypeInternal(); + } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return true; } + QualType desugar() const { return getReplacementType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getReplacementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + QualType Replacement) { + ID.AddPointer(Replaced); + ID.AddPointer(Replacement.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParm; + } + static bool classof(const SubstTemplateTypeParmType *T) { return true; } +}; + /// \brief Represents the type of a template specialization as written /// in the source code. /// @@ -2453,9 +2466,9 @@ class ObjCInterfaceType : public Type, public llvm::FoldingSetNode { // List is sorted on protocol name. No protocol is enterred more than once. llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; - ObjCInterfaceType(ObjCInterfaceDecl *D, + ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCInterface, QualType(), /*Dependent=*/false), + Type(ObjCInterface, Canonical, /*Dependent=*/false), Decl(D), Protocols(Protos, Protos+NumP) { } friend class ASTContext; // ASTContext creates these. public: @@ -2501,8 +2514,9 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { // List is sorted on protocol name. No protocol is entered more than once. llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; - ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCObjectPointer, QualType(), /*Dependent=*/false), + ObjCObjectPointerType(QualType Canonical, QualType T, + ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), PointeeType(T), Protocols(Protos, Protos+NumP) { } friend class ASTContext; // ASTContext creates these. @@ -2567,49 +2581,6 @@ public: static bool classof(const ObjCObjectPointerType *) { return true; } }; -/// \brief An ObjC Protocol list that qualifies a type. -/// -/// This is used only for keeping detailed type source information, it should -/// not participate in the semantics of the type system. -/// The protocol list is not canonicalized. -class ObjCProtocolListType : public Type, public llvm::FoldingSetNode { - QualType BaseType; - - // List of protocols for this protocol conforming object type. - llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; - - ObjCProtocolListType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCProtocolList, QualType(), /*Dependent=*/false), - BaseType(T), Protocols(Protos, Protos+NumP) { } - friend class ASTContext; // ASTContext creates these. - -public: - QualType getBaseType() const { return BaseType; } - - /// \brief Provides access to the list of protocols qualifying the base type. - typedef llvm::SmallVector<ObjCProtocolDecl*, 4>::const_iterator qual_iterator; - - qual_iterator qual_begin() const { return Protocols.begin(); } - qual_iterator qual_end() const { return Protocols.end(); } - bool qual_empty() const { return Protocols.size() == 0; } - - /// \brief Return the number of qualifying protocols. - unsigned getNumProtocols() const { return Protocols.size(); } - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, QualType T, - ObjCProtocolDecl **protocols, unsigned NumProtocols); - virtual void getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const; - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCProtocolList; - } - static bool classof(const ObjCProtocolListType *) { return true; } -}; - /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { ASTContext *Context; @@ -2646,6 +2617,20 @@ public: // Inline function definitions. +inline bool QualType::isCanonical() const { + const Type *T = getTypePtr(); + if (hasQualifiers()) + return T->isCanonicalUnqualified() && !isa<ArrayType>(T); + return T->isCanonicalUnqualified(); +} + +inline bool QualType::isCanonicalAsParam() const { + if (hasQualifiers()) return false; + const Type *T = getTypePtr(); + return T->isCanonicalUnqualified() && + !isa<FunctionType>(T) && !isa<ArrayType>(T); +} + inline void QualType::removeConst() { removeFastQualifiers(Qualifiers::Const); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 3735eee..1d7181b 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -18,10 +18,15 @@ namespace clang { class ParmVarDecl; - class TypeSpecLoc; class DeclaratorInfo; class UnqualTypeLoc; +// Predeclare all the type nodes. +#define ABSTRACT_TYPELOC(Class, Base) +#define TYPELOC(Class, Base) \ + class Class##TypeLoc; +#include "clang/AST/TypeLocNodes.def" + /// \brief Base wrapper for a particular "section" of type source info. /// /// A client should use the TypeLoc subclasses through cast/dyn_cast in order to @@ -34,12 +39,28 @@ protected: void *Data; public: + /// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum, + /// except it also defines a Qualified enum that corresponds to the + /// QualifiedLoc class. + enum TypeLocClass { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + Class = Type::Class, +#include "clang/AST/TypeNodes.def" + Qualified + }; + TypeLoc() : Ty(0), Data(0) { } TypeLoc(QualType ty, void *opaqueData) : Ty(ty.getAsOpaquePtr()), Data(opaqueData) { } TypeLoc(Type *ty, void *opaqueData) : Ty(ty), Data(opaqueData) { } + TypeLocClass getTypeLocClass() const { + if (getType().hasQualifiers()) return Qualified; + return (TypeLocClass) getType()->getTypeClass(); + } + bool isNull() const { return !Ty; } operator bool() const { return Ty; } @@ -48,35 +69,45 @@ public: /// \brief Get the type for which this source info wrapper provides /// information. - QualType getSourceType() const { return QualType::getFromOpaquePtr(Ty); } + QualType getType() const { + return QualType::getFromOpaquePtr(Ty); + } - Type *getSourceTypePtr() const { + Type *getTypePtr() const { return QualType::getFromOpaquePtr(Ty).getTypePtr(); } /// \brief Get the pointer where source information is stored. - void *getOpaqueData() const { return Data; } - - SourceRange getSourceRange() const; - - /// \brief Find the TypeSpecLoc that is part of this TypeLoc. - TypeSpecLoc getTypeSpecLoc() const; + void *getOpaqueData() const { + return Data; + } - /// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its - /// SourceRange. - SourceRange getTypeSpecRange() const; + SourceRange getSourceRange() const { + return getSourceRangeImpl(*this); + } /// \brief Returns the size of the type source info data block. unsigned getFullDataSize() const { - return getFullDataSizeForType(getSourceType()); + return getFullDataSizeForType(getType()); } /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". - TypeLoc getNextTypeLoc() const; + TypeLoc getNextTypeLoc() const { + return getNextTypeLocImpl(*this); + } /// \brief Skips past any qualifiers, if this is qualified. - UnqualTypeLoc getUnqualifiedLoc() const; + UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header + + /// \brief Initializes this to state that every location in this + /// type is the given location. + /// + /// This method exists to provide a simple transition for code that + /// relies on location-less types. + void initialize(SourceLocation Loc) const { + initializeImpl(*this, Loc); + } friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data; @@ -87,6 +118,11 @@ public: } static bool classof(const TypeLoc *TL) { return true; } + +private: + static void initializeImpl(TypeLoc TL, SourceLocation Loc); + static TypeLoc getNextTypeLocImpl(TypeLoc TL); + static SourceRange getSourceRangeImpl(TypeLoc TL); }; /// \brief Wrapper of type source information for a type with @@ -96,12 +132,16 @@ public: UnqualTypeLoc() {} UnqualTypeLoc(Type *Ty, void *Data) : TypeLoc(Ty, Data) {} - Type *getSourceTypePtr() const { + Type *getTypePtr() const { return reinterpret_cast<Type*>(Ty); } + TypeLocClass getTypeLocClass() const { + return (TypeLocClass) getTypePtr()->getTypeClass(); + } + static bool classof(const TypeLoc *TL) { - return !TL->getSourceType().hasQualifiers(); + return !TL->getType().hasQualifiers(); } static bool classof(const UnqualTypeLoc *TL) { return true; } }; @@ -111,14 +151,24 @@ public: /// /// Currently, we intentionally do not provide source location for /// type qualifiers. -class QualifiedLoc : public TypeLoc { +class QualifiedTypeLoc : public TypeLoc { public: SourceRange getSourceRange() const { return SourceRange(); } UnqualTypeLoc getUnqualifiedLoc() const { - return UnqualTypeLoc(getSourceTypePtr(), Data); + return UnqualTypeLoc(getTypePtr(), Data); + } + + /// Initializes the local data of this type source info block to + /// provide no information. + void initializeLocal(SourceLocation Loc) { + // do nothing + } + + TypeLoc getNextTypeLoc() const { + return getUnqualifiedLoc(); } /// \brief Returns the size of the type source info data block that is @@ -132,52 +182,21 @@ public: /// \brief Returns the size of the type source info data block. unsigned getFullDataSize() const { return getLocalDataSize() + - getFullDataSizeForType(getSourceType().getUnqualifiedType()); + getFullDataSizeForType(getType().getUnqualifiedType()); } static bool classof(const TypeLoc *TL) { - return TL->getSourceType().hasQualifiers(); + return TL->getType().hasQualifiers(); } - static bool classof(const QualifiedLoc *TL) { return true; } + static bool classof(const QualifiedTypeLoc *TL) { return true; } }; inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const { - if (isa<QualifiedLoc>(this)) - return cast<QualifiedLoc>(this)->getUnqualifiedLoc(); + if (isa<QualifiedTypeLoc>(this)) + return cast<QualifiedTypeLoc>(this)->getUnqualifiedLoc(); return cast<UnqualTypeLoc>(*this); } -/// \brief Base wrapper of type source info data for type-spec types. -class TypeSpecLoc : public UnqualTypeLoc { -public: - static bool classof(const TypeLoc *TL) { - return (UnqualTypeLoc::classof(TL) && - classof(static_cast<const UnqualTypeLoc*>(TL))); - } - static bool classof(const UnqualTypeLoc *TL); - static bool classof(const TypeSpecLoc *TL) { return true; } -}; - -inline SourceRange TypeLoc::getTypeSpecRange() const { - return getTypeSpecLoc().getSourceRange(); -} - -/// \brief Base wrapper of type source info data for types part of a declarator, -/// excluding type-spec types. -class DeclaratorLoc : public UnqualTypeLoc { -public: - /// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. - TypeSpecLoc getTypeSpecLoc() const; - - static bool classof(const TypeLoc *TL) { - return (UnqualTypeLoc::classof(TL) && - classof(static_cast<const UnqualTypeLoc*>(TL))); - } - static bool classof(const UnqualTypeLoc *TL); - static bool classof(const DeclaratorLoc *TL) { return true; } -}; - - /// A metaprogramming base class for TypeLoc classes which correspond /// to a particular Type subclass. It is accepted for a single /// TypeLoc class to correspond to multiple Type classes. @@ -196,9 +215,19 @@ public: /// getExtraLocalDataSize(); getExtraLocalData() will then point to /// this extra memory. /// -/// TypeLocs with an inner type should override hasInnerType() and -/// getInnerType(); getInnerTypeLoc() will then point to this inner -/// type's location data. +/// TypeLocs with an inner type should define +/// QualType getInnerType() const +/// and getInnerTypeLoc() will then point to this inner type's +/// location data. +/// +/// A word about hierarchies: this template is not designed to be +/// derived from multiple times in a hierarchy. It is also not +/// designed to be used for classes where subtypes might provide +/// different amounts of source information. It should be subclassed +/// only at the deepest portion of the hierarchy where all children +/// have identical source information; if that's an abstract type, +/// then further descendents should inherit from +/// InheritingConcreteTypeLoc instead. template <class Base, class Derived, class TypeClass, class LocalData> class ConcreteTypeLoc : public Base { @@ -215,25 +244,19 @@ public: return asDerived()->getLocalDataSize() + getInnerTypeSize(); } - static bool classof(const TypeLoc *TL) { - return Derived::classofType(TL->getSourceTypePtr()); - } - static bool classof(const UnqualTypeLoc *TL) { - return Derived::classofType(TL->getSourceTypePtr()); - } - static bool classof(const Derived *TL) { - return true; - } - static bool classofType(const Type *Ty) { return TypeClass::classof(Ty); } -protected: + TypeLoc getNextTypeLoc() const { + return getNextTypeLoc(asDerived()->getInnerType()); + } + TypeClass *getTypePtr() const { - return cast<TypeClass>(Base::getSourceTypePtr()); + return cast<TypeClass>(Base::getTypePtr()); } +protected: unsigned getExtraLocalDataSize() const { return 0; } @@ -253,136 +276,151 @@ protected: return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize(); } - bool hasInnerType() const { - return false; - } + struct HasNoInnerType {}; + HasNoInnerType getInnerType() const { return HasNoInnerType(); } TypeLoc getInnerTypeLoc() const { - assert(asDerived()->hasInnerType()); return TypeLoc(asDerived()->getInnerType(), getNonLocalData()); } private: unsigned getInnerTypeSize() const { - if (asDerived()->hasInnerType()) - return getInnerTypeLoc().getFullDataSize(); + return getInnerTypeSize(asDerived()->getInnerType()); + } + + unsigned getInnerTypeSize(HasNoInnerType _) const { return 0; } - // Required here because my metaprogramming is too weak to avoid it. - QualType getInnerType() const { - assert(0 && "getInnerType() not overridden"); - return QualType(); + unsigned getInnerTypeSize(QualType _) const { + return getInnerTypeLoc().getFullDataSize(); } -}; + TypeLoc getNextTypeLoc(HasNoInnerType _) const { + return TypeLoc(); + } -struct DefaultTypeSpecLocInfo { - SourceLocation StartLoc; + TypeLoc getNextTypeLoc(QualType T) const { + return TypeLoc(T, getNonLocalData()); + } }; -/// \brief The default wrapper for type-spec types that are not handled by -/// another specific wrapper. -class DefaultTypeSpecLoc : public ConcreteTypeLoc<TypeSpecLoc, - DefaultTypeSpecLoc, - Type, - DefaultTypeSpecLocInfo> { +/// A metaprogramming class designed for concrete subtypes of abstract +/// types where all subtypes share equivalently-structured source +/// information. See the note on ConcreteTypeLoc. +template <class Base, class Derived, class TypeClass> +class InheritingConcreteTypeLoc : public Base { public: - SourceLocation getStartLoc() const { - return getLocalData()->StartLoc; + static bool classof(const TypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); } - void setStartLoc(SourceLocation Loc) { - getLocalData()->StartLoc = Loc; + static bool classof(const UnqualTypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); } - SourceRange getSourceRange() const { - return SourceRange(getStartLoc(), getStartLoc()); + static bool classof(const Derived *TL) { + return true; } - static bool classofType(const Type *T); + TypeClass *getTypePtr() const { + return cast<TypeClass>(Base::getTypePtr()); + } }; - -struct TypedefLocInfo { +struct TypeSpecLocInfo { SourceLocation NameLoc; }; -/// \brief Wrapper for source info for typedefs. -class TypedefLoc : public ConcreteTypeLoc<TypeSpecLoc,TypedefLoc, - TypedefType,TypedefLocInfo> { +/// \brief A reasonable base class for TypeLocs that correspond to +/// types that are written as a type-specifier. +template <class Derived, class TypeClass, class LocalData = TypeSpecLocInfo> +class TypeSpecTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> { public: SourceLocation getNameLoc() const { - return getLocalData()->NameLoc; + return this->getLocalData()->NameLoc; } void setNameLoc(SourceLocation Loc) { - getLocalData()->NameLoc = Loc; + this->getLocalData()->NameLoc = Loc; } SourceRange getSourceRange() const { return SourceRange(getNameLoc(), getNameLoc()); } + void initializeLocal(SourceLocation Loc) { + setNameLoc(Loc); + } +}; +/// \brief Wrapper for source info for typedefs. +class TypedefTypeLoc : public TypeSpecTypeLoc<TypedefTypeLoc,TypedefType> { +public: TypedefDecl *getTypedefDecl() const { return getTypePtr()->getDecl(); } }; -struct ObjCInterfaceLocInfo { - SourceLocation NameLoc; +/// \brief Wrapper for source info for builtin types. +class BuiltinTypeLoc : public TypeSpecTypeLoc<BuiltinTypeLoc, + BuiltinType> { }; -/// \brief Wrapper for source info for ObjC interfaces. -class ObjCInterfaceLoc : public ConcreteTypeLoc<TypeSpecLoc, - ObjCInterfaceLoc, - ObjCInterfaceType, - ObjCInterfaceLocInfo> { -public: - SourceLocation getNameLoc() const { - return getLocalData()->NameLoc; - } - void setNameLoc(SourceLocation Loc) { - getLocalData()->NameLoc = Loc; - } - SourceRange getSourceRange() const { - return SourceRange(getNameLoc(), getNameLoc()); - } +/// \brief Wrapper for template type parameters. +class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc<TemplateTypeParmTypeLoc, + TemplateTypeParmType> { +}; - ObjCInterfaceDecl *getIFaceDecl() const { - return getTypePtr()->getDecl(); - } +/// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmTypeLoc : + public TypeSpecTypeLoc<SubstTemplateTypeParmTypeLoc, + SubstTemplateTypeParmType> { }; struct ObjCProtocolListLocInfo { - SourceLocation LAngleLoc, RAngleLoc; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; }; -/// \brief Wrapper for source info for ObjC protocol lists. -class ObjCProtocolListLoc : public ConcreteTypeLoc<TypeSpecLoc, - ObjCProtocolListLoc, - ObjCProtocolListType, - ObjCProtocolListLocInfo> { +// A helper class for defining ObjC TypeLocs that can qualified with +// protocols. +// +// TypeClass basically has to be either ObjCInterfaceType or +// ObjCObjectPointerType. +template <class Derived, class TypeClass, class LocalData> +class ObjCProtocolListTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + Derived, + TypeClass, + LocalData> { // SourceLocations are stored after Info, one for each Protocol. SourceLocation *getProtocolLocArray() const { - return (SourceLocation*) getExtraLocalData(); + return (SourceLocation*) this->getExtraLocalData(); + } + +protected: + void initializeLocalBase(SourceLocation Loc) { + setLAngleLoc(Loc); + setRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); } public: SourceLocation getLAngleLoc() const { - return getLocalData()->LAngleLoc; + return this->getLocalData()->LAngleLoc; } void setLAngleLoc(SourceLocation Loc) { - getLocalData()->LAngleLoc = Loc; + this->getLocalData()->LAngleLoc = Loc; } SourceLocation getRAngleLoc() const { - return getLocalData()->RAngleLoc; + return this->getLocalData()->RAngleLoc; } void setRAngleLoc(SourceLocation Loc) { - getLocalData()->RAngleLoc = Loc; + this->getLocalData()->RAngleLoc = Loc; } unsigned getNumProtocols() const { - return getTypePtr()->getNumProtocols(); + return this->getTypePtr()->getNumProtocols(); } SourceLocation getProtocolLoc(unsigned i) const { @@ -396,165 +434,229 @@ public: ObjCProtocolDecl *getProtocol(unsigned i) const { assert(i < getNumProtocols() && "Index is out of bounds!"); - return *(getTypePtr()->qual_begin() + i); + return *(this->getTypePtr()->qual_begin() + i); } - TypeLoc getBaseTypeLoc() const { - return getInnerTypeLoc(); - } - SourceRange getSourceRange() const { return SourceRange(getLAngleLoc(), getRAngleLoc()); } - /// \brief Returns the size of the type source info data block that is - /// specific to this type. - unsigned getExtraLocalDataSize() const { - return getNumProtocols() * sizeof(SourceLocation); + void initializeLocal(SourceLocation Loc) { + initializeLocalBase(Loc); } - bool hasInnerType() const { return true; } - QualType getInnerType() const { return getTypePtr()->getBaseType(); } + unsigned getExtraLocalDataSize() const { + return this->getNumProtocols() * sizeof(SourceLocation); + } }; -struct PointerLocInfo { - SourceLocation StarLoc; +struct ObjCInterfaceLocInfo : ObjCProtocolListLocInfo { + SourceLocation NameLoc; }; -/// \brief Wrapper for source info for pointers. -class PointerLoc : public ConcreteTypeLoc<DeclaratorLoc, - PointerLoc, - PointerType, - PointerLocInfo> { +/// \brief Wrapper for source info for ObjC interfaces. +class ObjCInterfaceTypeLoc : + public ObjCProtocolListTypeLoc<ObjCInterfaceTypeLoc, + ObjCInterfaceType, + ObjCInterfaceLocInfo> { public: - SourceLocation getStarLoc() const { - return getLocalData()->StarLoc; - } - void setStarLoc(SourceLocation Loc) { - getLocalData()->StarLoc = Loc; + ObjCInterfaceDecl *getIFaceDecl() const { + return getTypePtr()->getDecl(); } - TypeLoc getPointeeLoc() const { - return getInnerTypeLoc(); + SourceLocation getNameLoc() const { + return getLocalData()->NameLoc; } - /// \brief Find the TypeSpecLoc that is part of this PointerLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getPointeeLoc().getTypeSpecLoc(); + void setNameLoc(SourceLocation Loc) { + getLocalData()->NameLoc = Loc; } SourceRange getSourceRange() const { - return SourceRange(getStarLoc(), getStarLoc()); + if (getNumProtocols()) + return SourceRange(getNameLoc(), getRAngleLoc()); + else + return SourceRange(getNameLoc(), getNameLoc()); } - bool hasInnerType() const { return true; } - QualType getInnerType() const { return getTypePtr()->getPointeeType(); } + void initializeLocal(SourceLocation Loc) { + initializeLocalBase(Loc); + setNameLoc(Loc); + } }; -struct BlockPointerLocInfo { - SourceLocation CaretLoc; +struct ObjCObjectPointerLocInfo : ObjCProtocolListLocInfo { + SourceLocation StarLoc; + bool HasProtocols; + bool HasBaseType; }; -/// \brief Wrapper for source info for block pointers. -class BlockPointerLoc : public ConcreteTypeLoc<DeclaratorLoc, - BlockPointerLoc, - BlockPointerType, - BlockPointerLocInfo> { +/// Wraps an ObjCPointerType with source location information. Note +/// that not all ObjCPointerTypes actually have a star location; nor +/// are protocol locations necessarily written in the source just +/// because they're present on the type. +class ObjCObjectPointerTypeLoc : + public ObjCProtocolListTypeLoc<ObjCObjectPointerTypeLoc, + ObjCObjectPointerType, + ObjCObjectPointerLocInfo> { public: - SourceLocation getCaretLoc() const { - return getLocalData()->CaretLoc; + bool hasProtocolsAsWritten() const { + return getLocalData()->HasProtocols; } - void setCaretLoc(SourceLocation Loc) { - getLocalData()->CaretLoc = Loc; + + void setHasProtocolsAsWritten(bool HasProtocols) { + getLocalData()->HasProtocols = HasProtocols; } - TypeLoc getPointeeLoc() const { - return getInnerTypeLoc(); + bool hasBaseTypeAsWritten() const { + return getLocalData()->HasBaseType; } - /// \brief Find the TypeSpecLoc that is part of this BlockPointerLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getPointeeLoc().getTypeSpecLoc(); + void setHasBaseTypeAsWritten(bool HasBaseType) { + getLocalData()->HasBaseType = HasBaseType; + } + + SourceLocation getStarLoc() const { + return getLocalData()->StarLoc; + } + + void setStarLoc(SourceLocation Loc) { + getLocalData()->StarLoc = Loc; } SourceRange getSourceRange() const { - return SourceRange(getCaretLoc(), getCaretLoc()); + // Being written with protocols is incompatible with being written + // with a star. + if (hasProtocolsAsWritten()) + return SourceRange(getLAngleLoc(), getRAngleLoc()); + else + return SourceRange(getStarLoc(), getStarLoc()); + } + + void initializeLocal(SourceLocation Loc) { + initializeLocalBase(Loc); + setHasProtocolsAsWritten(false); + setHasBaseTypeAsWritten(false); + setStarLoc(Loc); + } + + TypeLoc getBaseTypeLoc() const { + return getInnerTypeLoc(); } - bool hasInnerType() const { return true; } - QualType getInnerType() const { return getTypePtr()->getPointeeType(); } + QualType getInnerType() const { + return getTypePtr()->getPointeeType(); + } }; -struct MemberPointerLocInfo { +struct PointerLikeLocInfo { SourceLocation StarLoc; }; -/// \brief Wrapper for source info for member pointers. -class MemberPointerLoc : public ConcreteTypeLoc<DeclaratorLoc, - MemberPointerLoc, - MemberPointerType, - MemberPointerLocInfo> { -public: - SourceLocation getStarLoc() const { - return getLocalData()->StarLoc; +/// A base class for +template <class Derived, class TypeClass, class LocalData = PointerLikeLocInfo> +class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived, + TypeClass, LocalData> { +public: + SourceLocation getSigilLoc() const { + return this->getLocalData()->StarLoc; } - void setStarLoc(SourceLocation Loc) { - getLocalData()->StarLoc = Loc; + void setSigilLoc(SourceLocation Loc) { + this->getLocalData()->StarLoc = Loc; } TypeLoc getPointeeLoc() const { - return getInnerTypeLoc(); + return this->getInnerTypeLoc(); } - /// \brief Find the TypeSpecLoc that is part of this MemberPointerLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getPointeeLoc().getTypeSpecLoc(); + SourceRange getSourceRange() const { + return SourceRange(getSigilLoc(), getSigilLoc()); } - SourceRange getSourceRange() const { - return SourceRange(getStarLoc(), getStarLoc()); + void initializeLocal(SourceLocation Loc) { + setSigilLoc(Loc); } - bool hasInnerType() const { return true; } - QualType getInnerType() const { return getTypePtr()->getPointeeType(); } + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } }; -struct ReferenceLocInfo { - SourceLocation AmpLoc; +/// \brief Wrapper for source info for pointers. +class PointerTypeLoc : public PointerLikeTypeLoc<PointerTypeLoc, + PointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } }; -/// \brief Wrapper for source info for references. -class ReferenceLoc : public ConcreteTypeLoc<DeclaratorLoc, - ReferenceLoc, - ReferenceType, - ReferenceLocInfo> { + +/// \brief Wrapper for source info for block pointers. +class BlockPointerTypeLoc : public PointerLikeTypeLoc<BlockPointerTypeLoc, + BlockPointerType> { public: - SourceLocation getAmpLoc() const { - return getLocalData()->AmpLoc; + SourceLocation getCaretLoc() const { + return getSigilLoc(); } - void setAmpLoc(SourceLocation Loc) { - getLocalData()->AmpLoc = Loc; + void setCaretLoc(SourceLocation Loc) { + setSigilLoc(Loc); } +}; - TypeLoc getPointeeLoc() const { - return TypeLoc(getTypePtr()->getPointeeType(), getNonLocalData()); + +/// \brief Wrapper for source info for member pointers. +class MemberPointerTypeLoc : public PointerLikeTypeLoc<MemberPointerTypeLoc, + MemberPointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); } +}; - /// \brief Find the TypeSpecLoc that is part of this ReferenceLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getPointeeLoc().getTypeSpecLoc(); + +class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc, + ReferenceType> { +public: + QualType getInnerType() const { + return getTypePtr()->getPointeeTypeAsWritten(); } +}; - SourceRange getSourceRange() const { - return SourceRange(getAmpLoc(), getAmpLoc()); +class LValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + LValueReferenceTypeLoc, + LValueReferenceType> { +public: + SourceLocation getAmpLoc() const { + return getSigilLoc(); + } + void setAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); } +}; - bool hasInnerType() const { return true; } - QualType getInnerType() const { return getTypePtr()->getPointeeType(); } +class RValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + RValueReferenceTypeLoc, + RValueReferenceType> { +public: + SourceLocation getAmpAmpLoc() const { + return getSigilLoc(); + } + void setAmpAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } }; @@ -563,10 +665,10 @@ struct FunctionLocInfo { }; /// \brief Wrapper for source info for functions. -class FunctionLoc : public ConcreteTypeLoc<DeclaratorLoc, - FunctionLoc, - FunctionType, - FunctionLocInfo> { +class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + FunctionTypeLoc, + FunctionType, + FunctionLocInfo> { // ParmVarDecls* are stored after Info, one for each argument. ParmVarDecl **getParmArray() const { return (ParmVarDecl**) getExtraLocalData(); @@ -601,24 +703,38 @@ public: return getInnerTypeLoc(); } - /// \brief Find the TypeSpecLoc that is part of this FunctionLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getResultLoc().getTypeSpecLoc(); - } SourceRange getSourceRange() const { return SourceRange(getLParenLoc(), getRParenLoc()); } + void initializeLocal(SourceLocation Loc) { + setLParenLoc(Loc); + setRParenLoc(Loc); + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) + setArg(i, NULL); + } + /// \brief Returns the size of the type source info data block that is /// specific to this type. unsigned getExtraLocalDataSize() const { return getNumArgs() * sizeof(ParmVarDecl*); } - bool hasInnerType() const { return true; } QualType getInnerType() const { return getTypePtr()->getResultType(); } }; +class FunctionProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionProtoTypeLoc, + FunctionProtoType> { +}; + +class FunctionNoProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionNoProtoTypeLoc, + FunctionNoProtoType> { +}; + struct ArrayLocInfo { SourceLocation LBracketLoc, RBracketLoc; @@ -626,10 +742,10 @@ struct ArrayLocInfo { }; /// \brief Wrapper for source info for arrays. -class ArrayLoc : public ConcreteTypeLoc<DeclaratorLoc, - ArrayLoc, - ArrayType, - ArrayLocInfo> { +class ArrayTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ArrayTypeLoc, + ArrayType, + ArrayLocInfo> { public: SourceLocation getLBracketLoc() const { return getLocalData()->LBracketLoc; @@ -656,18 +772,108 @@ public: return getInnerTypeLoc(); } - /// \brief Find the TypeSpecLoc that is part of this ArrayLoc. - TypeSpecLoc getTypeSpecLoc() const { - return getElementLoc().getTypeSpecLoc(); - } SourceRange getSourceRange() const { return SourceRange(getLBracketLoc(), getRBracketLoc()); } - bool hasInnerType() const { return true; } + void initializeLocal(SourceLocation Loc) { + setLBracketLoc(Loc); + setRBracketLoc(Loc); + setSizeExpr(NULL); + } + QualType getInnerType() const { return getTypePtr()->getElementType(); } }; +class ConstantArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + ConstantArrayTypeLoc, + ConstantArrayType> { +}; + +class IncompleteArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + IncompleteArrayTypeLoc, + IncompleteArrayType> { +}; + +class DependentSizedArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + DependentSizedArrayTypeLoc, + DependentSizedArrayType> { + +}; + +class VariableArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + VariableArrayTypeLoc, + VariableArrayType> { +}; + +// None of these types have proper implementations yet. + +class VectorTypeLoc : public TypeSpecTypeLoc<VectorTypeLoc, VectorType> { +}; + +class ExtVectorTypeLoc : public InheritingConcreteTypeLoc<VectorTypeLoc, + ExtVectorTypeLoc, + ExtVectorType> { +}; + +// For some reason, this isn't a subtype of VectorType. +class DependentSizedExtVectorTypeLoc : + public TypeSpecTypeLoc<DependentSizedExtVectorTypeLoc, + DependentSizedExtVectorType> { +}; + +class FixedWidthIntTypeLoc : public TypeSpecTypeLoc<FixedWidthIntTypeLoc, + FixedWidthIntType> { +}; + +class ComplexTypeLoc : public TypeSpecTypeLoc<ComplexTypeLoc, + ComplexType> { +}; + +class TypeOfExprTypeLoc : public TypeSpecTypeLoc<TypeOfExprTypeLoc, + TypeOfExprType> { +}; + +class TypeOfTypeLoc : public TypeSpecTypeLoc<TypeOfTypeLoc, TypeOfType> { +}; + +class DecltypeTypeLoc : public TypeSpecTypeLoc<DecltypeTypeLoc, DecltypeType> { +}; + +class TagTypeLoc : public TypeSpecTypeLoc<TagTypeLoc, TagType> { +}; + +class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + RecordTypeLoc, + RecordType> { +}; + +class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + EnumTypeLoc, + EnumType> { +}; + +class ElaboratedTypeLoc : public TypeSpecTypeLoc<ElaboratedTypeLoc, + ElaboratedType> { +}; + +class TemplateSpecializationTypeLoc + : public TypeSpecTypeLoc<TemplateSpecializationTypeLoc, + TemplateSpecializationType> { +}; + +class QualifiedNameTypeLoc : public TypeSpecTypeLoc<QualifiedNameTypeLoc, + QualifiedNameType> { +}; + +class TypenameTypeLoc : public TypeSpecTypeLoc<TypenameTypeLoc, + TypenameType> { +}; + } #endif diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h new file mode 100644 index 0000000..4e1fbaa --- /dev/null +++ b/include/clang/AST/TypeLocBuilder.h @@ -0,0 +1,122 @@ +//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines TypeLocBuilder, a class for building TypeLocs +// bottom-up. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPELOCBUILDER_H +#define LLVM_CLANG_AST_TYPELOCBUILDER_H + +#include "clang/AST/TypeLoc.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class TypeLocBuilder { + enum { InlineCapacity = 8 * sizeof(SourceLocation) }; + + /// The underlying location-data buffer. Data grows from the end + /// of the buffer backwards. + char *Buffer; + + /// The capacity of the current buffer. + size_t Capacity; + + /// The index of the first occupied byte in the buffer. + size_t Index; + +#ifndef NDEBUG + /// The last type pushed on this builder. + QualType LastTy; +#endif + + /// The inline buffer. + char InlineBuffer[InlineCapacity]; + + public: + TypeLocBuilder() + : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) + {} + + ~TypeLocBuilder() { + if (Buffer != InlineBuffer) + delete[] Buffer; + } + + /// Ensures that this buffer has at least as much capacity as described. + void reserve(size_t Requested) { + if (Requested > Capacity) + // For now, match the request exactly. + grow(Requested); + } + + /// Pushes space for a new TypeLoc onto the given type. Invalidates + /// any TypeLocs previously retrieved from this builder. + template <class TyLocType> TyLocType push(QualType T) { +#ifndef NDEBUG + QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); + assert(TLast == LastTy && + "mismatch between last type and new type's inner type"); + LastTy = T; +#endif + + size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize(); + + // If we need to grow, grow by a factor of 2. + if (LocalSize > Index) { + size_t RequiredCapacity = Capacity + (LocalSize - Index); + size_t NewCapacity = Capacity * 2; + while (RequiredCapacity > NewCapacity) + NewCapacity *= 2; + grow(NewCapacity); + } + + Index -= LocalSize; + + return cast<TyLocType>(TypeLoc(T, &Buffer[Index])); + } + + /// Creates a DeclaratorInfo for the given type. + DeclaratorInfo *getDeclaratorInfo(ASTContext& Context, QualType T) { +#ifndef NDEBUG + assert(T == LastTy && "type doesn't match last type pushed!"); +#endif + + size_t FullDataSize = Capacity - Index; + DeclaratorInfo *DI = Context.CreateDeclaratorInfo(T, FullDataSize); + memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); + return DI; + } + + private: + /// Grow to the given capacity. + void grow(size_t NewCapacity) { + assert(NewCapacity > Capacity); + + // Allocate the new buffer and copy the old data into it. + char *NewBuffer = new char[NewCapacity]; + unsigned NewIndex = Index + NewCapacity - Capacity; + memcpy(&NewBuffer[NewIndex], + &Buffer[Index], + Capacity - Index); + + if (Buffer != InlineBuffer) + delete[] Buffer; + + Buffer = NewBuffer; + Capacity = NewCapacity; + Index = NewIndex; + } +}; + +} + +#endif diff --git a/include/clang/AST/TypeLocNodes.def b/include/clang/AST/TypeLocNodes.def index ecf7cc5..4590e48 100644 --- a/include/clang/AST/TypeLocNodes.def +++ b/include/clang/AST/TypeLocNodes.def @@ -7,54 +7,32 @@ // //===----------------------------------------------------------------------===// // -// This file defines the TypeLoc info database. Each node is -// enumerated by providing its name (e.g., "PointerLoc" or "ArrayLoc"), -// base class (e.g., "TypeSpecLoc" or "DeclaratorLoc"), and the Type subclass -// that the TypeLoc is associated with. +// This file defines the TypeLoc info database. Each node is +// enumerated by providing its core name (e.g., "Pointer" for "PointerTypeLoc") +// and base class (e.g., "DeclaratorLoc"). All nodes except QualifiedTypeLoc +// are associated // -// TYPELOC(Class, Base) - A TypeLoc subclass. +// TYPELOC(Class, Base) - A TypeLoc subclass. If UNQUAL_TYPELOC is +// provided, there will be exactly one of these, Qualified. // // UNQUAL_TYPELOC(Class, Base, Type) - An UnqualTypeLoc subclass. // // ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc. // -// TYPESPEC_TYPELOC(Class, Type) - A TypeLoc referring to a type-spec type. -// -// DECLARATOR_TYPELOC(Class, Type) - A TypeLoc referring to a type part of -// a declarator, excluding type-spec types. -// //===----------------------------------------------------------------------===// #ifndef UNQUAL_TYPELOC -# define UNQUAL_TYPELOC(Class, Base, Type) TYPELOC(Class, Base) +# define UNQUAL_TYPELOC(Class, Base) TYPELOC(Class, Base) #endif #ifndef ABSTRACT_TYPELOC -# define ABSTRACT_TYPELOC(Class) TYPELOC(Class, TypeLoc) -#endif - -#ifndef TYPESPEC_TYPELOC -# define TYPESPEC_TYPELOC(Class, Type) UNQUAL_TYPELOC(Class, TypeSpecLoc, Type) +# define ABSTRACT_TYPELOC(Class, Base) UNQUAL_TYPELOC(Class, Base) #endif -#ifndef DECLARATOR_TYPELOC -# define DECLARATOR_TYPELOC(Class, Type) UNQUAL_TYPELOC(Class, DeclaratorLoc, Type) -#endif - -TYPESPEC_TYPELOC(DefaultTypeSpecLoc, Type) -TYPESPEC_TYPELOC(TypedefLoc, TypedefType) -TYPESPEC_TYPELOC(ObjCInterfaceLoc, ObjCInterfaceType) -TYPESPEC_TYPELOC(ObjCProtocolListLoc, ObjCProtocolListType) -DECLARATOR_TYPELOC(PointerLoc, PointerType) -DECLARATOR_TYPELOC(BlockPointerLoc, BlockPointerType) -DECLARATOR_TYPELOC(MemberPointerLoc, MemberPointerType) -DECLARATOR_TYPELOC(ReferenceLoc, ReferenceType) -DECLARATOR_TYPELOC(FunctionLoc, FunctionType) -DECLARATOR_TYPELOC(ArrayLoc, ArrayType) -ABSTRACT_TYPELOC(DeclaratorLoc) -ABSTRACT_TYPELOC(TypeSpecLoc) -TYPELOC(QualifiedLoc, TypeLoc) - +TYPELOC(Qualified, TypeLoc) +#define TYPE(Class, Base) UNQUAL_TYPELOC(Class, Base##Loc) +#define ABSTRACT_TYPE(Class, Base) ABSTRACT_TYPELOC(Class, Base##Loc) +#include "clang/AST/TypeNodes.def" #undef DECLARATOR_TYPELOC #undef TYPESPEC_TYPELOC diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h index a96757f..a62bb3f 100644 --- a/include/clang/AST/TypeLocVisitor.h +++ b/include/clang/AST/TypeLocVisitor.h @@ -15,46 +15,38 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeVisitor.h" +#include "llvm/Support/ErrorHandling.h" namespace clang { -#define DISPATCH(CLASS) \ - return static_cast<ImplClass*>(this)->Visit ## CLASS(cast<CLASS>(TyLoc)) +#define DISPATCH(CLASSNAME) \ + return static_cast<ImplClass*>(this)-> \ + Visit##CLASSNAME(cast<CLASSNAME>(TyLoc)) template<typename ImplClass, typename RetTy=void> class TypeLocVisitor { - class TypeDispatch : public TypeVisitor<TypeDispatch, RetTy> { - ImplClass *Impl; - UnqualTypeLoc TyLoc; - - public: - TypeDispatch(ImplClass *impl, UnqualTypeLoc &tyLoc) - : Impl(impl), TyLoc(tyLoc) { } -#define TYPELOC(CLASS, BASE) -#define ABSTRACT_TYPELOC(CLASS) -#define UNQUAL_TYPELOC(CLASS, PARENT, TYPE) \ - RetTy Visit##TYPE(TYPE *) { \ - return Impl->Visit##CLASS(reinterpret_cast<CLASS&>(TyLoc)); \ - } -#include "clang/AST/TypeLocNodes.def" - }; - public: RetTy Visit(TypeLoc TyLoc) { - if (isa<QualifiedLoc>(TyLoc)) - return static_cast<ImplClass*>(this)-> - VisitQualifiedLoc(cast<QualifiedLoc>(TyLoc)); - - return Visit(cast<UnqualTypeLoc>(TyLoc)); + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm::llvm_unreachable("unexpected type loc class!"); } RetTy Visit(UnqualTypeLoc TyLoc) { - TypeDispatch TD(static_cast<ImplClass*>(this), TyLoc); - return TD.Visit(TyLoc.getSourceTypePtr()); + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } } #define TYPELOC(CLASS, PARENT) \ - RetTy Visit##CLASS(CLASS TyLoc) { \ + RetTy Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ DISPATCH(PARENT); \ } #include "clang/AST/TypeLocNodes.def" diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 6c6bd20..c272123 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -62,8 +62,6 @@ TYPE(RValueReference, ReferenceType) TYPE(MemberPointer, Type) ABSTRACT_TYPE(Array, Type) TYPE(ConstantArray, ArrayType) -NON_CANONICAL_TYPE(ConstantArrayWithExpr, ConstantArrayType) -NON_CANONICAL_TYPE(ConstantArrayWithoutExpr, ConstantArrayType) TYPE(IncompleteArray, ArrayType) TYPE(VariableArray, ArrayType) DEPENDENT_TYPE(DependentSizedArray, ArrayType) @@ -82,12 +80,12 @@ TYPE(Record, TagType) TYPE(Enum, TagType) NON_CANONICAL_TYPE(Elaborated, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) +NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) TYPE(TemplateSpecialization, Type) NON_CANONICAL_TYPE(QualifiedName, Type) DEPENDENT_TYPE(Typename, Type) TYPE(ObjCInterface, Type) TYPE(ObjCObjectPointer, Type) -NON_CANONICAL_TYPE(ObjCProtocolList, Type) // These types are always leaves in the type hierarchy. #ifdef LEAF_TYPE @@ -95,7 +93,6 @@ LEAF_TYPE(Enum) LEAF_TYPE(Builtin) LEAF_TYPE(FixedWidthInt) LEAF_TYPE(ObjCInterface) -LEAF_TYPE(ObjCObjectPointer) LEAF_TYPE(TemplateTypeParm) #undef LEAF_TYPE #endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index ffe282d..8e02ccf 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -60,6 +60,9 @@ public: ~AnalysisContextManager(); AnalysisContext *getContext(const Decl *D); + + // Discard all previously created AnalysisContexts. + void clear(); }; class LocationContext : public llvm::FoldingSetNode { @@ -155,12 +158,17 @@ class LocationContextManager { llvm::FoldingSet<LocationContext> Contexts; public: + ~LocationContextManager(); + StackFrameContext *getStackFrame(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s); ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s); + + /// Discard all previously created LocationContext objects. + void clear(); }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h index e97f805..1a64f56 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisManager.h +++ b/include/clang/Analysis/PathSensitive/AnalysisManager.h @@ -65,6 +65,11 @@ public: AScope(ScopeDecl), DisplayedFunction(!displayProgress), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), EagerlyAssume(eager), TrimGraph(trim) {} + + void ClearContexts() { + LocCtxMgr.clear(); + AnaCtxMgr.clear(); + } StoreManagerCreator getStoreManagerCreator() { return CreateStoreMgr; diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 3ff253d..7a462c5 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -141,9 +141,12 @@ public: const VarDecl *VD, const LocationContext *LC) = 0; + typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; + virtual const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count) = 0; + const Expr *E, unsigned Count, + InvalidatedSymbols *IS) = 0; // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index a5e11a1..b23a80e 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -27,16 +27,16 @@ namespace clang { class BumpVectorContext { - llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1, bool> Alloc; + llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc; public: /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator /// and destroys it when the BumpVectorContext object is destroyed. - BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), true) {} + BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {} /// Construct a new BumpVectorContext that reuses an existing /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the /// BumpVectorContext object is destroyed. - BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, false) {} + BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {} ~BumpVectorContext() { if (Alloc.getInt()) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 380192e..005aab3 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_DIAGNOSTIC_H #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/type_traits.h" #include <string> #include <vector> @@ -43,7 +44,7 @@ namespace clang { 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_START_ANALYSIS = DIAG_START_SEMA + 1100, DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 }; @@ -107,7 +108,7 @@ public: /// \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) { + llvm::StringRef Code) { CodeModificationHint Hint; Hint.InsertionLoc = InsertionLoc; Hint.CodeToInsert = Code; @@ -125,7 +126,7 @@ public: /// \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) { + llvm::StringRef Code) { CodeModificationHint Hint; Hint.RemoveRange = RemoveRange; Hint.InsertionLoc = RemoveRange.getBegin(); @@ -163,6 +164,10 @@ public: ak_nestednamespec, // NestedNameSpecifier * ak_declcontext // DeclContext * }; + + /// ArgumentValue - This typedef represents on argument value, which is a + /// union discriminated by ArgumentKind, with a value. + typedef std::pair<ArgumentKind, intptr_t> ArgumentValue; private: unsigned char AllExtensionsSilenced; // Used by __extension__ @@ -202,10 +207,17 @@ private: /// 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. + /// + /// The PrevArgs array (whose length is NumPrevArgs) indicates the previous + /// arguments formatted for this diagnostic. Implementations of this function + /// can use this information to avoid redundancy across arguments. + /// /// 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, + const ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output, void *Cookie); void *ArgToStringCookie; @@ -310,9 +322,10 @@ public: void ConvertArgToString(ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, + const ArgumentValue *PrevArgs, unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output) const { - ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output, - ArgToStringCookie); + ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, + PrevArgs, NumPrevArgs, Output, ArgToStringCookie); } void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { @@ -546,7 +559,7 @@ public: /// return Diag(...); operator bool() const { return true; } - void AddString(const std::string &S) const { + void AddString(llvm::StringRef S) const { assert(NumArgs < Diagnostic::MaxArguments && "Too many arguments to diagnostic!"); if (DiagObj) { @@ -581,7 +594,7 @@ public: }; inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const std::string &S) { + llvm::StringRef S) { DB.AddString(S); return DB; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 6971df5..19b0ea3 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -201,6 +201,9 @@ 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 warn_semicolon_before_method_nody : Warning< + "semicolon before method body is ignored">, + InGroup<DiagGroup<"semicolon-before-method-body">>; def err_expected_field_designator : Error< "expected a field designator, such as '.field = 4'">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b1222a3..7a87e24 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -383,6 +383,8 @@ def note_ambig_member_ref_object_type : Note< "lookup in the object type %0 refers here">; def note_ambig_member_ref_scope : Note< "lookup from the current scope refers here">; +def err_qualified_member_nonclass : Error< + "qualified member access refers to a member in %0">; // C++ class members def err_storageclass_invalid_for_member : Error< @@ -785,9 +787,9 @@ def err_ovl_template_candidate : Note< def err_ovl_candidate_deleted : Note< "candidate function has been explicitly %select{made unavailable|deleted}0">; def err_ovl_builtin_binary_candidate : Note< - "built-in candidate operator %0 (%1, %2)">; + "built-in candidate %0">; def err_ovl_builtin_unary_candidate : Note< - "built-in candidate operator %0 (%1)">; + "built-in candidate %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">; @@ -1112,7 +1114,17 @@ def err_explicit_instantiation_without_qualified_id_quals : Error< "qualifier in explicit instantiation of '%0%1' requires a template-id">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< "explicit instantiation of %q0 must occur in %1">; - +def err_explicit_instantiation_undefined_member : Error< + "explicit instantiation of undefined %select{member class|member function|" + "static data member}0 %1 of class template %2">; +def err_explicit_instantiation_undefined_func_template : Error< + "explicit instantiation of undefined function template %0">; +def err_explicit_instantiation_declaration_after_definition : Error< + "explicit instantiation declaration (with 'extern') follows explicit " + "instantiation definition (without 'extern')">; +def note_explicit_instantiation_definition_here : Note< + "explicit instantiation definition is here">; + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_type : Error< @@ -1734,7 +1746,9 @@ def err_not_tag_in_scope : Error< def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; - +def err_incomplete_object_call : Error< + "incomplete type in call to object of type %0">; + def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup<Parentheses>; @@ -2156,6 +2170,8 @@ def err_break_not_in_loop_or_switch : Error< 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_bool_switch_condition : Warning< + "switch condition is a bool">; 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'">; @@ -2187,7 +2203,7 @@ def ext_return_has_expr : ExtWarn< 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, + "function %0 declared 'noreturn' should not return">, InGroup<DiagGroup<"invalid-noreturn">>; def warn_falloff_noreturn_function : Warning< "function declared 'noreturn' should not return">, diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index 7c9113c..5e7ac4f 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -71,16 +71,38 @@ public: } }; -// 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. +/// \brief Abstract interface for introducing a FileManager cache for 'stat' +/// system calls, which is used by precompiled and pretokenized headers to +/// improve performance. class StatSysCallCache { +protected: + llvm::OwningPtr<StatSysCallCache> NextStatCache; + public: virtual ~StatSysCallCache() {} - virtual int stat(const char *path, struct stat *buf) = 0; + virtual int stat(const char *path, struct stat *buf) { + if (getNextStatCache()) + return getNextStatCache()->stat(path, buf); + + return ::stat(path, buf); + } + + /// \brief Sets the next stat call cache in the chain of stat caches. + /// Takes ownership of the given stat cache. + void setNextStatCache(StatSysCallCache *Cache) { + NextStatCache.reset(Cache); + } + + /// \brief Retrieve the next stat call cache in the chain. + StatSysCallCache *getNextStatCache() { return NextStatCache.get(); } + + /// \brief Retrieve the next stat call cache in the chain, transferring + /// ownership of this cache (and, transitively, all of the remaining caches) + /// to the caller. + StatSysCallCache *takeNextStatCache() { return NextStatCache.take(); } }; -/// \brief A stat listener that can be used by FileManager to keep +/// \brief A stat "cache" that can be used by FileManager to keep /// track of the results of stat() calls that occur throughout the /// execution of the front end. class MemorizeStatCalls : public StatSysCallCache { @@ -144,13 +166,22 @@ 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); - } - + /// \brief Installs the provided StatSysCallCache object within + /// the FileManager. + /// + /// Ownership of this object is transferred to the FileManager. + /// + /// \param statCache the new stat cache to install. Ownership of this + /// object is transferred to the FileManager. + /// + /// \param AtBeginning whether this new stat cache must be installed at the + /// beginning of the chain of stat caches. Otherwise, it will be added to + /// the end of the chain. + void addStatCache(StatSysCallCache *statCache, bool AtBeginning = false); + + /// \brief Removes the provided StatSysCallCache object from the file manager. + void removeStatCache(StatSysCallCache *statCache); + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 84c2fc9..e06dfbb 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -75,13 +75,13 @@ public: /// 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); + return getLength() == StrLen-1 && !memcmp(getNameStart(), Str, StrLen-1); } - /// getName - Return the actual string for this identifier. The returned - /// string is properly null terminated. + /// getNameStart - Return the beginning of the actual string for this + /// identifier. The returned string is properly null terminated. /// - const char *getName() const { + const char *getNameStart() 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. @@ -101,8 +101,12 @@ public: // 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; + return (((unsigned) p[0]) | (((unsigned) p[1]) << 8)) - 1; + } + + /// getName - Return the actual identifier string. + llvm::StringRef getName() const { + return llvm::StringRef(getNameStart(), getLength()); } /// hasMacroDefinition - Return true if this identifier is #defined to some @@ -232,6 +236,8 @@ public: /// Unlike the version in IdentifierTable, this returns a pointer instead /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. + // + // FIXME: Move to StringRef API. virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0; }; @@ -333,8 +339,11 @@ public: return *II; } + IdentifierInfo &CreateIdentifierInfo(llvm::StringRef Name) { + return CreateIdentifierInfo(Name.begin(), Name.end()); + } - IdentifierInfo &get(const llvm::StringRef& Name) { + IdentifierInfo &get(llvm::StringRef Name) { return get(Name.begin(), Name.end()); } @@ -463,7 +472,7 @@ public: const IdentifierInfo *Name) { llvm::SmallString<100> SelectorName; SelectorName = "set"; - SelectorName.append(Name->getName(), Name->getName()+Name->getLength()); + SelectorName += Name->getName(); SelectorName[3] = toupper(SelectorName[3]); IdentifierInfo *SetterName = &Idents.get(SelectorName.data(), diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 6524516..2184bf3 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -25,27 +25,6 @@ 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; diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 7eb988f..8a69cba 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -685,26 +685,19 @@ public: /// 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"); + const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const { + assert(ID < SLocEntryTable.size() && "Invalid id"); if (ExternalSLocEntries && - FID.ID < SLocEntryLoaded.size() && - !SLocEntryLoaded[FID.ID]) - ExternalSLocEntries->ReadSLocEntry(FID.ID); - return SLocEntryTable[FID.ID]; + ID < SLocEntryLoaded.size() && + !SLocEntryLoaded[ID]) + ExternalSLocEntries->ReadSLocEntry(ID); + return SLocEntryTable[ID]; + } + + const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { + return getSLocEntry(FID.ID); } unsigned getNextOffset() const { return NextOffset; } diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index a1e0a17..b88e2aa 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -83,7 +83,7 @@ public: }; protected: IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, - Char16Type, Char32Type, Int64Type; + WIntType, Char16Type, Char32Type, Int64Type; public: IntType getSizeType() const { return SizeType; } IntType getIntMaxType() const { return IntMaxType; } @@ -93,10 +93,20 @@ public: } IntType getIntPtrType() const { return IntPtrType; } IntType getWCharType() const { return WCharType; } + IntType getWIntType() const { return WIntType; } IntType getChar16Type() const { return Char16Type; } IntType getChar32Type() const { return Char32Type; } IntType getInt64Type() const { return Int64Type; } + + /// getTypeWidth - Return the width (in bits) of the specified integer type + /// enum. For example, SignedInt -> getIntWidth(). + unsigned getTypeWidth(IntType T) const; + + /// getTypeSigned - Return whether an integer types is signed. Returns true if + /// the type is signed; false otherwise. + bool getTypeSigned(IntType T) const; + /// getPointerWidth - Return the width of pointers on this target, for the /// specified address space. uint64_t getPointerWidth(unsigned AddrSpace) const { @@ -185,6 +195,10 @@ public: /// For example, SignedShort -> "short". static const char *getTypeName(IntType T); + /// getTypeConstantSuffix - Return the constant suffix for the specified + /// integer type enum. For example, SignedLong -> "L". + static const char *getTypeConstantSuffix(IntType T); + ///===---- Other target property query methods --------------------------===// /// getTargetDefines - Appends the target-specific #define values for this @@ -192,6 +206,7 @@ public: 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. diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 89eb3b8..9573777 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -16,6 +16,8 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/OwningPtr.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Basic/FileManager.h" #include <string> namespace clang { @@ -23,6 +25,7 @@ namespace clang { class FileEntry; class SourceManager; class Diagnostic; + class TextDiagnosticBuffer; class HeaderSearch; class TargetInfo; class Preprocessor; @@ -32,18 +35,27 @@ namespace clang { /// \brief Utility class for loading a ASTContext from a PCH file. /// class ASTUnit { - Diagnostic &Diags; + Diagnostic Diags; + FileManager FileMgr; + SourceManager SourceMgr; llvm::OwningPtr<HeaderSearch> HeaderInfo; llvm::OwningPtr<TargetInfo> Target; llvm::OwningPtr<Preprocessor> PP; llvm::OwningPtr<ASTContext> Ctx; - + bool tempFile; + + // OnlyLocalDecls - when true, walking this AST should only visit declarations + // that come from the AST itself, not from included precompiled headers. + // FIXME: This is temporary; eventually, CIndex will always do this. + bool OnlyLocalDecls; + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT - ASTUnit(Diagnostic &_Diag); + ASTUnit(); public: + ASTUnit(DiagnosticClient *diagClient = NULL); ~ASTUnit(); const SourceManager &getSourceManager() const { return SourceMgr; } @@ -58,14 +70,23 @@ public: const Diagnostic &getDiagnostic() const { return Diags; } Diagnostic &getDiagnostic() { return Diags; } - FileManager &getFileManager(); + const FileManager &getFileManager() const { return FileMgr; } + FileManager &getFileManager() { return FileMgr; } + const std::string &getOriginalSourceFileName(); + const std::string &getPCHFileName(); + void unlinkTemporaryFile() { tempFile = true; } + + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + /// \brief Create a ASTUnit from a PCH file. /// /// \param Filename - The PCH file to load. /// - /// \param Diags - The Diagnostic implementation to use. + /// \param diagClient - The diagnostics client to use. Specify NULL + /// to use a default client that emits warnings/errors to standard error. + /// The ASTUnit objects takes ownership of this object. /// /// \param FileMgr - The FileManager to use. /// @@ -74,9 +95,10 @@ public: /// /// \returns - The initialized ASTUnit or null if the PCH failed to load. static ASTUnit *LoadFromPCHFile(const std::string &Filename, - Diagnostic &Diags, - FileManager &FileMgr, - std::string *ErrMsg = 0); + std::string *ErrMsg = 0, + DiagnosticClient *diagClient = NULL, + bool OnlyLocalDecls = false, + bool UseBumpAllocator = false); }; } // namespace clang diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 716780e..1e953d6 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -86,38 +86,33 @@ namespace clang { 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 + /// types and decls used within the PCH file. + DECLTYPES_BLOCK_ID }; /// \brief Record types that occur within the PCH block itself. enum PCHRecordTypes { - /// \brief Offset of each type within the types block. + /// \brief Record code for the offsets of each type. /// /// 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 + /// within the PCH block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). 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. + /// corresponding record within the DECLTYPES_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 + /// within the block identified by DECL_OFFSETS_BLOCK_ID within + /// the PCH block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_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. @@ -353,8 +348,8 @@ namespace clang { /// \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 + /// These constants describe the type records that can occur within a + /// block identified by DECLTYPES_BLOCK_ID in the PCH file. Each /// constant describes a record for a specific type class in the /// AST. enum TypeCode { @@ -402,16 +397,12 @@ namespace clang { TYPE_OBJC_INTERFACE = 21, /// \brief An ObjCObjectPointerType record. TYPE_OBJC_OBJECT_POINTER = 22, - /// \brief An ObjCProtocolListType record. - TYPE_OBJC_PROTOCOL_LIST = 23, /// \brief a DecltypeType record. - TYPE_DECLTYPE = 24, - /// \brief A ConstantArrayWithExprType record. - TYPE_CONSTANT_ARRAY_WITH_EXPR = 25, - /// \brief A ConstantArrayWithoutExprType record. - TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 26, + TYPE_DECLTYPE = 23, /// \brief An ElaboratedType record. - TYPE_ELABORATED = 27 + TYPE_ELABORATED = 24, + /// \brief A SubstTemplateTypeParmType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM = 25 }; /// \brief The type IDs for special types constructed by semantic @@ -443,18 +434,22 @@ namespace clang { /// \brief Objective-C "id" redefinition type SPECIAL_TYPE_OBJC_ID_REDEFINITION = 10, /// \brief Objective-C "Class" redefinition type - SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 11 + SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 11, + /// \brief Block descriptor type for Blocks CodeGen + SPECIAL_TYPE_BLOCK_DESCRIPTOR = 12, + /// \brief Block extedned descriptor type for Blocks CodeGen + SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13 }; /// \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 + /// These constants describe the declaration 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, + DECL_ATTR = 50, /// \brief A TranslationUnitDecl record. DECL_TRANSLATION_UNIT, /// \brief A TypedefDecl record. @@ -529,14 +524,14 @@ namespace clang { /// \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. + /// or expressions. These records occur within type and declarations + /// block, so they begin with record values of 100. 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, + STMT_STOP = 100, /// \brief A NULL expression. STMT_NULL_PTR, /// \brief A NullStmt record. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 1230e37..cc16970 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -169,6 +169,11 @@ private: /// \brief The AST context into which we'll read the PCH file. ASTContext *Context; + /// \brief The PCH stat cache installed by this PCHReader, if any. + /// + /// The dynamic type of this stat cache is always PCHStatCache + void *StatCache; + /// \brief The AST consumer. ASTConsumer *Consumer; @@ -492,8 +497,8 @@ public: /// \param isysroot If non-NULL, the system include path specified by the /// user. This is only used with relocatable PCH files. If non-NULL, /// a relocatable PCH file will use the default path "/". - PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot = 0); + PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags, const char *isysroot = 0); ~PCHReader(); /// \brief Load the precompiled header designated by the given file @@ -513,6 +518,9 @@ public: /// \brief Sets and initializes the given Context. void InitializeContext(ASTContext &Context); + /// \brief Retrieve the name of the PCH file + const std::string &getFileName() { return FileName; } + /// \brief Retrieve the name of the original source file name const std::string &getOriginalSourceFile() { return OriginalFileName; } @@ -534,6 +542,10 @@ public: /// comments in the source code. virtual void ReadComments(std::vector<SourceRange> &Comments); + /// \brief Reads a declarator info from the given record. + virtual DeclaratorInfo *GetDeclaratorInfo(const RecordData &Record, + unsigned &Idx); + /// \brief Resolve a type ID into a type, potentially building a new /// type. virtual QualType GetType(pch::TypeID ID); diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index a807cd7..728e138 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -73,6 +73,33 @@ private: /// \brief The bitstream writer used to emit this precompiled header. llvm::BitstreamWriter &Stream; + /// \brief Stores a declaration or a type to be written to the PCH file. + class DeclOrType { + public: + DeclOrType(Decl *D) : Stored(D), IsType(false) { } + DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) { } + + bool isType() const { return IsType; } + bool isDecl() const { return !IsType; } + + QualType getType() const { + assert(isType() && "Not a type!"); + return QualType::getFromOpaquePtr(Stored); + } + + Decl *getDecl() const { + assert(isDecl() && "Not a decl!"); + return static_cast<Decl *>(Stored); + } + + private: + void *Stored; + bool IsType; + }; + + /// \brief The declarations and types to emit. + std::queue<DeclOrType> DeclTypesToEmit; + /// \brief Map that provides the ID numbers of each declaration within /// the output stream. /// @@ -85,10 +112,6 @@ private: /// 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. /// @@ -107,10 +130,6 @@ private: /// \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<QualType> TypesToEmit; - /// \brief Map that provides the ID numbers of each identifier in /// the output stream. /// @@ -189,18 +208,17 @@ private: void WritePreprocessor(const Preprocessor &PP); void WriteComments(ASTContext &Context); void WriteType(QualType T); - void WriteTypesBlock(ASTContext &Context); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); - void WriteDeclsBlock(ASTContext &Context); void WriteMethodPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP); void WriteAttributeRecord(const Attr *Attr); unsigned ParmVarDeclAbbrev; void WriteDeclsBlockAbbrevs(); - + void WriteDecl(ASTContext &Context, Decl *D); + public: /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. @@ -254,6 +272,9 @@ public: /// \brief Emit a reference to a type. void AddTypeRef(QualType T, RecordData &Record); + /// \brief Emits a reference to a declarator info. + void AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record); + /// \brief Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordData &Record); diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h index 9620ec5..fc18dae 100644 --- a/include/clang/Index/ASTLocation.h +++ b/include/clang/Index/ASTLocation.h @@ -91,7 +91,7 @@ public: ASTLocation(const Decl *parentDecl, TypeLoc tyLoc) : ParentDecl(const_cast<Decl*>(parentDecl), N_Type) { if (tyLoc) { - Ty.TyPtr = tyLoc.getSourceType().getAsOpaquePtr(); + Ty.TyPtr = tyLoc.getType().getAsOpaquePtr(); Ty.Data = tyLoc.getOpaqueData(); } else ParentDecl.setPointer(0); @@ -124,8 +124,8 @@ public: return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data); } - Decl *dyn_AsDecl() const { return getKind() == N_Decl ? D : 0; } - Stmt *dyn_AsStmt() const { return getKind() == N_Stmt ? Stm : 0; } + Decl *dyn_AsDecl() const { return isValid() && getKind() == N_Decl ? D : 0; } + Stmt *dyn_AsStmt() const { return isValid() && getKind() == N_Stmt ? Stm : 0; } NamedRef dyn_AsNamedRef() const { return getKind() == N_Type ? AsNamedRef() : NamedRef(); } diff --git a/include/clang/Index/Indexer.h b/include/clang/Index/Indexer.h index 8b1d2dd..361e729 100644 --- a/include/clang/Index/Indexer.h +++ b/include/clang/Index/Indexer.h @@ -14,13 +14,11 @@ #ifndef LLVM_CLANG_INDEX_INDEXER_H #define LLVM_CLANG_INDEX_INDEXER_H -#include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Index/IndexProvider.h" #include "clang/Index/Entity.h" #include "clang/Index/GlobalSelector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMap.h" -#include "clang/Basic/FileManager.h" #include <map> namespace clang { @@ -39,16 +37,10 @@ public: typedef std::map<GlobalSelector, TUSetTy> SelMapTy; explicit Indexer(Program &prog) : - Prog(prog), Diags(&DiagClient) { } + Prog(prog) { } Program &getProgram() const { return Prog; } - Diagnostic &getDiagnostics() { return Diags; } - const Diagnostic &getDiagnostics() const { return Diags; } - - FileManager &getFileManager() { return FileMgr; } - const FileManager &getFileManager() const { return FileMgr; } - /// \brief Find all Entities and map them to the given translation unit. void IndexAST(TranslationUnit *TU); @@ -59,9 +51,6 @@ public: private: Program &Prog; - TextDiagnosticBuffer DiagClient; - Diagnostic Diags; - FileManager FileMgr; MapTy Map; CtxTUMapTy CtxTUMap; diff --git a/include/clang/Index/Utils.h b/include/clang/Index/Utils.h index e78ef8a..36cf56d 100644 --- a/include/clang/Index/Utils.h +++ b/include/clang/Index/Utils.h @@ -18,7 +18,8 @@ namespace clang { class ASTContext; class SourceLocation; - + class Decl; + namespace idx { class ASTLocation; @@ -26,7 +27,8 @@ namespace idx { /// /// \returns the resolved ASTLocation or an invalid ASTLocation if the source /// location could not be resolved. -ASTLocation ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc); +ASTLocation ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, + Decl *RelativeToDecl = 0); } // end namespace idx diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 1ee1470..050b3f4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1390,6 +1390,34 @@ public: return ExprEmpty(); } + /// \brief Parsed a C++ destructor reference that refers to a type. + /// + /// This action is used when parsing a destructor reference that uses a + /// template-id, e.g., + /// + /// \code + /// t->~Tmpl<T1, T2> + /// \endcode + /// + /// \param S the scope in which the destructor reference occurs. + /// \param Base the base object of the destructor reference expression. + /// \param OpLoc the location of the operator ('.' or '->'). + /// \param OpKind the kind of the destructor reference operator ('.' or '->'). + /// \param TypeRange the source range that covers the destructor type. + /// \param Type the type that is being destroyed. + /// \param SS the scope specifier that precedes the destructor name. + /// \param HasTrailingLParen whether the destructor name is followed by a '('. + virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *Type, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + return ExprEmpty(); + } + /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator /// reference, for example: /// @@ -1691,9 +1719,25 @@ public: /// possibly checking well-formedness of the template arguments. It does not /// imply the declaration of any entity. /// + /// \param SS The scope specifier that may precede the template name. + /// /// \param Template A template whose specialization results in a /// function or a dependent template. - virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, + /// + /// \param TemplateNameLoc The location of the template name. + /// + /// \param LAngleLoc The location of the left angle bracket ('<') that starts + /// the template argument list. + /// + /// \param TemplateArgs The template arguments in the template argument list, + /// which may be empty. + /// + /// \param TemplateArgLocs The locations of the template arguments. + /// + /// \param RAngleLoc The location of the right angle bracket ('>') that + /// closes the template argument list. + virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e028186..7f5fa35 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -40,7 +40,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), - sigjmp_bufDecl(0), SourceMgr(SM), LangOpts(LOpts), + sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), + SourceMgr(SM), LangOpts(LOpts), LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { @@ -554,10 +555,6 @@ ASTContext::getTypeInfo(const Type *T) { assert(false && "Should not see dependent types"); break; - case Type::ObjCProtocolList: - assert(false && "Should not see protocol list types"); - break; - case Type::FunctionNoProto: case Type::FunctionProto: // GCC extension: alignof(function) = 32 bits @@ -571,8 +568,6 @@ ASTContext::getTypeInfo(const Type *T) { Align = getTypeAlign(cast<ArrayType>(T)->getElementType()); break; - case Type::ConstantArrayWithExpr: - case Type::ConstantArrayWithoutExpr: case Type::ConstantArray: { const ConstantArrayType *CAT = cast<ConstantArrayType>(T); @@ -583,14 +578,16 @@ ASTContext::getTypeInfo(const Type *T) { } case Type::ExtVector: case Type::Vector: { - std::pair<uint64_t, unsigned> EltInfo = - getTypeInfo(cast<VectorType>(T)->getElementType()); - Width = EltInfo.first*cast<VectorType>(T)->getNumElements(); + const VectorType *VT = cast<VectorType>(T); + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(VT->getElementType()); + Width = EltInfo.first*VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. - // FIXME: this should probably be a target property. - Align = 1 << llvm::Log2_32_Ceil(Align); + if (VT->getNumElements() & (VT->getNumElements()-1)) { + Align = llvm::NextPowerOf2(Align); + Width = llvm::RoundUpToAlignment(Width, Align); + } break; } @@ -749,9 +746,13 @@ ASTContext::getTypeInfo(const Type *T) { break; } - case Type::Elaborated: { - return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr()); - } + case Type::SubstTemplateTypeParm: + return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> + getReplacementType().getTypePtr()); + + case Type::Elaborated: + return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType() + .getTypePtr()); case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); @@ -940,8 +941,14 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, /// \param T the type that will be the basis for type source info. This type /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. -DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) { - unsigned DataSize = TypeLoc::getFullDataSizeForType(T); +DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, + unsigned DataSize) { + if (!DataSize) + DataSize = TypeLoc::getFullDataSizeForType(T); + else + assert(DataSize == TypeLoc::getFullDataSizeForType(T) && + "incorrect data size provided to CreateDeclaratorInfo!"); + DeclaratorInfo *DInfo = (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8); new (DInfo) DeclaratorInfo(T); @@ -1140,7 +1147,7 @@ QualType ASTContext::getComplexType(QualType T) { // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getComplexType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1177,7 +1184,7 @@ QualType ASTContext::getPointerType(QualType T) { // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getPointerType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1207,7 +1214,7 @@ QualType ASTContext::getBlockPointerType(QualType T) { // If the block pointee type isn't canonical, this won't be a canonical // type either so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getBlockPointerType(getCanonicalType(T)); // Get the new insert position for the node we care about. @@ -1224,22 +1231,25 @@ QualType ASTContext::getBlockPointerType(QualType T) { /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. -QualType ASTContext::getLValueReferenceType(QualType T) { +QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T); + ReferenceType::Profile(ID, T, SpelledAsLValue); void *InsertPos = 0; if (LValueReferenceType *RT = LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { - Canonical = getLValueReferenceType(getCanonicalType(T)); + if (!SpelledAsLValue || InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getLValueReferenceType(getCanonicalType(PointeeType)); // Get the new insert position for the node we care about. LValueReferenceType *NewIP = @@ -1248,9 +1258,11 @@ QualType ASTContext::getLValueReferenceType(QualType T) { } LValueReferenceType *New - = new (*this, TypeAlignment) LValueReferenceType(T, Canonical); + = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, + SpelledAsLValue); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); } @@ -1260,18 +1272,21 @@ QualType ASTContext::getRValueReferenceType(QualType T) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T); + ReferenceType::Profile(ID, T, false); void *InsertPos = 0; if (RValueReferenceType *RT = RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { - Canonical = getRValueReferenceType(getCanonicalType(T)); + if (InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getRValueReferenceType(getCanonicalType(PointeeType)); // Get the new insert position for the node we care about. RValueReferenceType *NewIP = @@ -1302,7 +1317,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // If the pointee or class type isn't canonical, this won't be a canonical // type either, so fill in the canonical type field. QualType Canonical; - if (!T->isCanonical()) { + if (!T.isCanonical()) { Canonical = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls)); // Get the new insert position for the node we care about. @@ -1342,7 +1357,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // If the element type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!EltTy->isCanonical()) { + if (!EltTy.isCanonical()) { Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, ASM, EltTypeQuals); // Get the new insert position for the node we care about. @@ -1358,53 +1373,6 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, return QualType(New, 0); } -/// getConstantArrayWithExprType - Return a reference to the type for -/// an array of the specified element type. -QualType -ASTContext::getConstantArrayWithExprType(QualType EltTy, - const llvm::APInt &ArySizeIn, - Expr *ArySizeExpr, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets) { - // Convert the array size into a canonical width matching the pointer - // size for the target. - llvm::APInt ArySize(ArySizeIn); - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - - // Compute the canonical ConstantArrayType. - QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), - ArySize, ASM, EltTypeQuals); - // Since we don't unique expressions, it isn't possible to unique VLA's - // that have an expression provided for their size. - ConstantArrayWithExprType *New = new(*this, TypeAlignment) - ConstantArrayWithExprType(EltTy, Canonical, ArySize, ArySizeExpr, - ASM, EltTypeQuals, Brackets); - Types.push_back(New); - return QualType(New, 0); -} - -/// getConstantArrayWithoutExprType - Return a reference to the type for -/// an array of the specified element type. -QualType -ASTContext::getConstantArrayWithoutExprType(QualType EltTy, - const llvm::APInt &ArySizeIn, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - // Convert the array size into a canonical width matching the pointer - // size for the target. - llvm::APInt ArySize(ArySizeIn); - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - - // Compute the canonical ConstantArrayType. - QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), - ArySize, ASM, EltTypeQuals); - ConstantArrayWithoutExprType *New = new(*this, TypeAlignment) - ConstantArrayWithoutExprType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); - Types.push_back(New); - return QualType(New, 0); -} - /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. QualType ASTContext::getVariableArrayType(QualType EltTy, @@ -1484,7 +1452,7 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, // either, so fill in the canonical type field. QualType Canonical; - if (!EltTy->isCanonical()) { + if (!EltTy.isCanonical()) { Canonical = getIncompleteArrayType(getCanonicalType(EltTy), ASM, EltTypeQuals); @@ -1520,7 +1488,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { // If the element type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!vecType->isCanonical()) { + if (!vecType.isCanonical()) { Canonical = getVectorType(getCanonicalType(vecType), NumElts); // Get the new insert position for the node we care about. @@ -1552,7 +1520,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { // If the element type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!vecType->isCanonical()) { + if (!vecType.isCanonical()) { Canonical = getExtVectorType(getCanonicalType(vecType), NumElts); // Get the new insert position for the node we care about. @@ -1616,7 +1584,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { return QualType(FT, 0); QualType Canonical; - if (!ResultTy->isCanonical()) { + if (!ResultTy.isCanonical()) { Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); // Get the new insert position for the node we care about. @@ -1639,12 +1607,6 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, const QualType *ExArray, bool NoReturn) { - if (LangOpts.CPlusPlus) { - for (unsigned i = 0; i != NumArgs; ++i) - assert(!ArgArray[i].hasQualifiers() && - "C++ arguments can't have toplevel qualifiers!"); - } - // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1658,11 +1620,9 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, return QualType(FTP, 0); // Determine whether the type being created is already canonical or not. - bool isCanonical = ResultTy->isCanonical(); - if (hasExceptionSpec) - isCanonical = false; + bool isCanonical = !hasExceptionSpec && ResultTy.isCanonical(); for (unsigned i = 0; i != NumArgs && isCanonical; ++i) - if (!ArgArray[i]->isCanonical()) + if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; // If this type isn't canonical, get the canonical version of it. @@ -1672,7 +1632,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) - CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); + CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, @@ -1743,6 +1703,29 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +/// \brief Retrieve a substitution-result type. +QualType +ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, + QualType Replacement) { + assert(Replacement.isCanonical() + && "replacement types must always be canonical"); + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); + void *InsertPos = 0; + SubstTemplateTypeParmType *SubstParm + = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!SubstParm) { + SubstParm = new (*this, TypeAlignment) + SubstTemplateTypeParmType(Parm, Replacement); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + } + + return QualType(SubstParm, 0); +} + /// \brief Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. @@ -1933,7 +1916,17 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, return LHS->getDeclName() < RHS->getDeclName(); } -static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, +static bool areSortedAndUniqued(ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + if (NumProtocols == 0) return true; + + for (unsigned i = 1; i != NumProtocols; ++i) + if (!CmpProtocolNames(Protocols[i-1], Protocols[i])) + return false; + return true; +} + +static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, unsigned &NumProtocols) { ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; @@ -1950,10 +1943,6 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - // Sort the protocol list alphabetically to canonicalize it. - if (NumProtocols) - SortAndUniqueProtocols(Protocols, NumProtocols); - llvm::FoldingSetNodeID ID; ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); @@ -1962,9 +1951,31 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); + // Sort the protocol list alphabetically to canonicalize it. + QualType Canonical; + if (!InterfaceT.isCanonical() || + !areSortedAndUniqued(Protocols, NumProtocols)) { + if (!areSortedAndUniqued(Protocols, NumProtocols)) { + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); + unsigned UniqueCount = NumProtocols; + + std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); + SortAndUniqueProtocols(&Sorted[0], UniqueCount); + + Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), + &Sorted[0], UniqueCount); + } else { + Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), + Protocols, NumProtocols); + } + + // Regenerate InsertPos. + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + } + // No Match; ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols); + ObjCObjectPointerType(Canonical, InterfaceT, Protocols, NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -1975,10 +1986,6 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, /// specified ObjC interface decl. The list of protocols is optional. QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - if (NumProtocols) - // Sort the protocol list alphabetically to canonicalize it. - SortAndUniqueProtocols(Protocols, NumProtocols); - llvm::FoldingSetNodeID ID; ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); @@ -1987,31 +1994,26 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // No Match; - ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(const_cast<ObjCInterfaceDecl*>(Decl), - Protocols, NumProtocols); - Types.push_back(QType); - ObjCInterfaceTypes.InsertNode(QType, InsertPos); - return QualType(QType, 0); -} + // Sort the protocol list alphabetically to canonicalize it. + QualType Canonical; + if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); + std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); -QualType ASTContext::getObjCProtocolListType(QualType T, - ObjCProtocolDecl **Protocols, - unsigned NumProtocols) { - llvm::FoldingSetNodeID ID; - ObjCProtocolListType::Profile(ID, T, Protocols, NumProtocols); + unsigned UniqueCount = NumProtocols; + SortAndUniqueProtocols(&Sorted[0], UniqueCount); - void *InsertPos = 0; - if (ObjCProtocolListType *QT = - ObjCProtocolListTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(QT, 0); + Canonical = getObjCInterfaceType(Decl, &Sorted[0], UniqueCount); + + ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + ObjCInterfaceType *QType = new (*this, TypeAlignment) + ObjCInterfaceType(Canonical, const_cast<ObjCInterfaceDecl*>(Decl), + Protocols, NumProtocols); - // No Match; - ObjCProtocolListType *QType = new (*this, TypeAlignment) - ObjCProtocolListType(T, Protocols, NumProtocols); Types.push_back(QType); - ObjCProtocolListTypes.InsertNode(QType, InsertPos); + ObjCInterfaceTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } @@ -2168,6 +2170,24 @@ QualType ASTContext::getPointerDiffType() const { // Type Operators //===----------------------------------------------------------------------===// +CanQualType ASTContext::getCanonicalParamType(QualType T) { + // Push qualifiers into arrays, and then discard any remaining + // qualifiers. + T = getCanonicalType(T); + const Type *Ty = T.getTypePtr(); + + QualType Result; + if (isa<ArrayType>(Ty)) { + Result = getArrayDecayedType(QualType(Ty,0)); + } else if (isa<FunctionType>(Ty)) { + Result = getPointerType(QualType(Ty, 0)); + } else { + Result = QualType(Ty, 0); + } + + return CanQualType::CreateUnsafe(Result); +} + /// 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 @@ -2512,7 +2532,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. unsigned ASTContext::getIntegerRank(Type *T) { - assert(T->isCanonical() && "T should be canonicalized"); + assert(T->isCanonicalUnqualified() && "T should be canonicalized"); if (EnumType* ET = dyn_cast<EnumType>(T)) T = ET->getDecl()->getIntegerType().getTypePtr(); @@ -2713,6 +2733,226 @@ QualType ASTContext::getObjCFastEnumerationStateType() { return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } +QualType ASTContext::getBlockDescriptorType() { + if (BlockDescriptorType) + return getTagDeclType(BlockDescriptorType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor")); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + }; + + const char *FieldNames[] = { + "reserved", + "Size" + }; + + for (size_t i = 0; i < 2; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + T, + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + BlockDescriptorType = T; + + return getTagDeclType(BlockDescriptorType); +} + +void ASTContext::setBlockDescriptorType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorType = Rec->getDecl(); +} + +QualType ASTContext::getBlockDescriptorExtendedType() { + if (BlockDescriptorExtendedType) + return getTagDeclType(BlockDescriptorExtendedType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor_withcopydispose")); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy) + }; + + const char *FieldNames[] = { + "reserved", + "Size", + "CopyFuncPtr", + "DestroyFuncPtr" + }; + + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + T, + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + BlockDescriptorExtendedType = T; + + return getTagDeclType(BlockDescriptorExtendedType); +} + +void ASTContext::setBlockDescriptorExtendedType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorExtendedType = Rec->getDecl(); +} + +bool ASTContext::BlockRequiresCopying(QualType Ty) { + if (Ty->isBlockPointerType()) + return true; + if (isObjCNSObjectType(Ty)) + return true; + if (Ty->isObjCObjectPointerType()) + return true; + return false; +} + +QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { + // type = struct __Block_byref_1_X { + // void *__isa; + // struct __Block_byref_1_X *__forwarding; + // unsigned int __flags; + // unsigned int __size; + // void *__copy_helper; // as needed + // void *__destroy_help // as needed + // int X; + // } * + + bool HasCopyAndDispose = BlockRequiresCopying(Ty); + + // FIXME: Move up + static int UniqueBlockByRefTypeID = 0; + char Name[36]; + sprintf(Name, "__Block_byref_%d_%s", ++UniqueBlockByRefTypeID, DeclName); + RecordDecl *T; + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name)); + T->startDefinition(); + QualType Int32Ty = IntTy; + assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); + QualType FieldTypes[] = { + getPointerType(VoidPtrTy), + getPointerType(getTagDeclType(T)), + Int32Ty, + Int32Ty, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy), + Ty + }; + + const char *FieldNames[] = { + "__isa", + "__forwarding", + "__flags", + "__size", + "__copy_helper", + "__destroy_helper", + DeclName, + }; + + for (size_t i = 0; i < 7; ++i) { + if (!HasCopyAndDispose && i >=4 && i <= 5) + continue; + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + return getPointerType(getTagDeclType(T)); +} + + +QualType ASTContext::getBlockParmType( + bool BlockHasCopyDispose, + llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { + // FIXME: Move up + static int UniqueBlockParmTypeID = 0; + char Name[36]; + sprintf(Name, "__block_literal_%u", ++UniqueBlockParmTypeID); + RecordDecl *T; + T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name)); + QualType FieldTypes[] = { + getPointerType(VoidPtrTy), + IntTy, + IntTy, + getPointerType(VoidPtrTy), + (BlockHasCopyDispose ? + getPointerType(getBlockDescriptorExtendedType()) : + getPointerType(getBlockDescriptorType())) + }; + + const char *FieldNames[] = { + "__isa", + "__flags", + "__reserved", + "__FuncPtr", + "__descriptor" + }; + + for (size_t i = 0; i < 5; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + for (size_t i = 0; i < BlockDeclRefDecls.size(); ++i) { + const Expr *E = BlockDeclRefDecls[i]; + const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); + clang::IdentifierInfo *Name = 0; + if (BDRE) { + const ValueDecl *D = BDRE->getDecl(); + Name = &Idents.get(D->getName()); + } + QualType FieldType = E->getType(); + + if (BDRE && BDRE->isByRef()) + FieldType = BuildByRefType(BDRE->getDecl()->getNameAsCString(), + FieldType); + + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + Name, FieldType, /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); + T->addDecl(Field); + } + + T->completeDefinition(*this); + + return getPointerType(getTagDeclType(T)); +} + void ASTContext::setObjCFastEnumerationStateType(QualType T) { const RecordType *Rec = T->getAs<RecordType>(); assert(Rec && "Invalid ObjCFAstEnumerationStateType"); @@ -2945,6 +3185,7 @@ static void EncodeBitField(const ASTContext *Context, std::string& S, S += llvm::utostr(N); } +// FIXME: Use SmallString for accumulating string. void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandPointedToStructures, bool ExpandStructures, @@ -3420,7 +3661,7 @@ Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { /// compatible. static bool areCompatVectorTypes(const VectorType *LHS, const VectorType *RHS) { - assert(LHS->isCanonical() && RHS->isCanonical()); + assert(LHS->isCanonicalUnqualified() && RHS->isCanonicalUnqualified()); return LHS->getElementType() == RHS->getElementType() && LHS->getNumElements() == RHS->getNumElements(); } @@ -3979,7 +4220,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) { if (T == BoolTy) return 1; - if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { return FWIT->getWidth(); } // For builtin types, just use the standard type sizing method @@ -3988,10 +4229,18 @@ unsigned ASTContext::getIntWidth(QualType T) { QualType ASTContext::getCorrespondingUnsignedType(QualType T) { assert(T->isSignedIntegerType() && "Unexpected type"); - if (const EnumType* ETy = T->getAs<EnumType>()) + + // Turn <4 x signed int> -> <4 x unsigned int> + if (const VectorType *VTy = T->getAs<VectorType>()) + return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), + VTy->getNumElements()); + + // For enums, we return the unsigned version of the base type. + if (const EnumType *ETy = T->getAs<EnumType>()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType* BTy = T->getAs<BuiltinType>(); - assert (BTy && "Unexpected signed integer type"); + + const BuiltinType *BTy = T->getAs<BuiltinType>(); + assert(BTy && "Unexpected signed integer type"); switch (BTy->getKind()) { case BuiltinType::Char_S: case BuiltinType::SChar: diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 4a46eab..b59b45f 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -50,7 +50,7 @@ CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { /// different base class subobjects of the same type. BaseType must be /// an unqualified, canonical class type. bool CXXBasePaths::isAmbiguous(QualType BaseType) { - assert(BaseType->isCanonical() && "Base type must be the canonical type"); + assert(BaseType.isCanonical() && "Base type must be the canonical type"); assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; return Subobjects.second + (Subobjects.first? 1 : 0) > 1; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index da7959b..d270a95 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -231,6 +231,8 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { + // FIXME: Collect contexts, then accumulate names to avoid unnecessary + // std::string thrashing. std::vector<std::string> Names; std::string QualName; const DeclContext *Ctx = getDeclContext(); @@ -252,7 +254,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), P); - Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); + Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) Names.push_back(ND->getNameAsString()); else @@ -336,8 +338,15 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { //===----------------------------------------------------------------------===// SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { - if (DeclInfo) - return DeclInfo->getTypeLoc().getTypeSpecRange().getBegin(); + if (DeclInfo) { + TypeLoc TL = DeclInfo->getTypeLoc(); + while (true) { + TypeLoc NextTL = TL.getNextTypeLoc(); + if (!NextTL) + return TL.getSourceRange().getBegin(); + TL = NextTL; + } + } return SourceLocation(); } @@ -408,10 +417,15 @@ MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { return getASTContext().getInstantiatedFromStaticDataMember(this); } -void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); assert(MSI && "Not an instantiated static data member?"); MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); } bool VarDecl::isTentativeDefinition(ASTContext &Context) const { @@ -812,18 +826,39 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { } void -FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { if (FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast< - FunctionTemplateSpecializationInfo*>()) + FunctionTemplateSpecializationInfo*>()) { FTSInfo->setTemplateSpecializationKind(TSK); - else if (MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) { MSInfo->setTemplateSpecializationKind(TSK); - else + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else assert(false && "Function cannot have a template specialization kind"); } +SourceLocation FunctionDecl::getPointOfInstantiation() const { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + return FTSInfo->getPointOfInstantiation(); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + return MSInfo->getPointOfInstantiation(); + + return SourceLocation(); +} + bool FunctionDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 7836b3f..9a1c654 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -299,7 +299,7 @@ void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) { switch (Arg.getKind()) { default: break; case TemplateArgument::Type: - assert(Arg.getAsType()->isCanonical() && "Type must be canonical!"); + assert(Arg.getAsType().isCanonical() && "Type must be canonical!"); break; } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 101ddd2..56a5975 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -51,7 +51,7 @@ public: bool operator<(DeclarationName LHS, DeclarationName RHS) { if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo()) if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo()) - return strcmp(LhsId->getName(), RhsId->getName()) < 0; + return LhsId->getName() < RhsId->getName(); return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger(); } @@ -60,7 +60,7 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { DeclarationName::DeclarationName(Selector Sel) { if (!Sel.getAsOpaquePtr()) { - Ptr = StoredObjCZeroArgSelector; + Ptr = 0; return; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 0e4a29f..a4de3e5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -426,6 +426,18 @@ const char *CastExpr::getCastKindName() const { return "IntegralToPointer"; case CastExpr::CK_PointerToIntegral: return "PointerToIntegral"; + case CastExpr::CK_ToVoid: + return "ToVoid"; + case CastExpr::CK_VectorSplat: + return "VectorSplat"; + case CastExpr::CK_IntegralCast: + return "IntegralCast"; + case CastExpr::CK_IntegralToFloating: + return "IntegralToFloating"; + case CastExpr::CK_FloatingToIntegral: + return "FloatingToIntegral"; + case CastExpr::CK_FloatingCast: + return "FloatingCast"; } assert(0 && "Unhandled cast kind!"); @@ -1740,40 +1752,36 @@ unsigned ExtVectorElementExpr::getNumElements() const { /// containsDuplicateElements - Return true if any element access is repeated. bool ExtVectorElementExpr::containsDuplicateElements() const { - const char *compStr = Accessor->getName(); - unsigned length = Accessor->getLength(); + // FIXME: Refactor this code to an accessor on the AST node which returns the + // "type" of component access, and share with code below and in Sema. + llvm::StringRef Comp = Accessor->getName(); // Halving swizzles do not contain duplicate elements. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || - !strcmp(compStr, "even") || !strcmp(compStr, "odd")) + if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd") return false; // Advance past s-char prefix on hex swizzles. - if (*compStr == 's' || *compStr == 'S') { - compStr++; - length--; - } + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); - for (unsigned i = 0; i != length-1; i++) { - const char *s = compStr+i; - for (const char c = *s++; *s; s++) - if (c == *s) + for (unsigned i = 0, e = Comp.size(); i != e; ++i) + if (Comp.substr(i + 1).find(Comp[i]) != llvm::StringRef::npos) return true; - } + return false; } /// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. void ExtVectorElementExpr::getEncodedElementAccess( llvm::SmallVectorImpl<unsigned> &Elts) const { - const char *compStr = Accessor->getName(); - if (*compStr == 's' || *compStr == 'S') - compStr++; + llvm::StringRef Comp = Accessor->getName(); + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); - bool isHi = !strcmp(compStr, "hi"); - bool isLo = !strcmp(compStr, "lo"); - bool isEven = !strcmp(compStr, "even"); - bool isOdd = !strcmp(compStr, "odd"); + bool isHi = Comp == "hi"; + bool isLo = Comp == "lo"; + bool isEven = Comp == "even"; + bool isOdd = Comp == "odd"; for (unsigned i = 0, e = getNumElements(); i != e; ++i) { uint64_t Index; @@ -1787,7 +1795,7 @@ void ExtVectorElementExpr::getEncodedElementAccess( else if (isOdd) Index = 2 * i + 1; else - Index = ExtVectorType::getAccessorIdx(compStr[i]); + Index = ExtVectorType::getAccessorIdx(Comp[i]); Elts.push_back(Index); } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 3a838fa..6e0da47 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -117,7 +117,7 @@ void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { } const char *LabelStmt::getName() const { - return getID()->getName(); + return getID()->getNameStart(); } // This is defined here to avoid polluting Stmt.h with importing Expr.h diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 0465999..cf71d6b 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -244,7 +244,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // print a free standing tag decl (e.g. "struct x;"). const char *tagname; if (const IdentifierInfo *II = TD->getIdentifier()) - tagname = II->getName(); + tagname = II->getNameStart(); else tagname = "<anonymous>"; fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); @@ -253,7 +253,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // print using-directive decl (e.g. "using namespace x;") const char *ns; if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier()) - ns = II->getName(); + ns = II->getNameStart(); else ns = "<anonymous>"; fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); @@ -403,7 +403,7 @@ void StmtDumper::VisitMemberExpr(MemberExpr *Node) { } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getAccessor().getName()); + fprintf(F, " %s", Node->getAccessor().getNameStart()); } void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { DumpExpr(Node); @@ -495,7 +495,7 @@ void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str()); IdentifierInfo* clsName = Node->getClassName(); - if (clsName) fprintf(F, " class=%s", clsName->getName()); + if (clsName) fprintf(F, " class=%s", clsName->getNameStart()); } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 05d0c26..2af1976 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1289,7 +1289,7 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, return; } - if (Policy.Dump) { + if (Policy.Dump && &Context) { dump(Context.getSourceManager()); return; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0293862..5fb0178 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -37,18 +37,6 @@ void Type::Destroy(ASTContext& C) { C.Deallocate(this); } -void ConstantArrayWithExprType::Destroy(ASTContext& C) { - // FIXME: destruction of SizeExpr commented out due to resource contention. - // SizeExpr->Destroy(C); - // See FIXME in SemaDecl.cpp:1536: if we were able to either steal - // or clone the SizeExpr there, then here we could freely delete it. - // Since we do not know how to steal or clone, we keep a pointer to - // a shared resource, but we cannot free it. - // (There probably is a trivial solution ... for people knowing clang!). - this->~ConstantArrayWithExprType(); - C.Deallocate(this); -} - void VariableArrayType::Destroy(ASTContext& C) { if (SizeExpr) SizeExpr->Destroy(C); @@ -177,8 +165,6 @@ bool Type::isDerivedType() const { case Pointer: case VariableArray: case ConstantArray: - case ConstantArrayWithExpr: - case ConstantArrayWithoutExpr: case IncompleteArray: case FunctionProto: case FunctionNoProto: @@ -642,6 +628,7 @@ bool Type::isSpecifierType() const { case TypeOfExpr: case TypeOf: case TemplateTypeParm: + case SubstTemplateTypeParm: case TemplateSpecialization: case QualifiedName: case Typename: @@ -737,18 +724,6 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), 0, 0); } -void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID, - QualType OIT, ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - ID.AddPointer(OIT.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); -} - -void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), &Protocols[0], getNumProtocols()); -} - /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to /// potentially looking through *all* consequtive typedefs. This returns the /// sum of the type qualifiers, so if you have: @@ -1072,10 +1047,10 @@ void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPoli // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) + if (isa<ArrayType>(getPointeeTypeAsWritten())) S = '(' + S + ')'; - getPointeeType().getAsStringInternal(S, Policy); + getPointeeTypeAsWritten().getAsStringInternal(S, Policy); } void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { @@ -1083,10 +1058,10 @@ void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPoli // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) + if (isa<ArrayType>(getPointeeTypeAsWritten())) S = '(' + S + ')'; - getPointeeType().getAsStringInternal(S, Policy); + getPointeeTypeAsWritten().getAsStringInternal(S, Policy); } void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { @@ -1111,29 +1086,6 @@ void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy getElementType().getAsStringInternal(S, Policy); } -void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - if (Policy.ConstantArraySizeAsWritten) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - getSizeExpr()->printPretty(s, 0, Policy); - S += '['; - S += s.str(); - S += ']'; - getElementType().getAsStringInternal(S, Policy); - } - else - ConstantArrayType::getAsStringInternal(S, Policy); -} - -void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - if (Policy.ConstantArraySizeAsWritten) { - S += "[]"; - getElementType().getAsStringInternal(S, Policy); - } - else - ConstantArrayType::getAsStringInternal(S, Policy); -} - void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += "[]"; @@ -1290,7 +1242,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; + InnerString = getDecl()->getIdentifier()->getName().str() + InnerString; } void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { @@ -1301,7 +1253,11 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + llvm::utostr_32(Index) + InnerString; else - InnerString = Name->getName() + InnerString; + InnerString = Name->getName().str() + InnerString; +} + +void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + getReplacementType().getAsStringInternal(InnerString, Policy); } std::string @@ -1495,25 +1451,6 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, InnerString = ObjCQIString + InnerString; } -void ObjCProtocolListType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - std::string ObjCQIString = getBaseType().getAsString(Policy); - ObjCQIString += '<'; - bool isFirst = true; - for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { - if (isFirst) - isFirst = false; - else - ObjCQIString += ','; - ObjCQIString += (*I)->getNameAsString(); - } - ObjCQIString += '>'; - InnerString = ObjCQIString + InnerString; -} - void ElaboratedType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { std::string TypeStr; @@ -1534,11 +1471,11 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); const char *ID; if (const IdentifierInfo *II = getDecl()->getIdentifier()) - ID = II->getName(); + ID = II->getNameStart(); else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) { Kind = 0; assert(Typedef->getIdentifier() && "Typedef without identifier?"); - ID = Typedef->getIdentifier()->getName(); + ID = Typedef->getIdentifier()->getNameStart(); } else ID = "<anonymous>"; @@ -1573,7 +1510,7 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), Policy); - MyPart = Spec->getIdentifier()->getName() + TemplateArgsStr; + MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr; } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) MyPart = Typedef->getIdentifier()->getName(); diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 04e7083..50a5120 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -20,55 +20,32 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - -/// \brief Return the source range for the visited TypeSpecLoc. -class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { -public: -#define ABSTRACT_TYPELOC(CLASS) + class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - SourceRange Visit##CLASS(CLASS TyLoc) { return TyLoc.getSourceRange(); } + SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getSourceRange(); \ + } #include "clang/AST/TypeLocNodes.def" - - SourceRange VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A typeloc wrapper was not handled!"); - return SourceRange(); - } -}; - -} - -SourceRange TypeLoc::getSourceRange() const { - if (isNull()) - return SourceRange(); - return TypeLocRanger().Visit(*this); + }; } -/// \brief Find the TypeSpecLoc that is part of this TypeLoc. -TypeSpecLoc TypeLoc::getTypeSpecLoc() const { - if (isNull()) - return TypeSpecLoc(); - UnqualTypeLoc Cur = getUnqualifiedLoc(); - if (const DeclaratorLoc *DL = dyn_cast<DeclaratorLoc>(&Cur)) - return DL->getTypeSpecLoc(); - return cast<TypeSpecLoc>(Cur); +SourceRange TypeLoc::getSourceRangeImpl(TypeLoc TL) { + if (TL.isNull()) return SourceRange(); + return TypeLocRanger().Visit(TL); } namespace { - -/// \brief Report the full source info data size for the visited TypeLoc. -class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { -public: -#define ABSTRACT_TYPELOC(CLASS) + class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - unsigned Visit##CLASS(CLASS TyLoc) { return TyLoc.getFullDataSize(); } + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getFullDataSize(); \ + } #include "clang/AST/TypeLocNodes.def" - - unsigned VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - return 0; - } -}; - + }; } /// \brief Returns the size of the type source info data block. @@ -78,138 +55,42 @@ unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { } namespace { - -/// \brief Return the "next" TypeLoc for the visited TypeLoc, e.g for "int*" the -/// TypeLoc is a PointerLoc and next TypeLoc is for "int". -class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { -public: -#define TYPELOC(CLASS, PARENT) -#define DECLARATOR_TYPELOC(CLASS, TYPE) \ - TypeLoc Visit##CLASS(CLASS TyLoc); + class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getNextTypeLoc(); \ + } #include "clang/AST/TypeLocNodes.def" - - TypeLoc VisitTypeSpecLoc(TypeLoc TyLoc) { return TypeLoc(); } - TypeLoc VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); - TypeLoc VisitQualifiedLoc(QualifiedLoc TyLoc) { - return TyLoc.getUnqualifiedLoc(); - } - - TypeLoc VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A declarator loc wrapper was not handled!"); - return TypeLoc(); - } -}; - -} - -TypeLoc NextLoc::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { - return TL.getBaseTypeLoc(); -} - -TypeLoc NextLoc::VisitPointerLoc(PointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitMemberPointerLoc(MemberPointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitBlockPointerLoc(BlockPointerLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitReferenceLoc(ReferenceLoc TL) { - return TL.getPointeeLoc(); -} -TypeLoc NextLoc::VisitFunctionLoc(FunctionLoc TL) { - return TL.getResultLoc(); -} -TypeLoc NextLoc::VisitArrayLoc(ArrayLoc TL) { - return TL.getElementLoc(); + }; } /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". -TypeLoc TypeLoc::getNextTypeLoc() const { - //llvm::errs() << "getNextTypeLoc: Ty=" << Ty << ", Data=" << Data << "\n"; - TypeLoc Tmp = NextLoc().Visit(*this); - //llvm::errs() << " result: Ty=" << Tmp.Ty << ", Data=" << Tmp.Data << "\n"; - return Tmp; +TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { + return NextLoc().Visit(TL); } -//===----------------------------------------------------------------------===// -// TypeSpecLoc Implementation -//===----------------------------------------------------------------------===// - namespace { -class TypeSpecChecker : public TypeLocVisitor<TypeSpecChecker, bool> { -public: - bool VisitTypeSpecLoc(TypeSpecLoc TyLoc) { return true; } -}; - -} - -bool TypeSpecLoc::classof(const UnqualTypeLoc *TL) { - return TypeSpecChecker().Visit(*TL); -} - -//===----------------------------------------------------------------------===// -// DeclaratorLoc Implementation -//===----------------------------------------------------------------------===// - -namespace { - -/// \brief Return the TypeSpecLoc for the visited DeclaratorLoc. -class TypeSpecGetter : public TypeLocVisitor<TypeSpecGetter, TypeSpecLoc> { -public: -#define TYPELOC(CLASS, PARENT) -#define DECLARATOR_TYPELOC(CLASS, TYPE) \ - TypeSpecLoc Visit##CLASS(CLASS TyLoc) { return TyLoc.getTypeSpecLoc(); } + struct TypeLocInitializer : public TypeLocVisitor<TypeLocInitializer> { + SourceLocation Loc; + TypeLocInitializer(SourceLocation Loc) : Loc(Loc) {} + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + TyLoc.initializeLocal(Loc); \ + } #include "clang/AST/TypeLocNodes.def" - - TypeSpecLoc VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A declarator loc wrapper was not handled!"); - return TypeSpecLoc(); - } - - TypeSpecLoc VisitQualifiedLoc(QualifiedLoc TyLoc) { - return Visit(TyLoc.getUnqualifiedLoc()); - } -}; - -} - -/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. -TypeSpecLoc DeclaratorLoc::getTypeSpecLoc() const { - return TypeSpecGetter().Visit(*this); -} - -namespace { - -class DeclaratorLocChecker : public TypeLocVisitor<DeclaratorLocChecker, bool> { -public: - bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; } -}; - -} - -bool DeclaratorLoc::classof(const UnqualTypeLoc *TL) { - return DeclaratorLocChecker().Visit(*TL); -} - -//===----------------------------------------------------------------------===// -// DefaultTypeSpecLoc Implementation -//===----------------------------------------------------------------------===// - -namespace { - -class DefaultTypeSpecLocChecker : - public TypeLocVisitor<DefaultTypeSpecLocChecker, bool> { -public: - bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; } -}; - + }; } -bool DefaultTypeSpecLoc::classofType(const Type *Ty) { - return - DefaultTypeSpecLocChecker().Visit(UnqualTypeLoc(const_cast<Type*>(Ty), 0)); +/// \brief Initializes a type location, and all of its children +/// recursively, as if the entire tree had been written in the +/// given location. +void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { + do { + TypeLocInitializer(Loc).Visit(TL); + } while ((TL = TL.getNextTypeLoc())); } - diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index a4cb66b..640912a 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -33,6 +33,12 @@ AnalysisContextManager::~AnalysisContextManager() { delete I->second; } +void AnalysisContextManager::clear() { + for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) + delete I->second; + Contexts.clear(); +} + Stmt *AnalysisContext::getBody() { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) return FD->getBody(); @@ -103,6 +109,21 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, ID.AddPointer(s); } +LocationContextManager::~LocationContextManager() { + clear(); +} + +void LocationContextManager::clear() { + for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), + E = Contexts.end(); I != E; ) { + LocationContext *LC = &*I; + ++I; + delete LC; + } + + Contexts.clear(); +} + StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index af300f3..aa2d0ab 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -45,9 +45,9 @@ static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { } static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { - const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); - return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() - : NULL; + if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) + return ReceiverType->getDecl()->getIdentifier()->getNameStart(); + return NULL; } namespace { @@ -62,7 +62,7 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { BugReporter& BR; ASTContext &Ctx; - bool isNSString(const ObjCInterfaceType *T, const char* suffix); + bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); void Warn(ExplodedNode* N, const Expr* E, const std::string& s); @@ -114,18 +114,8 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, if (!ReceiverType) return false; - const char* name = ReceiverType->getDecl()->getIdentifier()->getName(); - - if (!name) - return false; - - if (name[0] != 'N' || name[1] != 'S') - return false; - - name += 2; - - // FIXME: Make all of this faster. - if (isNSString(ReceiverType, name)) + if (isNSString(ReceiverType, + ReceiverType->getDecl()->getIdentifier()->getName())) return AuditNSString(N, ME); return false; @@ -158,8 +148,8 @@ bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { //===----------------------------------------------------------------------===// bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, - const char* suffix) { - return !strcmp("String", suffix) || !strcmp("MutableString", suffix); + llvm::StringRef ClassName) { + return ClassName == "NSString" || ClassName == "NSMutableString"; } bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index a4f451f..d81d83c 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -49,7 +49,8 @@ public: QualType T = QualType()); const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count); + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); const GRState *Bind(const GRState *state, Loc L, SVal V) { return state->makeWithStore(BindInternal(state->getStore(), L, V)); @@ -623,12 +624,21 @@ StoreManager::BindingsHandler::~BindingsHandler() {} const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *E, - unsigned Count) { + unsigned Count, + InvalidatedSymbols *IS) { R = R->getBaseRegion(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return state; + if (IS) { + BindingsTy B = GetBindings(state->getStore()); + if (BindingsTy::data_type *Val = B.lookup(R)) { + if (SymbolRef Sym = Val->getAsSymbol()) + IS->insert(Sym); + } + } + QualType T = cast<TypedRegion>(R)->getValueType(R->getContext()); SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count); return Bind(state, loc::MemRegionVal(R), V); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 7b1d50c..3141759 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Format.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" using namespace clang; @@ -51,7 +52,7 @@ static SourceLocation GetEndLoc(Decl* D) { /// class VISIBILITY_HIDDEN CFGBuilder { ASTContext *Context; - CFG* cfg; + llvm::OwningPtr<CFG> cfg; CFGBlock* Block; CFGBlock* Succ; @@ -79,8 +80,6 @@ public: ContinueTargetBlock(NULL), BreakTargetBlock(NULL), SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {} - ~CFGBuilder() { delete cfg; } - // buildCFG - Used by external clients to construct the CFG. CFG* buildCFG(Stmt *Statement, ASTContext *C); @@ -195,7 +194,7 @@ static VariableArrayType* FindVA(Type* t) { /// NULL. CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { Context = C; - assert(cfg); + assert(cfg.get()); if (!Statement) return NULL; @@ -210,7 +209,8 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Visit the statements and create the CFG. CFGBlock* B = addStmt(Statement); - if (!B) B = Succ; + if (!B) + B = Succ; if (B) { // Finalize the last constructed block. This usually involves reversing the @@ -254,17 +254,7 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Create an empty entry block that has no predecessors. cfg->setEntry(createBlock()); - if (badCFG) { - delete cfg; - cfg = NULL; - return NULL; - } - - // NULL out cfg so that repeated calls to the builder will fail and that the - // ownership of the constructed CFG is passed to the caller. - CFG* t = cfg; - cfg = NULL; - return t; + return badCFG ? NULL : cfg.take(); } /// createBlock - Used to lazily create blocks that are connected diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index eb1265d..c629ad1 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -81,7 +81,7 @@ static NamingConvention deriveNamingConvention(Selector S) { if (!II) return NoConvention; - const char *s = II->getName(); + const char *s = II->getNameStart(); // A method/function name may contain a prefix. We don't know it is there, // however, until we encounter the first '_'. @@ -93,12 +93,14 @@ static NamingConvention deriveNamingConvention(Selector S) { // Skip '_'. if (*s == '_') { if (InPossiblePrefix) { + // If we already have a convention, return it. Otherwise, skip + // the prefix as if it wasn't there. + if (C != NoConvention) + break; + InPossiblePrefix = false; AtBeginning = true; - // Discard whatever 'convention' we - // had already derived since it occurs - // in the prefix. - C = NoConvention; + assert(C == NoConvention); } ++s; continue; @@ -208,41 +210,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { // Type querying functions. //===----------------------------------------------------------------------===// -static bool hasPrefix(const char* s, const char* prefix) { - if (!prefix) - return true; - - char c = *s; - char cP = *prefix; - - while (c != '\0' && cP != '\0') { - if (c != cP) break; - c = *(++s); - cP = *(++prefix); - } - - return cP == '\0'; -} - -static bool hasSuffix(const char* s, const char* suffix) { - const char* loc = strstr(s, suffix); - return loc && strcmp(suffix, loc) == 0; -} - static bool isRefType(QualType RetTy, const char* prefix, ASTContext* Ctx = 0, const char* name = 0) { // Recursively walk the typedef stack, allowing typedefs of reference types. - while (1) { - if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { - const char* TDName = TD->getDecl()->getIdentifier()->getName(); - if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref")) - return true; + while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { + llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); + if (TDName.startswith(prefix) && TDName.endswith("Ref")) + return true; - RetTy = TD->getDecl()->getUnderlyingType(); - continue; - } - break; + RetTy = TD->getDecl()->getUnderlyingType(); } if (!Ctx || !name) @@ -254,7 +231,7 @@ static bool isRefType(QualType RetTy, const char* prefix, return false; // Does the name start with the prefix? - return hasPrefix(name, prefix); + return llvm::StringRef(name).startswith(prefix); } //===----------------------------------------------------------------------===// @@ -956,7 +933,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the // function's type. const FunctionType* FT = FD->getType()->getAs<FunctionType>(); - const char* FName = FD->getIdentifier()->getName(); + const char* FName = FD->getIdentifier()->getNameStart(); // Strip away preceding '_'. Doing this here will effect all the checks // down below. @@ -1009,7 +986,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Part of <rdar://problem/6961230>. (IOKit) // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing); } break; @@ -1432,16 +1409,19 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ); // Create the [NSAssertionHandler currentHander] summary. - addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"), - GetNullarySelector("currentHandler", Ctx), + addClassMethSummary("NSAssertionHandler", "currentHandler", getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); // Create the [NSAutoreleasePool addObject:] summary. ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease); - addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"), - GetUnarySelector("addObject", Ctx), - getPersistentSummary(RetEffect::MakeNoRet(), - DoNothing, Autorelease)); + addClassMethSummary("NSAutoreleasePool", "addObject", + getPersistentSummary(RetEffect::MakeNoRet(), + DoNothing, Autorelease)); + + // Create a summary for [NSCursor dragCopyCursor]. + addClassMethSummary("NSCursor", "dragCopyCursor", + getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, + DoNothing)); // Create the summaries for [NSObject performSelector...]. We treat // these as 'stop tracking' for the arguments because they are often @@ -2856,14 +2836,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // FIXME: What about layers of ElementRegions? } - // Is the invalidated variable something that we were tracking? - SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); - - // Remove any existing reference-count binding. - if (Sym) - state = state->remove<RefBindings>(Sym); - - state = StoreMgr.InvalidateRegion(state, R, *I, Count); + StoreManager::InvalidatedSymbols IS; + state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS); + for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), + E = IS.end(); I!=E; ++I) { + // Remove any existing reference-count binding. + state = state->remove<RefBindings>(*I); + } } else { // Nuke all other arguments passed by reference. diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 5079ace..ea0255d 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -207,7 +207,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Precondition: the first argument of 'main' is an integer guaranteed // to be > 0. - if (strcmp(FD->getIdentifier()->getName(), "main") == 0 && + if (FD->getIdentifier()->getName() == "main" && FD->getNumParams() > 0) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); @@ -1445,10 +1445,9 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - const char* s = FD->getIdentifier()->getName(); - unsigned n = strlen(s); + const char* s = FD->getIdentifier()->getNameStart(); - switch (n) { + switch (FD->getIdentifier()->getLength()) { default: break; @@ -2788,66 +2787,55 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, SVal RightV = state->getSVal(RHS); BinaryOperator::Opcode Op = B->getOpcode(); - switch (Op) { - case BinaryOperator::Assign: { - - // EXPERIMENTAL: "Conjured" symbols. - // FIXME: Handle structs. - QualType T = RHS->getType(); - - if ((RightV.isUnknown() || - !getConstraintManager().canReasonAbout(RightV)) - && (Loc::IsLocType(T) || - (T->isScalarType() && T->isIntegerType()))) { - unsigned Count = Builder->getCurrentBlockCount(); - RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); - } - // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), - LeftV, RightV); - continue; + if (Op == BinaryOperator::Assign) { + // EXPERIMENTAL: "Conjured" symbols. + // FIXME: Handle structs. + QualType T = RHS->getType(); + + if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV)) + && (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) { + unsigned Count = Builder->getCurrentBlockCount(); + RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } - - // FALL-THROUGH. - - default: { - - if (B->isAssignmentOp()) - break; - - // Process non-assignments except commas or short-circuited - // logical expressions (LAnd and LOr). - SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType()); - - if (Result.isUnknown()) { - if (OldSt != state) { - // Generate a new node if we have already created a new state. - MakeNode(Dst, B, *I2, state); - } - else - Dst.Add(*I2); - - continue; + + // Simulate the effects of a "store": bind the value of the RHS + // to the L-Value represented by the LHS. + EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), LeftV, RightV); + continue; + } + + if (!B->isAssignmentOp()) { + // Process non-assignments except commas or short-circuited + // logical expressions (LAnd and LOr). + SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType()); + + if (Result.isUnknown()) { + if (OldSt != state) { + // Generate a new node if we have already created a new state. + MakeNode(Dst, B, *I2, state); } - - state = state->BindExpr(B, Result); - - if (Result.isUndef()) { - // The operands were *not* undefined, but the result is undefined. - // This is a special node that should be flagged as an error. - if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; + else + Dst.Add(*I2); + + continue; + } + + state = state->BindExpr(B, Result); + + if (Result.isUndef()) { + // The operands were *not* undefined, but the result is undefined. + // This is a special node that should be flagged as an error. + if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ + UndefNode->markAsSink(); + UndefResults.insert(UndefNode); } - - // Otherwise, create a new node. - MakeNode(Dst, B, *I2, state); continue; } + + // Otherwise, create a new node. + MakeNode(Dst, B, *I2, state); + continue; } assert (B->isCompoundAssignmentOp()); @@ -2875,7 +2863,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) { - state = GetState(*I3); SVal V = state->getSVal(LHS); diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index cc1ec4b..da24192 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -742,11 +742,11 @@ void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { } } -class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor<CheckBadDiv> { +class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> { DivZero *BT; public: - CheckBadDiv() : BT(0) {} - ~CheckBadDiv() {} + CheckDivZero() : BT(0) {} + ~CheckDivZero() {} const void *getTag() { static int x; @@ -756,8 +756,8 @@ public: void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); }; -void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { +void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { BinaryOperator::Opcode Op = B->getOpcode(); if (Op != BinaryOperator::Div && Op != BinaryOperator::Rem && @@ -792,7 +792,8 @@ void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C, return; } - // If we get here, then the denom should not be zero. + // If we get here, then the denom should not be zero. We abandon the implicit + // zero denom case for now. if (stateNotZero != C.getState()) C.addTransition(C.GenerateNode(B, stateNotZero)); } @@ -828,5 +829,5 @@ void GRExprEngine::RegisterInternalChecks() { registerCheck(new CheckAttrNonNull()); registerCheck(new CheckUndefinedArg()); registerCheck(new CheckBadCall()); - registerCheck(new CheckBadDiv()); + registerCheck(new CheckDivZero()); } diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 4d96c8f..ae78d1f 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -21,9 +21,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" - -#include <string.h> -#include <stdio.h> +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -341,20 +339,19 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), E = AD.end_decl(); I!=E; ++I) if (V.getDeclBit(I->second)) { - fprintf(stderr, " %s <", I->first->getIdentifier()->getName()); + llvm::errs() << " " << I->first->getIdentifier()->getName() << " <"; I->first->getLocation().dump(SM); - fprintf(stderr, ">\n"); + llvm::errs() << ">\n"; } } void LiveVariables::dumpBlockLiveness(SourceManager& M) const { for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), E = getBlockDataMap().end(); I!=E; ++I) { - fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n", - I->first->getBlockID()); - + llvm::errs() << "\n[ B" << I->first->getBlockID() + << " (live variables at block exit) ]\n"; dumpLiveness(I->second,M); } - fprintf(stderr,"\n"); + llvm::errs() << "\n"; } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 9456ab6..780772a 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -262,7 +262,8 @@ public: //===-------------------------------------------------------------------===// const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, - const Expr *E, unsigned Count); + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, @@ -455,7 +456,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *Ex, - unsigned Count) { + unsigned Count, + InvalidatedSymbols *IS) { ASTContext& Ctx = StateMgr.getContext(); // Strip away casts. @@ -490,9 +492,21 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, if (Optional<SVal> V = getDirectBinding(B, R)) { if (const MemRegion *RV = V->getAsRegion()) WorkList.push_back(RV); + + // A symbol? Mark it touched by the invalidation. + if (IS) { + if (SymbolRef Sym = V->getAsSymbol()) + IS->insert(Sym); + } } - // Handle region. + // Symbolic region? Mark that symbol touched by the invalidation. + if (IS) { + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) + IS->insert(SR->getSymbol()); + } + + // Handle the region itself. if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) || isa<ObjCObjectRegion>(R)) { // Invalidate the region by setting its default value to @@ -1230,8 +1244,8 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, const MemRegion *superR = R->getSuperRegion(); - // Check if the super region has a binding. - if (Optional<SVal> V = getDirectBinding(B, superR)) { + // Check if the super region has a default binding. + if (Optional<SVal> V = getDefaultBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1376,7 +1390,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // For now, just invalidate the fields of the struct/union/class. // FIXME: Precisely handle the fields of the record. if (superTy->isRecordType()) - return InvalidateRegion(state, superR, NULL, 0); + return InvalidateRegion(state, superR, NULL, 0, NULL); } } } @@ -1588,36 +1602,13 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, //===----------------------------------------------------------------------===// // State pruning. //===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN RBDNode - : public std::pair<const GRState*, const MemRegion *> { -public: - RBDNode(const GRState *st, const MemRegion *r) - : std::pair<const GRState*, const MemRegion*>(st, r) {} - - const GRState *getState() const { return first; } - const MemRegion *getRegion() const { return second; } -}; - -enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion }; - -class RBDItem : public RBDNode { -private: - const VisitFlag VF; - -public: - RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf) - : RBDNode(st, r), VF(vf) {} - - VisitFlag getVisitFlag() const { return VF; } -}; -} // end anonymous namespace void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { + typedef std::pair<const GRState*, const MemRegion *> RBDNode; + Store store = state.getStore(); RegionBindings B = GetRegionBindings(store); @@ -1638,27 +1629,26 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Process the "intermediate" roots to find if they are referenced by // real roots. - llvm::SmallVector<RBDItem, 10> WorkList; - llvm::DenseMap<const MemRegion*,unsigned> IntermediateVisited; + llvm::SmallVector<RBDNode, 10> WorkList; + llvm::DenseSet<const MemRegion*> IntermediateVisited; while (!IntermediateRoots.empty()) { const MemRegion* R = IntermediateRoots.back(); IntermediateRoots.pop_back(); - unsigned &visited = IntermediateVisited[R]; - if (visited) + if (IntermediateVisited.count(R)) continue; - visited = 1; + IntermediateVisited.insert(R); if (const VarRegion* VR = dyn_cast<VarRegion>(R)) { if (SymReaper.isLive(Loc, VR->getDecl())) - WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, VR)); continue; } if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) { if (SymReaper.isLive(SR->getSymbol())) - WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, SR)); continue; } @@ -1671,54 +1661,40 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Enqueue the RegionRoots onto WorkList. for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(), E=RegionRoots.end(); I!=E; ++I) { - WorkList.push_back(RBDItem(&state, *I, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(&state, *I)); } RegionRoots.clear(); - // Process the worklist. - typedef llvm::DenseMap<std::pair<const GRState*, const MemRegion*>, VisitFlag> - VisitMap; - - VisitMap Visited; + llvm::DenseSet<RBDNode> Visited; while (!WorkList.empty()) { - RBDItem N = WorkList.back(); + RBDNode N = WorkList.back(); WorkList.pop_back(); // Have we visited this node before? - VisitFlag &VF = Visited[N]; - if (VF >= N.getVisitFlag()) + if (Visited.count(N)) continue; + Visited.insert(N); + + const MemRegion *R = N.second; + const GRState *state_N = N.first; - const MemRegion *R = N.getRegion(); - const GRState *state_N = N.getState(); - - // Enqueue subregions? - if (N.getVisitFlag() == VisitedFromSuperRegion) { - RegionStoreSubRegionMap *M; - - if (&state == state_N) - M = SubRegions.get(); - else { - RegionStoreSubRegionMap *& SM = SC[state_N]; - if (!SM) - SM = getRegionStoreSubRegionMap(state_N->getStore()); - M = SM; - } + // Enqueue subregions. + RegionStoreSubRegionMap *M; - RegionStoreSubRegionMap::iterator I, E; - for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I) - WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion)); - } - - // At this point, if we have already visited this region before, we are - // done. - if (VF != NotVisited) { - VF = N.getVisitFlag(); - continue; + if (&state == state_N) + M = SubRegions.get(); + else { + RegionStoreSubRegionMap *& SM = SC[state_N]; + if (!SM) + SM = getRegionStoreSubRegionMap(state_N->getStore()); + M = SM; } - VF = N.getVisitFlag(); + RegionStoreSubRegionMap::iterator I, E; + for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I) + WorkList.push_back(std::make_pair(state_N, *I)); + // Enqueue the super region. if (const SubRegion *SR = dyn_cast<SubRegion>(R)) { const MemRegion *superR = SR->getSuperRegion(); @@ -1726,12 +1702,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // If 'R' is a field or an element, we want to keep the bindings // for the other fields and elements around. The reason is that // pointer arithmetic can get us to the other fields or elements. - // FIXME: add an assertion that this is always true. - VisitFlag NewVisit = - isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R) - ? VisitedFromSuperRegion : VisitedFromSubRegion; - - WorkList.push_back(RBDItem(state_N, superR, NewVisit)); + assert(isa<FieldRegion>(R) || isa<ElementRegion>(R) + || isa<ObjCIvarRegion>(R)); + WorkList.push_back(std::make_pair(state_N, superR)); } } @@ -1752,8 +1725,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) { const LazyCompoundValData *D = LCV->getCVData(); - WorkList.push_back(RBDItem(D->getState(), D->getRegion(), - VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(D->getState(), D->getRegion())); } else { // Update the set of live symbols. @@ -1763,7 +1735,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // If V is a region, then add it to the worklist. if (const MemRegion *RX = V->getAsRegion()) - WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion)); + WorkList.push_back(std::make_pair(state_N, RX)); } } } @@ -1774,7 +1746,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { const MemRegion* R = I.getKey(); // If this region live? Is so, none of its symbols are dead. - if (Visited.find(std::make_pair(&state, R)) != Visited.end()) + if (Visited.count(std::make_pair(&state, R))) continue; // Remove this dead region from the store. @@ -1820,7 +1792,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, void RegionStoreManager::print(Store store, llvm::raw_ostream& OS, const char* nl, const char *sep) { RegionBindings B = GetRegionBindings(store); - OS << "Store (direct bindings):" << nl; + OS << "Store (direct and default bindings):" << nl; for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) OS << ' ' << I.getKey() << " : " << I.getData() << nl; diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 636ce15..4487aa9 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -346,16 +346,29 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs); SymbolRef Sym = slhs->getSymbol(); - // Does the symbol simplify to a constant? + // Does the symbol simplify to a constant? If so, "fold" the constant + // by setting 'lhs' to a ConcreteInt and try again. if (Sym->getType(ValMgr.getContext())->isIntegerType()) if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { - // What should we convert it to? - if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){ - BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); - lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(), - *Constant)); + // The symbol evaluates to a constant. If necessary, promote the + // folded constant (LHS) to the result type. + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + const llvm::APSInt &lhs_I = BVF.Convert(resultTy, *Constant); + lhs = nonloc::ConcreteInt(lhs_I); + + // Also promote the RHS (if necessary). + + // For shifts, it necessary promote the RHS to the result type. + if (BinaryOperator::isShiftOp(op)) continue; + + // Other operators: do an implicit conversion. This shouldn't be + // necessary once we support truncation/extension of symbolic values. + if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){ + rhs = nonloc::ConcreteInt(BVF.Convert(resultTy, rhs_I->getValue())); } + + continue; } if (isa<nonloc::ConcreteInt>(rhs)) { diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 4a29997..fbc7313 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" #include <vector> #include <map> #include <cstring> @@ -82,9 +83,14 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #ifndef NDEBUG static bool IsFirst = true; if (IsFirst) { - for (unsigned i = 1; i != NumDiagEntries; ++i) + for (unsigned i = 1; i != NumDiagEntries; ++i) { + assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && + "Diag ID conflict, the enums at the start of clang::diag (in " + "Diagnostic.h) probably need to be increased"); + assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] && "Improperly sorted diag info"); + } IsFirst = false; } #endif @@ -184,6 +190,8 @@ namespace clang { static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, const char *Modifier, unsigned ML, const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output, void *Cookie) { const char *Str = "<can't format argument>"; @@ -222,6 +230,8 @@ Diagnostic::~Diagnostic() { void Diagnostic::pushMappings() { + // Avoids undefined behavior when the stack has to resize. + DiagMappingsStack.reserve(DiagMappingsStack.size() + 1); DiagMappingsStack.push_back(DiagMappingsStack.back()); } @@ -679,6 +689,12 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { const char *DiagStr = getDiags()->getDescription(getID()); const char *DiagEnd = DiagStr+strlen(DiagStr); + /// FormattedArgs - Keep track of all of the arguments formatted by + /// ConvertArgToString and pass them into subsequent calls to + /// ConvertArgToString, allowing the implementation to avoid redundancies in + /// obvious cases. + llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs; + while (DiagStr != DiagEnd) { if (DiagStr[0] != '%') { // Append non-%0 substrings to Str if we have one. @@ -726,7 +742,9 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); unsigned ArgNo = *DiagStr++ - '0'; - switch (getArgKind(ArgNo)) { + Diagnostic::ArgumentKind Kind = getArgKind(ArgNo); + + switch (Kind) { // ---- STRINGS ---- case Diagnostic::ak_std_string: { const std::string &S = getArgStdStr(ArgNo); @@ -757,9 +775,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); - // FIXME: Optimize - std::string S = llvm::itostr(Val); - OutStr.append(S.begin(), S.end()); + llvm::raw_svector_ostream(OutStr) << Val; } break; } @@ -774,10 +790,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); - - // FIXME: Optimize - std::string S = llvm::utostr_32(Val); - OutStr.append(S.begin(), S.end()); + llvm::raw_svector_ostream(OutStr) << Val; } break; } @@ -793,9 +806,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { continue; } - OutStr.push_back('\''); - OutStr.append(II->getName(), II->getName() + II->getLength()); - OutStr.push_back('\''); + llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } case Diagnostic::ak_qualtype: @@ -803,11 +814,23 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { case Diagnostic::ak_nameddecl: case Diagnostic::ak_nestednamespec: case Diagnostic::ak_declcontext: - getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), + getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), Modifier, ModifierLen, - Argument, ArgumentLen, OutStr); + Argument, ArgumentLen, + FormattedArgs.data(), FormattedArgs.size(), + OutStr); break; } + + // Remember this argument info for subsequent formatting operations. Turn + // std::strings into a null terminated string to make it be the same case as + // all the other ones. + if (Kind != Diagnostic::ak_std_string) + FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); + else + FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string, + (intptr_t)getArgStdStr(ArgNo).c_str())); + } } diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index df86f9d..ee4309d 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -149,6 +149,41 @@ FileManager::~FileManager() { delete &UniqueFiles; } +void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { + assert(statCache && "No stat cache provided?"); + if (AtBeginning || StatCache.get() == 0) { + statCache->setNextStatCache(StatCache.take()); + StatCache.reset(statCache); + return; + } + + StatSysCallCache *LastCache = StatCache.get(); + while (LastCache->getNextStatCache()) + LastCache = LastCache->getNextStatCache(); + + LastCache->setNextStatCache(statCache); +} + +void FileManager::removeStatCache(StatSysCallCache *statCache) { + if (!statCache) + return; + + if (StatCache.get() == statCache) { + // This is the first stat cache. + StatCache.reset(StatCache->takeNextStatCache()); + return; + } + + // Find the stat cache in the list. + StatSysCallCache *PrevCache = StatCache.get(); + while (PrevCache && PrevCache->getNextStatCache() != statCache) + PrevCache = PrevCache->getNextStatCache(); + if (PrevCache) + PrevCache->setNextStatCache(statCache->getNextStatCache()); + else + assert(false && "Stat cache not found for removal"); +} + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// @@ -290,8 +325,8 @@ void FileManager::PrintStats() const { } int MemorizeStatCalls::stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); - + int result = StatSysCallCache::stat(path, buf); + if (result != 0) { // Cache failed 'stat' results. struct stat empty; diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 93c260f..16aa0c5 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" #include <cstdio> using namespace clang; @@ -153,7 +154,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { unsigned Len = getLength(); if (Len < 2) return tok::pp_not_keyword; - const char *Name = getName(); + const char *Name = getNameStart(); switch (HASH(Len, Name[0], Name[2])) { default: return tok::pp_not_keyword; CASE( 2, 'i', '\0', if); @@ -301,24 +302,15 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { } std::string MultiKeywordSelector::getName() const { - std::string Result; - unsigned Length = 0; + llvm::SmallString<256> Str; + llvm::raw_svector_ostream OS(Str); for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { if (*I) - Length += (*I)->getLength(); - ++Length; // : + OS << (*I)->getName(); + OS << ':'; } - Result.reserve(Length); - - for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { - if (*I) - Result.insert(Result.end(), (*I)->getName(), - (*I)->getName()+(*I)->getLength()); - Result.push_back(':'); - } - - return Result; + return OS.str(); } std::string Selector::getAsString() const { @@ -332,9 +324,10 @@ std::string Selector::getAsString() const { if (getNumArgs() == 0) return II->getName(); - std::string Res = II ? II->getName() : ""; - Res += ":"; - return Res; + if (!II) + return ":"; + + return II->getName().str() + ":"; } // We have a multiple keyword selector (no embedded flags). diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 9cd1249..8f3c777 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -43,6 +43,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { UIntMaxType = UnsignedLongLong; IntPtrType = SignedLong; WCharType = SignedInt; + WIntType = SignedInt; Char16Type = UnsignedShort; Char32Type = UnsignedInt; Int64Type = SignedLongLong; @@ -73,6 +74,57 @@ const char *TargetInfo::getTypeName(IntType T) { } } +/// getTypeConstantSuffix - Return the constant suffix for the specified +/// integer type enum. For example, SignedLong -> "L". +const char *TargetInfo::getTypeConstantSuffix(IntType T) { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: return ""; + case SignedLong: return "L"; + case SignedLongLong: return "LL"; + case UnsignedShort: + case UnsignedInt: return "U"; + case UnsignedLong: return "UL"; + case UnsignedLongLong: return "ULL"; + } +} + +/// getTypeWidth - Return the width (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntWidth(). +unsigned TargetInfo::getTypeWidth(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: return getShortWidth(); + case UnsignedShort: return getShortWidth(); + case SignedInt: return getIntWidth(); + case UnsignedInt: return getIntWidth(); + case SignedLong: return getLongWidth(); + case UnsignedLong: return getLongWidth(); + case SignedLongLong: return getLongLongWidth(); + case UnsignedLongLong: return getLongLongWidth(); + }; +} + +/// getTypeSigned - Return whether an integer types is signed. Returns true if +/// the type is signed; false otherwise. +bool TargetInfo::getTypeSigned(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: + case SignedLong: + case SignedLongLong: + return true; + case UnsignedShort: + case UnsignedInt: + case UnsignedLong: + case UnsignedLongLong: + return false; + }; +} + + //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1d4d123..66d6824 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -320,6 +320,27 @@ public: : OSTargetInfo<Target>(triple) {} }; +// AuroraUX target +template<typename Target> +class AuroraUXTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector<char> &Defs) const { + DefineStd(Defs, "sun", Opts); + DefineStd(Defs, "unix", Opts); + Define(Defs, "__ELF__"); + Define(Defs, "__svr4__"); + Define(Defs, "__SVR4"); + } +public: + AuroraUXTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->WCharType = this->SignedLong; + // FIXME: WIntType should be SignedLong + } +}; + // Solaris target template<typename Target> class SolarisTargetInfo : public OSTargetInfo<Target> { @@ -1456,6 +1477,14 @@ void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, } // end anonymous namespace. namespace { +class AuroraUXSparcV8TargetInfo : public AuroraUXTargetInfo<SparcV8TargetInfo> { +public: + AuroraUXSparcV8TargetInfo(const std::string& triple) : + AuroraUXTargetInfo<SparcV8TargetInfo>(triple) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + } +}; class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> { public: SolarisSparcV8TargetInfo(const std::string& triple) : @@ -1573,8 +1602,8 @@ namespace { } virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const { - // FIXME: implement - return true; + // No target constraints for now. + return false; } virtual const char *getClobbers() const { // FIXME: Is this really right? @@ -1846,6 +1875,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { return new PPC64TargetInfo(T); case llvm::Triple::sparc: + if (os == llvm::Triple::AuroraUX) + return new AuroraUXSparcV8TargetInfo(T); if (os == llvm::Triple::Solaris) return new SolarisSparcV8TargetInfo(T); return new SparcV8TargetInfo(T); @@ -1858,6 +1889,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { case llvm::Triple::x86: switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_32TargetInfo>(T); case llvm::Triple::Darwin: return new DarwinI386TargetInfo(T); case llvm::Triple::Linux: @@ -1884,6 +1917,8 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { case llvm::Triple::x86_64: switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::Darwin: return new DarwinX86_64TargetInfo(T); case llvm::Triple::Linux: diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 736425e..682cf5d 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -73,29 +73,60 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo(const Stmt *S, - CodeGenFunction::BlockInfo &Info) { +static void CollectBlockDeclRefInfo( + const Stmt *S, CodeGenFunction::BlockInfo &Info, + llvm::SmallSet<const DeclContext *, 16> &InnerContexts) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) - CollectBlockDeclRefInfo(*I, Info); + CollectBlockDeclRefInfo(*I, Info, InnerContexts); - if (const BlockDeclRefExpr *DE = dyn_cast<BlockDeclRefExpr>(S)) { + // We want to ensure we walk down into block literals so we can find + // all nested BlockDeclRefExprs. + if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { + InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); + CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + } + + if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { // FIXME: Handle enums. - if (isa<FunctionDecl>(DE->getDecl())) + if (isa<FunctionDecl>(BDRE->getDecl())) return; - if (DE->isByRef()) - Info.ByRefDeclRefs.push_back(DE); - else - Info.ByCopyDeclRefs.push_back(DE); + // Only Decls that escape are added. + if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) + Info.DeclRefs.push_back(BDRE); } } /// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be /// declared as a global variable instead of on the stack. static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { - return Info.ByRefDeclRefs.empty() && Info.ByCopyDeclRefs.empty(); + return Info.DeclRefs.empty(); +} + +/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to +/// ensure we can generate the debug information for the parameter for the block +/// invoke function. +static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, + CodeGenFunction *CGF) { + // Always allocate self, as it is often handy in the debugger, even if there + // is no codegen in the block that uses it. This is also useful to always do + // this as if we didn't, we'd have to figure out all code that uses a self + // pointer, including implicit uses. + if (const ObjCMethodDecl *OMD + = dyn_cast_or_null<ObjCMethodDecl>(CGF->CurFuncDecl)) { + ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); + BlockDeclRefExpr *BDRE = new (CGF->getContext()) + BlockDeclRefExpr(SelfDecl, + SelfDecl->getType(), SourceLocation(), false); + CGF->AllocateBlockDecl(BDRE); + } + + // FIXME: Also always forward the this pointer in C++ as well. + + for (size_t i = 0; i < Info.DeclRefs.size(); ++i) + CGF->AllocateBlockDecl(Info.DeclRefs[i]); } // FIXME: Push most into CGM, passing down a few bits, like current function @@ -104,7 +135,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { std::string Name = CurFn->getName(); CodeGenFunction::BlockInfo Info(0, Name.c_str()); - CollectBlockDeclRefInfo(BE->getBody(), Info); + llvm::SmallSet<const DeclContext *, 16> InnerContexts; + InnerContexts.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); // Check if the block can be global. // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like @@ -159,7 +192,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (subBlockDeclRefDecls.size() == 0) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, 0, 0); + Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, + 0, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -269,7 +303,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value *BlockLiteral = LoadBlockStruct(); Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset), "block.literal"); Ty = llvm::PointerType::get(Ty, 0); @@ -391,10 +425,6 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { return GenericExtendedBlockLiteralType; } -bool BlockFunction::BlockRequiresCopying(QualType Ty) { - return CGM.BlockRequiresCopying(Ty); -} - RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { const BlockPointerType *BPT = E->getCallee()->getType()->getAs<BlockPointerType>(); @@ -447,24 +477,34 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { return EmitCall(FnInfo, Func, Args); } -llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { +uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - uint64_t &offset = BlockDecls[VD]; - // See if we have already allocated an offset for this variable. - if (offset == 0) { - // Don't run the expensive check, unless we have to. - if (!BlockHasCopyDispose && BlockRequiresCopying(E->getType())) + if (offset) + return offset; + + // Don't run the expensive check, unless we have to. + if (!BlockHasCopyDispose) + if (E->isByRef() + || BlockRequiresCopying(E->getType())) BlockHasCopyDispose = true; - // if not, allocate one now. - offset = getBlockOffset(E); - } + + // if not, allocate one now. + offset = getBlockOffset(E); + + return offset; +} + +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + uint64_t offset = AllocateBlockDecl(E); + llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset), "block.literal"); if (E->isByRef()) { @@ -576,7 +616,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { } llvm::Value *CodeGenFunction::LoadBlockStruct() { - return Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], "self"); + llvm::Value *V = Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], + "self"); + // For now, we codegen based upon byte offsets. + return Builder.CreateBitCast(V, PtrToInt8Ty); } llvm::Function * @@ -605,14 +648,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, LocalDeclMap[VD] = i->second; } - // FIXME: We need to rearrange the code for copy/dispose so we have this - // sooner, so we can calculate offsets correctly. - if (!BlockHasCopyDispose) - BlockOffset = CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8; - else - BlockOffset = CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericExtendedBlockLiteralType()) / 8; + BlockOffset = CGM.getTargetData() + .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8; BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; const FunctionType *BlockFunctionType = BExpr->getFunctionType(); @@ -630,13 +667,22 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, FunctionArgList Args; + CurFuncDecl = OuterFuncDecl; + const BlockDecl *BD = BExpr->getBlockDecl(); + IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); + + // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below. + AllocateAllBlockDeclRefs(Info, this); + + QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, + BlockDeclRefDecls); // FIXME: This leaks ImplicitParamDecl *SelfDecl = ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); + SourceLocation(), II, + ParmTy); Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType())); BlockStructDecl = SelfDecl; @@ -758,11 +804,13 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Dst, Dst->getType())); ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -843,7 +891,8 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -922,13 +971,15 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Dst, Dst->getType())); // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); @@ -991,7 +1042,8 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionArgList Args; // FIXME: This leaks ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 3a860c0..3ab4efb 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -115,15 +115,8 @@ public: PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext()); } - bool BlockRequiresCopying(QualType Ty) { - if (Ty->isBlockPointerType()) - return true; - if (getContext().isObjCNSObjectType(Ty)) - return true; - if (Ty->isObjCObjectPointerType()) - return true; - return false; - } + bool BlockRequiresCopying(QualType Ty) + { return getContext().BlockRequiresCopying(Ty); } }; class BlockFunction : public BlockBase { @@ -165,11 +158,7 @@ public: /// ByCopyDeclRefs - Variables from parent scopes that have been imported /// into this block. - llvm::SmallVector<const BlockDeclRefExpr *, 8> ByCopyDeclRefs; - - // ByRefDeclRefs - __block variables from parent scopes that have been - // imported into this block. - llvm::SmallVector<const BlockDeclRefExpr *, 8> ByRefDeclRefs; + llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; BlockInfo(const llvm::Type *blt, const char *n) : BlockLiteralTy(blt), Name(n) { @@ -228,7 +217,8 @@ public: llvm::Value *getBlockObjectDispose(); void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF); - bool BlockRequiresCopying(QualType Ty); + bool BlockRequiresCopying(QualType Ty) + { return getContext().BlockRequiresCopying(Ty); } }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 3960cf5..cfa669d 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -590,12 +590,15 @@ void CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); - - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); - if (RD->hasTrivialConstructor()) + const CXXConstructorDecl *CD = E->getConstructor(); + // For a copy constructor, even if it is trivial, must fall thru so + // its argument is code-gen'ed. + if (!CD->isCopyConstructor(getContext())) { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + if (RD->hasTrivialConstructor()) return; - + } // Code gen optimization to eliminate copy constructor and return // its first argument instead. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { @@ -604,7 +607,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, return; } // Call the constructor. - EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, + EmitCXXConstructorCall(CD, Ctor_Complete, Dest, E->arg_begin(), E->arg_end()); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index bad166f..7865516 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -639,9 +639,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // If this structure was expanded into multiple arguments then // we need to create a temporary and reconstruct it from the // arguments. - std::string Name = Arg->getNameAsString(); llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty), - (Name + ".addr").c_str()); + Arg->getName() + ".addr"); // FIXME: What are the right qualifiers here? llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); @@ -650,7 +649,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the arguments used in expansion and increment AI. unsigned Index = 0; for (; AI != End; ++AI, ++Index) - AI->setName(Name + "." + llvm::Twine(Index)); + AI->setName(Arg->getName() + "." + llvm::Twine(Index)); continue; } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 4c62420..1b01e15 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -173,10 +173,14 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, uint64_t Align = M->getContext().getTypeAlign(BT); uint64_t Offset = 0; - return DebugFactory.CreateBasicType(Unit, - BT->getName(M->getContext().getLangOptions()), - Unit, 0, Size, Align, - Offset, /*flags*/ 0, Encoding); + llvm::DIType DbgTy = + DebugFactory.CreateBasicType(Unit, + BT->getName(M->getContext().getLangOptions()), + Unit, 0, Size, Align, + Offset, /*flags*/ 0, Encoding); + + TypeCache[QualType(BT, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, @@ -190,9 +194,12 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); uint64_t Offset = 0; - return DebugFactory.CreateBasicType(Unit, "complex", - Unit, 0, Size, Align, - Offset, /*flags*/ 0, Encoding); + llvm::DIType DbgTy = + DebugFactory.CreateBasicType(Unit, "complex", + Unit, 0, Size, Align, + Offset, /*flags*/ 0, Encoding); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } /// CreateCVRType - Get the qualified type from the cache or create @@ -226,8 +233,11 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit U // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. - return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), - 0, 0, 0, 0, 0, FromTy); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, FromTy); + TypeCache[Ty.getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, @@ -238,9 +248,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, EltTy); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, + "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, EltTy); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, @@ -251,9 +264,10 @@ llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, EltTy); + return + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, + "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, EltTy); } llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, @@ -401,8 +415,11 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, - TyName, DefUnit, Line, 0, 0, 0, 0, Src); + llvm::DIType DbgTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, + TyName, DefUnit, Line, 0, 0, 0, 0, Src); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, @@ -424,10 +441,13 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIArray EltTypeArray = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, - Unit, "", llvm::DICompileUnit(), - 0, 0, 0, 0, 0, - llvm::DIType(), EltTypeArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, + Unit, "", llvm::DICompileUnit(), + 0, 0, 0, 0, 0, + llvm::DIType(), EltTypeArray); + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } /// CreateType - get structure or union type. @@ -713,10 +733,14 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, Align = M->getContext().getTypeAlign(Ty); } - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, EnumName, DefUnit, Line, - Size, Align, 0, 0, - llvm::DIType(), EltArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, + Unit, EnumName, DefUnit, Line, + Size, Align, 0, 0, + llvm::DIType(), EltArray); + + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, @@ -767,11 +791,15 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); - return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_array_type, - Unit, "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, - getOrCreateType(EltTy, Unit), - SubscriptArray); + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_array_type, + Unit, "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, + getOrCreateType(EltTy, Unit), + SubscriptArray); + + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + return DbgTy; } @@ -793,7 +821,6 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, // Otherwise create the type. llvm::DIType Res = CreateTypeNode(Ty, Unit); - TypeCache.insert(std::make_pair(Ty.getAsOpaquePtr(), Res.getNode())); return Res; } @@ -846,8 +873,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, Unit); case Type::ConstantArray: - case Type::ConstantArrayWithExpr: - case Type::ConstantArrayWithoutExpr: case Type::VariableArray: case Type::IncompleteArray: return CreateType(cast<ArrayType>(Ty), Unit); @@ -863,7 +888,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, +void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { const char *LinkageName = Name; @@ -881,7 +906,7 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, llvm::DISubprogram SP = DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo, - getOrCreateType(ReturnType, Unit), + getOrCreateType(FnType, Unit), Fn->hasInternalLinkage(), true/*definition*/); #ifndef ATTACH_DEBUG_INFO_TO_AN_INSN @@ -1366,7 +1391,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), - Name, Name, "", Unit, LineNo, + Name, Name, Name, Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); @@ -1396,7 +1421,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ArrayType::Normal, 0); } - DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo, + DebugFactory.CreateGlobalVariable(Unit, Name, Name, Name, Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 0a617b9..2e44e09 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -88,7 +88,7 @@ public: /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(const char *Name, QualType ReturnType, + void EmitFunctionStart(const char *Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 7feff83..1728c67 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -37,6 +37,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Enum: // enum X; case Decl::EnumConstant: // enum ? { X = ? } case Decl::CXXRecord: // struct/union/class X; [C++] + case Decl::UsingDirective: // using X; [C++] // None of these decls require codegen support. return; @@ -275,8 +276,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; if (NumPaddingBytes > 0) { const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext); - // FIXME: We need a sema error for alignment larger than the minimum of the - // maximal stack alignmint and the alignment of malloc on the system. + // FIXME: We need a sema error for alignment larger than the minimum of + // the maximal stack alignmint and the alignment of malloc on the system. if (NumPaddingBytes > 1) Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 01a057f..bb487f6 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -28,9 +28,9 @@ using namespace CodeGen; /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, - const char *Name) { + const llvm::Twine &Name) { if (!Builder.isNamePreserving()) - Name = ""; + return new llvm::AllocaInst(Ty, 0, "", AllocaInsertPt); return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } @@ -78,24 +78,18 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, QualType DestType, bool IsInitializer) { + bool ShouldDestroyTemporaries = false; + unsigned OldNumLiveTemporaries = 0; + if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!TE->shouldDestroyTemporaries()) - return EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Keep track of the current cleanup stack depth. - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); + ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); + + if (ShouldDestroyTemporaries) { + // Keep track of the current cleanup stack depth. + OldNumLiveTemporaries = LiveTemporaries.size(); + } - return RV; + E = TE->getSubExpr(); } RValue Val; @@ -105,6 +99,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (LV.isSimple()) return RValue::get(LV.getAddress()); Val = EmitLoadOfLValue(LV, E->getType()); + + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } } else { const CXXRecordDecl *BaseClassDecl = 0; const CXXRecordDecl *DerivedClassDecl = 0; @@ -124,6 +124,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } + if (IsInitializer) { // We might have to destroy the temporary variable. if (const RecordType *RT = E->getType()->getAs<RecordType>()) { @@ -297,6 +303,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: return EmitCastLValue(cast<CastExpr>(E)); + case Expr::CXXZeroInitValueExprClass: + return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E)); } } @@ -858,6 +866,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } else if (const QualifiedDeclRefExpr *QDRExpr = + dyn_cast<QualifiedDeclRefExpr>(E)) { + return EmitPointerToDataMemberLValue(QDRExpr); } assert(0 && "Unimp declref"); //an invalid LValue, but the assert will @@ -1307,6 +1318,18 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { } } +LValue CodeGenFunction::EmitNullInitializationLValue( + const CXXZeroInitValueExpr *E) { + QualType Ty = E->getType(); + const llvm::Type *LTy = ConvertTypeForMem(Ty); + llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); + unsigned Align = getContext().getTypeAlign(Ty)/8; + Alloc->setAlignment(Align); + LValue lvalue = LValue::MakeAddr(Alloc, Qualifiers()); + EmitMemSetToZero(lvalue.getAddress(), Ty); + return lvalue; +} + //===--------------------------------------------------------------------===// // Expression Emission //===--------------------------------------------------------------------===// @@ -1356,11 +1379,24 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return EmitLValue(E->getRHS()); } + if (E->getOpcode() == BinaryOperator::PtrMemD) + return EmitPointerToDataMemberBinaryExpr(E); + // Can only get l-value for binary operator expressions which are a // simple assignment of aggregate type. if (E->getOpcode() != BinaryOperator::Assign) return EmitUnsupportedLValue(E, "binary l-value expression"); + if (!hasAggregateLLVMType(E->getType())) { + // Emit the LHS as an l-value. + LValue LV = EmitLValue(E->getLHS()); + + llvm::Value *RHS = EmitScalarExpr(E->getRHS()); + EmitStoreOfScalar(RHS, LV.getAddress(), LV.isVolatileQualified(), + E->getType()); + return LV; + } + llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); // FIXME: Are these qualifiers correct? @@ -1483,6 +1519,25 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { } +LValue CodeGenFunction::EmitPointerToDataMemberLValue( + const QualifiedDeclRefExpr *E) { + const FieldDecl *Field = cast<FieldDecl>(E->getDecl()); + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext()); + QualType NNSpecTy = + getContext().getCanonicalType( + getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl))); + NNSpecTy = getContext().getPointerType(NNSpecTy); + llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy)); + LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field), + /*isUnion*/false, /*Qualifiers*/0); + const llvm::Type* ResultType = ConvertType( + getContext().getPointerDiffType()); + V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, + "datamember"); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LV; +} + RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, @@ -1492,11 +1547,13 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, assert(CalleeType->isFunctionPointerType() && "Call must have function pointer type!"); - QualType FnType = CalleeType->getAs<PointerType>()->getPointeeType(); - QualType ResultType = FnType->getAs<FunctionType>()->getResultType(); + CalleeType = getContext().getCanonicalType(CalleeType); + + QualType FnType = cast<PointerType>(CalleeType)->getPointeeType(); + QualType ResultType = cast<FunctionType>(FnType)->getResultType(); CallArgList Args; - EmitCallArgs(Args, FnType->getAs<FunctionProtoType>(), ArgBeg, ArgEnd); + EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); // FIXME: We should not need to do this, it should be part of the function // type. @@ -1508,3 +1565,25 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallingConvention), Callee, Args, TargetDecl); } + +LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( + const BinaryOperator *E) { + llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress(); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); + BaseV = Builder.CreateBitCast(BaseV, i8Ty); + LValue RHSLV = EmitLValue(E->getRHS()); + llvm::Value *OffsetV = + EmitLoadOfLValue(RHSLV, E->getRHS()->getType()).getScalarVal(); + const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType()); + OffsetV = Builder.CreateBitCast(OffsetV, ResultType); + llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); + QualType Ty = E->getRHS()->getType(); + const MemberPointerType *MemPtrType = Ty->getAs<MemberPointerType>(); + Ty = MemPtrType->getPointeeType(); + const llvm::Type* PType = + ConvertType(getContext().getPointerType(Ty)); + AddV = Builder.CreateBitCast(AddV, PType); + LValue LV = LValue::MakeAddr(AddV, MakeQualifiers(Ty)); + return LV; +} + diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0866ff8..f47b6ab 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -92,6 +92,7 @@ public: void VisitCallExpr(const CallExpr *E); void VisitStmtExpr(const StmtExpr *E); void VisitBinaryOperator(const BinaryOperator *BO); + void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO); void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); void VisitUnaryAddrOf(const UnaryOperator *E); @@ -112,6 +113,7 @@ public: void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); + void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); void VisitVAArgExpr(VAArgExpr *E); @@ -214,6 +216,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CastExpr::CK_BitCast: { + // This must be a member function pointer cast. + Visit(E->getSubExpr()); + break; + } + case CastExpr::CK_BaseToDerivedMemberPointer: { QualType SrcType = E->getSubExpr()->getType(); @@ -285,6 +293,7 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { // We have a member function pointer. const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>(); + (void) MPT; assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); @@ -320,7 +329,16 @@ void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - CGF.ErrorUnsupported(E, "aggregate binary expression"); + if (E->getOpcode() == BinaryOperator::PtrMemD) + VisitPointerToDataMemberBinaryOperator(E); + else + CGF.ErrorUnsupported(E, "aggregate binary expression"); +} + +void AggExprEmitter::VisitPointerToDataMemberBinaryOperator( + const BinaryOperator *E) { + LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E); + EmitFinalDestCopy(E, LV); } void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { @@ -438,6 +456,11 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer); } +void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + LValue lvalue = LValue::MakeAddr(DestPtr, Qualifiers()); + EmitNullInitializationToLValue(lvalue, E->getType()); +} + void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { // FIXME: Ignore result? // FIXME: Are initializers affected by volatile? diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 7f540c3..fc3748c 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -542,7 +542,11 @@ public: return CS; } } - + + case CastExpr::CK_BitCast: + // This must be a member function pointer cast. + return Visit(E->getSubExpr()); + default: { // FIXME: This should be handled by the CK_NoOp cast kind. // Explicit and implicit no-op casts diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index cc81256..69604f9 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -106,6 +106,7 @@ public: return 0; } Value *VisitExpr(Expr *S); + Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } // Leaves. @@ -181,48 +182,7 @@ public: Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } - Value *VisitInitListExpr(InitListExpr *E) { - bool Ignore = TestAndClearIgnoreResultAssign(); - (void)Ignore; - assert (Ignore == false && "init list ignored"); - unsigned NumInitElements = E->getNumInits(); - - if (E->hadArrayRangeDesignator()) { - CGF.ErrorUnsupported(E, "GNU array range designator extension"); - } - - const llvm::VectorType *VType = - dyn_cast<llvm::VectorType>(ConvertType(E->getType())); - - // We have a scalar in braces. Just use the first element. - if (!VType) - return Visit(E->getInit(0)); - - unsigned NumVectorElements = VType->getNumElements(); - const llvm::Type *ElementType = VType->getElementType(); - - // Emit individual vector element stores. - llvm::Value *V = llvm::UndefValue::get(VType); - - // Emit initializers - unsigned i; - for (i = 0; i < NumInitElements; ++i) { - Value *NewV = Visit(E->getInit(i)); - Value *Idx = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - // Emit remaining default initializers - for (/* Do not initialize i*/; i < NumVectorElements; ++i) { - Value *Idx = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); - llvm::Value *NewV = llvm::Constant::getNullValue(ElementType); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - return V; - } + Value *VisitInitListExpr(InitListExpr *E); Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); @@ -404,7 +364,7 @@ public: /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { - assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs"); + assert(SrcType.isCanonical() && "EmitScalarConversion strips typedefs"); if (SrcType->isRealFloatingType()) { // Compare against 0.0 for fp scalars. @@ -577,6 +537,13 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, //===----------------------------------------------------------------------===// Value *ScalarExprEmitter::VisitExpr(Expr *E) { + if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E)) + if (BExpr->getOpcode() == BinaryOperator::PtrMemD) { + LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(BExpr); + Value *InVal = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); + return InVal; + } + CGF.ErrorUnsupported(E, "scalar expression"); if (E->getType()->isVoidType()) return 0; @@ -616,6 +583,174 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { return Builder.CreateExtractElement(Base, Idx, "vecext"); } +static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, + unsigned Off, const llvm::Type *I32Ty) { + int MV = SVI->getMaskValue(Idx); + if (MV == -1) + return llvm::UndefValue::get(I32Ty); + return llvm::ConstantInt::get(I32Ty, Off+MV); +} + +Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { + bool Ignore = TestAndClearIgnoreResultAssign(); + (void)Ignore; + assert (Ignore == false && "init list ignored"); + unsigned NumInitElements = E->getNumInits(); + + if (E->hadArrayRangeDesignator()) + CGF.ErrorUnsupported(E, "GNU array range designator extension"); + + const llvm::VectorType *VType = + dyn_cast<llvm::VectorType>(ConvertType(E->getType())); + + // We have a scalar in braces. Just use the first element. + if (!VType) + return Visit(E->getInit(0)); + + unsigned ResElts = VType->getNumElements(); + const llvm::Type *I32Ty = llvm::Type::getInt32Ty(CGF.getLLVMContext()); + + // Loop over initializers collecting the Value for each, and remembering + // whether the source was swizzle (ExtVectorElementExpr). This will allow + // us to fold the shuffle for the swizzle into the shuffle for the vector + // initializer, since LLVM optimizers generally do not want to touch + // shuffles. + unsigned CurIdx = 0; + bool VIsUndefShuffle = false; + llvm::Value *V = llvm::UndefValue::get(VType); + for (unsigned i = 0; i != NumInitElements; ++i) { + Expr *IE = E->getInit(i); + Value *Init = Visit(IE); + llvm::SmallVector<llvm::Constant*, 16> Args; + + const llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType()); + + // Handle scalar elements. If the scalar initializer is actually one + // element of a different vector of the same width, use shuffle instead of + // extract+insert. + if (!VVT) { + if (isa<ExtVectorElementExpr>(IE)) { + llvm::ExtractElementInst *EI = cast<llvm::ExtractElementInst>(Init); + + if (EI->getVectorOperandType()->getNumElements() == ResElts) { + llvm::ConstantInt *C = cast<llvm::ConstantInt>(EI->getIndexOperand()); + Value *LHS = 0, *RHS = 0; + if (CurIdx == 0) { + // insert into undef -> shuffle (src, undef) + Args.push_back(C); + for (unsigned j = 1; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + LHS = EI->getVectorOperand(); + RHS = V; + VIsUndefShuffle = true; + } else if (VIsUndefShuffle) { + // insert into undefshuffle && size match -> shuffle (v, src) + llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V); + for (unsigned j = 0; j != CurIdx; ++j) + Args.push_back(getMaskElt(SVV, j, 0, I32Ty)); + Args.push_back(llvm::ConstantInt::get(I32Ty, + ResElts + C->getZExtValue())); + for (unsigned j = CurIdx + 1; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + LHS = cast<llvm::ShuffleVectorInst>(V)->getOperand(0); + RHS = EI->getVectorOperand(); + VIsUndefShuffle = false; + } + if (!Args.empty()) { + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + V = Builder.CreateShuffleVector(LHS, RHS, Mask); + ++CurIdx; + continue; + } + } + } + Value *Idx = llvm::ConstantInt::get(I32Ty, CurIdx); + V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); + VIsUndefShuffle = false; + ++CurIdx; + continue; + } + + unsigned InitElts = VVT->getNumElements(); + + // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's + // input is the same width as the vector being constructed, generate an + // optimized shuffle of the swizzle input into the result. + if (isa<ExtVectorElementExpr>(IE)) { + llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init); + Value *SVOp = SVI->getOperand(0); + const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); + + if (OpTy->getNumElements() == ResElts) { + unsigned Offset = (CurIdx == 0) ? 0 : ResElts; + + for (unsigned j = 0; j != CurIdx; ++j) { + // If the current vector initializer is a shuffle with undef, merge + // this shuffle directly into it. + if (VIsUndefShuffle) { + Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0, + I32Ty)); + } else { + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + } + } + for (unsigned j = 0, je = InitElts; j != je; ++j) + Args.push_back(getMaskElt(SVI, j, Offset, I32Ty)); + for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + + if (VIsUndefShuffle) + V = cast<llvm::ShuffleVectorInst>(V)->getOperand(0); + + Init = SVOp; + } + } + + // Extend init to result vector length, and then shuffle its contribution + // to the vector initializer into V. + if (Args.empty()) { + for (unsigned j = 0; j != InitElts; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + for (unsigned j = InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT), + Mask, "vecext"); + + Args.clear(); + for (unsigned j = 0; j != CurIdx; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j)); + for (unsigned j = 0; j != InitElts; ++j) + Args.push_back(llvm::ConstantInt::get(I32Ty, j+ResElts)); + for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) + Args.push_back(llvm::UndefValue::get(I32Ty)); + } + + // If V is undef, make sure it ends up on the RHS of the shuffle to aid + // merging subsequent shuffles into this one. + if (CurIdx == 0) + std::swap(V, Init); + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); + V = Builder.CreateShuffleVector(V, Init, Mask, "vecinit"); + VIsUndefShuffle = isa<llvm::UndefValue>(Init); + CurIdx += InitElts; + } + + // FIXME: evaluate codegen vs. shuffling against constant null vector. + // Emit remaining default initializers. + const llvm::Type *EltTy = VType->getElementType(); + + // Emit remaining default initializers + for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) { + Value *Idx = llvm::ConstantInt::get(I32Ty, CurIdx); + llvm::Value *Init = llvm::Constant::getNullValue(EltTy); + V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); + } + return V; +} + // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. @@ -700,7 +835,16 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { case CastExpr::CK_IntegralToPointer: { Value *Src = Visit(const_cast<Expr*>(E)); - return Builder.CreateIntToPtr(Src, ConvertType(DestTy)); + + // First, convert to the correct width so that we control the kind of + // extension. + const llvm::Type *MiddleTy = + llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth); + bool InputSigned = E->getType()->isSignedIntegerType(); + llvm::Value* IntResult = + Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); + + return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); } case CastExpr::CK_PointerToIntegral: { @@ -1379,18 +1523,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { + const llvm::Type *ResTy = ConvertType(E->getType()); + // If we have 0 && RHS, see if we can elide RHS, if so, just return 0. // If we have 1 && X, just emit X without inserting the control flow. if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { if (Cond == 1) { // If we have 1 && X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - // ZExt result to int. - return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "land.ext"); + // ZExt result to int or bool. + return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext"); } - // 0 && RHS: If it is safe, just elide the RHS, and return 0. + // 0 && RHS: If it is safe, just elide the RHS, and return 0/false. if (!CGF.ContainsLabel(E->getRHS())) - return llvm::Constant::getNullValue(CGF.LLVMIntTy); + return llvm::Constant::getNullValue(ResTy); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end"); @@ -1423,22 +1569,24 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext"); + return Builder.CreateZExtOrBitCast(PN, ResTy, "land.ext"); } Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { + const llvm::Type *ResTy = ConvertType(E->getType()); + // If we have 1 || RHS, see if we can elide RHS, if so, just return 1. // If we have 0 || X, just emit X without inserting the control flow. if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { if (Cond == -1) { // If we have 0 || X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - // ZExt result to int. - return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "lor.ext"); + // ZExt result to int or bool. + return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext"); } - // 1 || RHS: If it is safe, just elide the RHS, and return 1. + // 1 || RHS: If it is safe, just elide the RHS, and return 1/true. if (!CGF.ContainsLabel(E->getRHS())) - return llvm::ConstantInt::get(CGF.LLVMIntTy, 1); + return llvm::ConstantInt::get(ResTy, 1); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end"); @@ -1474,7 +1622,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext"); + return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext"); } Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 4485ed5..9b2f4a1 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -850,7 +850,7 @@ protected: /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD, - std::string &NameOut); + llvm::SmallVectorImpl<char> &NameOut); /// GetMethodVarName - Return a unique constant for the given /// selector's name. The return value has type char *. @@ -900,7 +900,7 @@ protected: /// EmitPropertyList - Emit the given property list. The return /// value has type PropertyListPtrTy. - llvm::Constant *EmitPropertyList(const std::string &Name, + llvm::Constant *EmitPropertyList(llvm::Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); @@ -924,7 +924,7 @@ protected: /// \param Align - The alignment for the variable, or 0. /// \param AddToUsed - Whether the variable should be added to /// "llvm.used". - llvm::GlobalVariable *CreateMetadataVar(const std::string &Name, + llvm::GlobalVariable *CreateMetadataVar(llvm::Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, @@ -1025,7 +1025,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListPtrTy. - llvm::Constant *EmitMethodList(const std::string &Name, + llvm::Constant *EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); @@ -1040,7 +1040,7 @@ private: /// - begin, end: The method list to output. /// /// The return value has type MethodDescriptionListPtrTy. - llvm::Constant *EmitMethodDescList(const std::string &Name, + llvm::Constant *EmitMethodDescList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); @@ -1066,7 +1066,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(const std::string &Name, + llvm::Constant *EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1197,7 +1197,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListnfABITy. - llvm::Constant *EmitMethodList(const std::string &Name, + llvm::Constant *EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods); /// EmitIvarList - Emit the ivar list for the given @@ -1224,7 +1224,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(const std::string &Name, + llvm::Constant *EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1616,8 +1616,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { // resolved. Investigate. Its also wasteful to look this up over and over. LazySymbols.insert(&CGM.getContext().Idents.get("Protocol")); - const char *ProtocolName = PD->getNameAsCString(); - // Construct method lists. std::vector<llvm::Constant*> InstanceMethods, ClassMethods; std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; @@ -1647,17 +1645,15 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods); Values[1] = GetClassName(PD->getIdentifier()); Values[2] = - EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(), + EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(), PD->protocol_begin(), PD->protocol_end()); Values[3] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); Values[4] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, @@ -1672,7 +1668,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::InternalLinkage, Init, - std::string("\01L_OBJC_PROTOCOL_")+ProtocolName); + "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? @@ -1694,7 +1690,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::ExternalLinkage, 0, - "\01L_OBJC_PROTOCOL_" + PD->getNameAsString()); + "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? @@ -1722,16 +1718,14 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[1] = EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", OptInstanceMethods); Values[2] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getNameAsString(), + EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", OptClassMethods); - Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + - PD->getNameAsString(), + Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD, ObjCTypes); // Return null if no extension bits are used. @@ -1743,7 +1737,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values); // No special section, but goes in llvm.used - return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getNameAsString(), + return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getName(), Init, 0, 0, true); } @@ -1756,7 +1750,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, }; */ llvm::Constant * -CGObjCMac::EmitProtocolList(const std::string &Name, +CGObjCMac::EmitProtocolList(llvm::Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; @@ -1800,7 +1794,7 @@ CGObjCMac::EmitProtocolList(const std::string &Name, struct _objc_property[prop_count]; }; */ -llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name, +llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { @@ -1854,7 +1848,7 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { Desc); } -llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name, +llvm::Constant *CGObjCMac::EmitMethodDescList(llvm::Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -1894,8 +1888,10 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { const ObjCInterfaceDecl *Interface = OCD->getClassInterface(); const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); - std::string ExtName(Interface->getNameAsString() + "_" + - OCD->getNameAsString()); + + llvm::SmallString<256> ExtName; + llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_' + << OCD->getName(); std::vector<llvm::Constant*> InstanceMethods, ClassMethods; for (ObjCCategoryImplDecl::instmeth_iterator @@ -1914,17 +1910,16 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[1] = GetClassName(Interface->getIdentifier()); LazySymbols.insert(Interface->getIdentifier()); Values[2] = - EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") + - ExtName, + EmitMethodList("\01L_OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); Values[3] = - EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName, + EmitMethodList("\01L_OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); if (Category) { Values[4] = - EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName, + EmitProtocolList("\01L_OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(), Category->protocol_begin(), Category->protocol_end()); } else { @@ -1934,7 +1929,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // If there is no category @interface then there can be no properties. if (Category) { - Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_")+ExtName, + Values[6] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), OCD, Category, ObjCTypes); } else { Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); @@ -1944,7 +1939,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values); llvm::GlobalVariable *GV = - CreateMetadataVar(std::string("\01L_OBJC_CATEGORY_")+ExtName, Init, + CreateMetadataVar("\01L_OBJC_CATEGORY_" + ExtName.str(), Init, "__OBJC,__category,regular,no_dead_strip", 4, true); DefinedCategories.push_back(GV); @@ -1988,7 +1983,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { ObjCInterfaceDecl *Interface = const_cast<ObjCInterfaceDecl*>(ID->getClassInterface()); llvm::Constant *Protocols = - EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getNameAsString(), + EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(), Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; @@ -2046,7 +2041,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, false); Values[ 7] = - EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getNameAsString(), + EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getName(), "__OBJC,__inst_meth,regular,no_dead_strip", InstanceMethods); // cache is always NULL. @@ -2058,7 +2053,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values); llvm::GlobalVariable *GV = - CreateMetadataVar(std::string("\01L_OBJC_CLASS_")+ClassName, Init, + CreateMetadataVar("\01L_OBJC_CLASS_" + ClassName, Init, "__OBJC,__class,regular,no_dead_strip", 4, true); DefinedClasses.push_back(GV); @@ -2174,7 +2169,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { std::vector<llvm::Constant*> Values(3); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[1] = BuildIvarLayout(ID, false); - Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), + Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), ID, ID->getClassInterface(), ObjCTypes); // Return null if no extension bits are used. @@ -2183,7 +2178,7 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values); - return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getNameAsString(), + return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getName(), Init, "__OBJC,__class_ext,regular,no_dead_strip", 4, true); } @@ -2243,12 +2238,11 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, llvm::GlobalVariable *GV; if (ForClass) - GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getNameAsString(), + GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getName(), Init, "__OBJC,__class_vars,regular,no_dead_strip", 4, true); else - GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" - + ID->getNameAsString(), + GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" + ID->getName(), Init, "__OBJC,__instance_vars,regular,no_dead_strip", 4, true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy); @@ -2286,7 +2280,7 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); } -llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, +llvm::Constant *CGObjCMac::EmitMethodList(llvm::Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -2308,7 +2302,7 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { - std::string Name; + llvm::SmallString<256> Name; GetNameForMethod(OMD, CD, Name); CodeGenTypes &Types = CGM.getTypes(); @@ -2317,7 +2311,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, - Name, + Name.str(), &CGM.getModule()); MethodDefinitions.insert(std::make_pair(OMD, Method)); @@ -2325,7 +2319,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, } llvm::GlobalVariable * -CGObjCCommonMac::CreateMetadataVar(const std::string &Name, +CGObjCCommonMac::CreateMetadataVar(llvm::Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, @@ -2985,7 +2979,8 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", - llvm::ConstantArray::get(VMContext, Ident->getName()), + llvm::ConstantArray::get(VMContext, + Ident->getNameStart()), "__TEXT,__cstring,cstring_literals", 1, true); @@ -3434,7 +3429,8 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_", - llvm::ConstantArray::get(VMContext, Ident->getName()), + llvm::ConstantArray::get(VMContext, + Ident->getNameStart()), "__TEXT,__cstring,cstring_literals", 1, true); @@ -3453,21 +3449,15 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, const ObjCContainerDecl *CD, - std::string &NameOut) { - NameOut = '\01'; - NameOut += (D->isInstanceMethod() ? '-' : '+'); - NameOut += '['; + llvm::SmallVectorImpl<char> &Name) { + llvm::raw_svector_ostream OS(Name); assert (CD && "Missing container decl in GetNameForMethod"); - NameOut += CD->getNameAsString(); + OS << '\01' << (D->isInstanceMethod() ? '-' : '+') + << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) { - NameOut += '('; - NameOut += CID->getNameAsString(); - NameOut+= ')'; - } - NameOut += ' '; - NameOut += D->getSelector().getAsString(); - NameOut += ']'; + dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) + OS << '(' << CID->getNameAsString() << ')'; + OS << ' ' << D->getSelector().getAsString() << ']'; } void CGObjCMac::FinishModule() { @@ -4256,7 +4246,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" - + OID->getNameAsString(), + + OID->getName(), OID->protocol_begin(), OID->protocol_end()); @@ -4269,9 +4259,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( if (flags & CLS_META) Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); else - Values[ 9] = - EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), - ID, ID->getClassInterface(), ObjCTypes); + Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), + ID, ID->getClassInterface(), ObjCTypes); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy, Values); llvm::GlobalVariable *CLASS_RO_GV = @@ -4532,16 +4521,16 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { - std::string ExtName(Interface->getNameAsString() + "_$_" + - OCD->getNameAsString()); + llvm::SmallString<256> ExtName; + llvm::raw_svector_ostream(ExtName) << Interface->getName() << "_$_" + << OCD->getName(); Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_" - + Interface->getNameAsString() + "_$_" - + Category->getNameAsString(), + + Interface->getName() + "_$_" + + Category->getName(), Category->protocol_begin(), Category->protocol_end()); - Values[5] = - EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName, - OCD, Category, ObjCTypes); + Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes); } else { Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); @@ -4593,10 +4582,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( /// struct _objc_method method_list[method_count]; /// } /// -llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList( - const std::string &Name, - const char *Section, - const ConstantVector &Methods) { +llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, + const char *Section, + const ConstantVector &Methods) { // Return null for empty list. if (Methods.empty()) return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy); @@ -4742,7 +4730,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - Prefix + OID->getNameAsString()); + Prefix + OID->getName()); GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); @@ -4763,7 +4751,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, llvm::GlobalValue::ExternalLinkage, 0, - "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString()); + "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } @@ -4795,8 +4783,6 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( if (Entry && Entry->hasInitializer()) return Entry; - const char *ProtocolName = PD->getNameAsCString(); - // Construct method lists. std::vector<llvm::Constant*> InstanceMethods, ClassMethods; std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; @@ -4826,28 +4812,27 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // isa is NULL Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy); Values[1] = GetClassName(PD->getIdentifier()); - Values[2] = EmitProtocolList( - "\01l_OBJC_$_PROTOCOL_REFS_" + PD->getNameAsString(), - PD->protocol_begin(), - PD->protocol_end()); + Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getName(), + PD->protocol_begin(), + PD->protocol_end()); Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", InstanceMethods); Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", ClassMethods); Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", OptInstanceMethods); Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getName(), "__DATA, __objc_const", OptClassMethods); - Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getNameAsString(), + Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(), 0, PD, ObjCTypes); uint32_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); @@ -4862,10 +4847,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( Entry->setInitializer(Init); } else { Entry = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName); + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, + false, llvm::GlobalValue::WeakAnyLinkage, Init, + "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); @@ -4875,13 +4859,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // Use this protocol meta-data to build protocol list table in section // __DATA, __objc_protolist - llvm::GlobalVariable *PTGV = new llvm::GlobalVariable( - CGM.getModule(), - ObjCTypes.ProtocolnfABIPtrTy, false, - llvm::GlobalValue::WeakAnyLinkage, - Entry, - std::string("\01l_OBJC_LABEL_PROTOCOL_$_") - +ProtocolName); + llvm::GlobalVariable *PTGV = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy, + false, llvm::GlobalValue::WeakAnyLinkage, Entry, + "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); @@ -4899,9 +4880,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( /// @endcode /// llvm::Constant * -CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end) { +CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, + ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; // Just return null for empty protocol lists @@ -4909,10 +4890,12 @@ CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); // FIXME: We shouldn't need to do this lookup here, should we? - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); + llvm::SmallString<256> TmpName; + Name.toVector(TmpName); + llvm::GlobalVariable *GV = + CGM.getModule().getGlobalVariable(TmpName.str(), true); if (GV) - return llvm::ConstantExpr::getBitCast(GV, - ObjCTypes.ProtocolListnfABIPtrTy); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); for (; begin != end; ++begin) ProtocolRefs.push_back(GetProtocolRef(*begin)); // Implemented??? @@ -5683,7 +5666,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::ExternalLinkage, 0, - (std::string("OBJC_EHTYPE_$_") + + ("OBJC_EHTYPE_$_" + ID->getIdentifier()->getName())); } @@ -5715,7 +5698,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::WeakAnyLinkage, Init, - (std::string("OBJC_EHTYPE_$_") + + ("OBJC_EHTYPE_$_" + ID->getIdentifier()->getName())); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 6e73db3..9df0e1a 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -119,6 +119,43 @@ public: Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B); + Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B, + Index_t Offset = 0) { + + if (B == D) + return Offset; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D); + for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(), + e = D->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + int64_t BaseOffset = 0; + if (!i->isVirtual()) + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + int64_t o = getNVOffset_1(Base, B, BaseOffset); + if (o >= 0) + return o; + } + + return -1; + } + + /// getNVOffset - Returns the non-virtual offset for the given (B) base of the + /// derived class D. + Index_t getNVOffset(QualType qB, QualType qD) { + qD = qD->getAs<PointerType>()->getPointeeType(); + qB = qB->getAs<PointerType>()->getPointeeType(); + CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); + CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); + int64_t o = getNVOffset_1(D, B); + if (o >= 0) + return o; + + assert(false && "FIXME: non-virtual base not found"); + return 0; + } + /// getVbaseOffset - Returns the index into the vtable for the virtual base /// offset for the given (B) virtual base of the derived class D. Index_t getVbaseOffset(QualType qB, QualType qD) { @@ -138,8 +175,10 @@ public: } bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, - bool MorallyVirtual, Index_t Offset) { + bool MorallyVirtual, Index_t OverrideOffset, + Index_t Offset) { typedef CXXMethodDecl::method_iterator meth_iter; + // FIXME: Should OverrideOffset's be Offset? // FIXME: Don't like the nested loops. For very large inheritance // heirarchies we could have a table on the side with the final overridder @@ -166,11 +205,12 @@ public: CallOffset ReturnOffset = std::make_pair(0, 0); if (oret != ret) { // FIXME: calculate offsets for covariance - Index_t nv = 0; if (CovariantThunks.count(OMD)) { oret = CovariantThunks[OMD].second; CovariantThunks.erase(OMD); } + // FIXME: Double check oret + Index_t nv = getNVOffset(oret, ret)/8; ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret)); } Index[MD] = i; @@ -180,17 +220,16 @@ public: if (MorallyVirtual) { Index_t &idx = VCall[OMD]; if (idx == 0) { - VCallOffset[MD] = Offset/8; + VCallOffset[MD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); } else { VCallOffset[MD] = VCallOffset[OMD]; - VCalls[idx-1] = -VCallOffset[OMD] + Offset/8; + VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; } VCall[MD] = idx; CallOffset ThisOffset; - // FIXME: calculate non-virtual offset - ThisOffset = std::make_pair(0 /* -CurrentVBaseOffset/8 + Offset/8 */, + ThisOffset = std::make_pair(CurrentVBaseOffset/8 - Offset/8, -((idx+extra+2)*LLVMPointerWidth/8)); // FIXME: Do we always have to build a covariant thunk to save oret, // which is the containing virtual base class? @@ -204,8 +243,8 @@ public: } // FIXME: finish off - int64_t O = VCallOffset[OMD] - Offset/8; - // int64_t O = CurrentVBaseOffset/8 - Offset/8; + int64_t O = VCallOffset[OMD] - OverrideOffset/8; + // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8; if (O || ReturnOffset.first || ReturnOffset.second) { CallOffset ThisOffset = std::make_pair(O, 0); @@ -248,11 +287,11 @@ public: CovariantThunks.clear(); } - void OverrideMethods(Path_t *Path, bool MorallyVirtual) { + void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) { for (Path_t::reverse_iterator i = Path->rbegin(), e = Path->rend(); i != e; ++i) { const CXXRecordDecl *RD = i->first; - int64_t Offset = i->second; + int64_t OverrideOffset = i->second; for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) { if (!mi->isVirtual()) @@ -272,7 +311,7 @@ public: m = wrap(CGM.GetAddrOfFunction(MD, Ty)); } - OverrideMethod(MD, m, MorallyVirtual, Offset); + OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset); } } } @@ -291,7 +330,7 @@ public: } // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(MD, m, MorallyVirtual, Offset)) + if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset)) return; // else allocate a new slot. @@ -344,7 +383,7 @@ public: llvm::Constant *e = 0; D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); - methods.insert(methods.begin() + InsertionPoint, VCalls.size()/*+2*/, e); + methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); // The vcalls come first... for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), e = VCalls.rend(); @@ -380,7 +419,9 @@ public: int VCallInsertionPoint = methods.size(); if (!DeferVCalls) { insertVCalls(VCallInsertionPoint); - } + } else + // FIXME: just for extra, or for all uses of VCalls.size post this? + extra = -VCalls.size(); if (ForVirtualBase) { D(methods.push_back(wrap(668))); @@ -463,7 +504,7 @@ public: AddMethods(RD, MorallyVirtual, Offset); if (Path) - OverrideMethods(Path, MorallyVirtual); + OverrideMethods(Path, MorallyVirtual, Offset); return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, Offset, ForVirtualBase, Path); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 5206f44..ba93e5d 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -167,18 +167,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Builder.SetInsertPoint(EntryBB); + QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0); + // Emit subprogram debug descriptor. // FIXME: The cast here is a huge hack. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(StartLoc); if (isa<FunctionDecl>(D)) { - DI->EmitFunctionStart(CGM.getMangledName(GD), RetTy, CurFn, Builder); + DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); } else { // Just use LLVM function name. // FIXME: Remove unnecessary conversion to std::string when API settles. DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), - RetTy, CurFn, Builder); + FnType, CurFn, Builder); } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 722d002..639e683 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -34,6 +34,7 @@ namespace llvm { class LLVMContext; class Module; class SwitchInst; + class Twine; class Value; } @@ -355,6 +356,7 @@ public: void BlockForwardSelf(); llvm::Value *LoadBlockStruct(); + uint64_t AllocateBlockDecl(const BlockDeclRefExpr *E); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); const llvm::Type *BuildByRefType(const ValueDecl *D); @@ -508,7 +510,7 @@ public: /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, - const char *Name = "tmp"); + const llvm::Twine &Name = "tmp"); /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. @@ -816,7 +818,9 @@ public: LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); - + LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); + LValue EmitPointerToDataMemberLValue(const QualifiedDeclRefExpr *E); + llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field, @@ -841,7 +845,8 @@ public: LValue EmitObjCKVCRefLValue(const ObjCImplicitSetterGetterRefExpr *E); LValue EmitObjCSuperExprLValue(const ObjCSuperExpr *E); LValue EmitStmtExprLValue(const StmtExpr *E); - + LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); + //===--------------------------------------------------------------------===// // Scalar Expression Emission //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4763b7f..ea84829 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -825,7 +825,7 @@ llvm::Constant * CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, const char *Name) { // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } @@ -911,7 +911,7 @@ llvm::Constant * CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty, const char *Name) { // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0); } @@ -1254,7 +1254,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { // Unique the name through the identifier table. const char *AliaseeName = AA->getAliasee().c_str(); - AliaseeName = getContext().Idents.get(AliaseeName).getName(); + AliaseeName = getContext().Idents.get(AliaseeName).getNameStart(); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. @@ -1341,7 +1341,7 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, cast<llvm::FunctionType>(getTypes().ConvertType(Type)); // Unique the name through the identifier table. - Name = getContext().Idents.get(Name).getName(); + Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD)); } diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index fd77274..2e6034b 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -248,7 +248,12 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { FD = PrimaryTemplate->getTemplatedDecl(); } - mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), MangleReturnType); + // Do the canonicalization out here because parameter types can + // undergo additional canonicalization (e.g. array decay). + FunctionType *FT = cast<FunctionType>(Context.getASTContext() + .getCanonicalType(FD->getType())); + + mangleBareFunctionType(FT, MangleReturnType); } static bool isStdNamespace(const DeclContext *DC) { @@ -705,7 +710,7 @@ void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); - bool IsSubstitutable = !isa<BuiltinType>(T); + bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T); if (IsSubstitutable && mangleSubstitution(T)) return; @@ -1236,10 +1241,7 @@ static bool isCharSpecialization(QualType T, const char *Name) { if (!isCharType(TemplateArgs[0].getAsType())) return false; - if (strcmp(SD->getIdentifier()->getName(), Name) != 0) - return false; - - return true; + return SD->getIdentifier()->getName() == Name; } bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 59f579f..852bba4 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -353,11 +353,17 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, return ABIArgInfo::getDirect(); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = RetTy->getAsStructureType()) + if (const RecordType *RT = RetTy->getAsStructureType()) { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + if (hasNonTrivialDestructorOrCopyConstructor(RT)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(0); - + } + // If specified, structs and unions are always indirect. if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) return ABIArgInfo::getIndirect(0); @@ -1744,14 +1750,14 @@ const ABIInfo &CodeGenTypes::getABIInfo() const { return *(TheABIInfo = new SystemZABIInfo()); case llvm::Triple::x86: - if (Triple.getOS() == llvm::Triple::Darwin) - return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); - switch (Triple.getOS()) { + case llvm::Triple::Darwin: + return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); case llvm::Triple::Cygwin: - case llvm::Triple::DragonFly: case llvm::Triple::MinGW32: case llvm::Triple::MinGW64: + case llvm::Triple::AuroraUX: + case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: return *(TheABIInfo = new X86_32ABIInfo(Context, false, true)); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a5a48ad..ae8119d 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -38,7 +38,8 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, DarwinVersion[2] = _DarwinVersion[2]; llvm::raw_string_ostream(MacosxVersionMin) - << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; + << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' + << DarwinVersion[1]; // FIXME: Lift default up. IPhoneOSVersionMin = "3.0"; @@ -54,7 +55,6 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, GCCVersion[2] = _GCCVersion[2]; // Set up the tool chain paths to match gcc. - ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(DarwinVersion[0]); ToolChainDir += "/"; @@ -64,6 +64,26 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, ToolChainDir += '.'; ToolChainDir += llvm::utostr(GCCVersion[2]); + // Try the next major version if that tool chain dir is invalid. + std::string Tmp = "/usr/lib/gcc/" + ToolChainDir; + if (!llvm::sys::Path(Tmp).exists()) { + std::string Next = "i686-apple-darwin"; + Next += llvm::utostr(DarwinVersion[0] + 1); + Next += "/"; + Next += llvm::utostr(GCCVersion[0]); + Next += '.'; + Next += llvm::utostr(GCCVersion[1]); + Next += '.'; + Next += llvm::utostr(GCCVersion[2]); + + // Use that if it exists, otherwise hope the user isn't linking. + // + // FIXME: Drop dependency on gcc's tool chain. + Tmp = "/usr/lib/gcc/" + Next; + if (llvm::sys::Path(Tmp).exists()) + ToolChainDir = Next; + } + std::string Path; if (getArchName() == "x86_64") { Path = getHost().getDriver().Dir; @@ -676,6 +696,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/sfw/lib"); getFilePaths().push_back("/opt/gcc4/lib"); + getFilePaths().push_back("/opt/gcc4/lib/gcc/i386-pc-solaris2.11/4.2.4"); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index fc91e4c..c9d0b26 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -142,10 +142,15 @@ void Clang::AddPreprocessingOptions(const Driver &D, continue; if (A->getOption().matches(options::OPT_include)) { + // Use PCH if the user requested it, except for C++ (for now). + bool UsePCH = D.CCCUsePCH; + if (types::isCXX(Inputs[0].getType())) + UsePCH = false; + bool FoundPTH = false; bool FoundPCH = false; llvm::sys::Path P(A->getValue(Args)); - if (D.CCCUsePCH) { + if (UsePCH) { P.appendSuffix("pch"); if (P.exists()) FoundPCH = true; @@ -164,8 +169,8 @@ void Clang::AddPreprocessingOptions(const Driver &D, if (!FoundPCH && !FoundPTH) { P.appendSuffix("gch"); if (P.exists()) { - FoundPCH = D.CCCUsePCH; - FoundPTH = !D.CCCUsePCH; + FoundPCH = UsePCH; + FoundPTH = !UsePCH; } else P.eraseSuffix(); @@ -173,7 +178,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, if (FoundPCH || FoundPTH) { A->claim(); - if (D.CCCUsePCH) + if (UsePCH) CmdArgs.push_back("-include-pch"); else CmdArgs.push_back("-include-pth"); @@ -528,7 +533,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-E"); } else if (isa<PrecompileJobAction>(JA)) { - if (D.CCCUsePCH) + // Use PCH if the user requested it, except for C++ (for now). + bool UsePCH = D.CCCUsePCH; + if (types::isCXX(Inputs[0].getType())) + UsePCH = false; + + if (UsePCH) CmdArgs.push_back("-emit-pch"); else CmdArgs.push_back("-emit-pth"); @@ -759,7 +769,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // option. if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) - CmdArgs.push_back("-std=c89"); + if (types::isCXX(InputType)) + CmdArgs.push_back("-std=c++98"); + else + CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); @@ -2149,7 +2162,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); + Args.MakeArgString(getToolChain().GetProgramPath(C, "gas")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -2164,18 +2177,19 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); - CmdArgs.push_back("__start"); + CmdArgs.push_back("_start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); + CmdArgs.push_back("-dn"); } else { - CmdArgs.push_back("--eh-frame-hdr"); +// CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { - CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("--dynamic-linker"); CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1 } } @@ -2193,11 +2207,14 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); +// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } CmdArgs.push_back(MakeFormattedString(Args, @@ -2242,8 +2259,8 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); - else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); +// else +// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); } const char *Exec = diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index d3475b5..c0415bf 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -21,11 +21,20 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/Compiler.h" +#include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(Diagnostic &_Diags) : Diags(_Diags) { } -ASTUnit::~ASTUnit() { } +ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { + Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); +} +ASTUnit::~ASTUnit() { + if (tempFile) + llvm::sys::Path(getPCHFileName()).eraseFromDisk(); + + // The ASTUnit object owns the DiagnosticClient. + delete Diags.getClient(); +} namespace { @@ -80,17 +89,18 @@ const std::string &ASTUnit::getOriginalSourceFileName() { return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile(); } -FileManager &ASTUnit::getFileManager() { - return HeaderInfo->getFileMgr(); +const std::string &ASTUnit::getPCHFileName() { + return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, - Diagnostic &Diags, - FileManager &FileMgr, - std::string *ErrMsg) { - llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags)); - - AST->HeaderInfo.reset(new HeaderSearch(FileMgr)); + std::string *ErrMsg, + DiagnosticClient *diagClient, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient)); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); // Gather Info for preprocessor construction later on. @@ -103,7 +113,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, llvm::OwningPtr<PCHReader> Reader; llvm::OwningPtr<ExternalASTSource> Source; - Reader.reset(new PCHReader(AST->getSourceManager(), FileMgr, AST->Diags)); + Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), + AST->Diags)); Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -138,7 +149,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), - /* FreeMemory = */ true, + /* FreeMemory = */ !UseBumpAllocator, /* size_reserve = */0)); ASTContext &Context = *AST->Ctx.get(); diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 2765994..55f2740 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -196,7 +196,7 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { case Decl::Function: { FunctionDecl* FD = cast<FunctionDecl>(D); - if (Opts.AnalyzeSpecificFunction.size() > 0 && + if (!Opts.AnalyzeSpecificFunction.empty() && Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) break; @@ -273,6 +273,9 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { !Ctx->getSourceManager().isFromMainFile(D->getLocation())) return; + // Clear the AnalysisManager of old AnalysisContexts. + Mgr->ClearContexts(); + // Dispatch on the actions. for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) (*I)(*Mgr, D); diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index e7fc566..339a1c4 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -20,11 +20,12 @@ #include "clang/Basic/OnDiskHashTable.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include "llvm/ADT/StringMap.h" // FIXME: put this somewhere else? #ifndef S_ISDIR @@ -69,7 +70,7 @@ public: bool isFile() const { return Kind == IsFE; } - const char* getCString() const { + llvm::StringRef getString() const { return Kind == IsFE ? FE->getName() : Path; } @@ -113,14 +114,14 @@ public: typedef const PTHEntry& data_type_ref; static unsigned ComputeHash(PTHEntryKeyVariant V) { - return BernsteinHash(V.getCString()); + return llvm::HashString(V.getString()); } static std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E) { - unsigned n = strlen(V.getCString()) + 1 + 1; + unsigned n = V.getString().size() + 1 + 1; ::Emit16(Out, n); unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0); @@ -133,7 +134,7 @@ public: // Emit the entry kind. ::Emit8(Out, (unsigned) V.getKind()); // Emit the string. - Out.write(V.getCString(), n - 1); + Out.write(V.getString().data(), n - 1); } static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, @@ -516,7 +517,7 @@ public: ~StatListener() {} int stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); + int result = StatSysCallCache::stat(path, buf); if (result != 0) // Failed 'stat'. PM.insert(path, PTHEntry()); @@ -553,7 +554,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { PTHWriter PW(*OS, PP); // Install the 'stat' system call listener in the FileManager. - PP.getFileManager().setStatCache(new StatListener(PW.getPM())); + StatListener *StatCache = new StatListener(PW.getPM()); + PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true); // Lex through the entire file. This will populate SourceManager with // all of the header information. @@ -562,7 +564,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. - PP.getFileManager().setStatCache(0); + PP.getFileManager().removeStatCache(StatCache); PW.GeneratePTH(&MainFileName); } @@ -584,12 +586,12 @@ public: typedef data_type data_type_ref; static unsigned ComputeHash(PTHIdKey* key) { - return BernsteinHash(key->II->getName()); + return llvm::HashString(key->II->getName()); } static std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { - unsigned n = strlen(key->II->getName()) + 1; + unsigned n = key->II->getLength() + 1; ::Emit16(Out, n); return std::make_pair(n, sizeof(uint32_t)); } @@ -598,7 +600,7 @@ public: // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. key->FileOffset = Out.tell(); - Out.write(key->II->getName(), n); + Out.write(key->II->getNameStart(), n); } static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index bc45cc4..0e4f83f 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -53,7 +53,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, // Install a stat() listener to keep track of all of the stat() // calls. StatCalls = new MemorizeStatCalls; - PP.getFileManager().setStatCache(StatCalls); + PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true); } void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 822a5ba..25316be 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -369,6 +369,12 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", triple); + // Gentoo x86 2009.1 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); // Gentoo x86 2009.0 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", @@ -386,6 +392,11 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, "i486-pc-linux-gnu", "i486-pc-linux-gnu", triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", @@ -400,6 +411,8 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, AddPath("/usr/include/c++/4.2", System, true, false, false); break; case llvm::Triple::Solaris: + // Solaris - Fall though.. + case llvm::Triple::AuroraUX: // AuroraUX AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", "i386-pc-solaris2.11", diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 0f3b4b8..b1a0a5e 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -317,13 +317,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "_GNU_SOURCE=1"); } - // Filter out some microsoft extensions when trying to parse in ms-compat - // mode. if (LangOpts.Microsoft) { + // Filter out some microsoft extensions when trying to parse in ms-compat + // mode. DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__"); DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + // Work around some issues with Visual C++ headerws. + if (LangOpts.CPlusPlus) { + // Since we define wchar_t in C++ mode. + DefineBuiltinMacro(Buf, "_WCHAR_T_DEFINED=1"); + DefineBuiltinMacro(Buf, "_NATIVE_WCHAR_T_DEFINED=1"); + // FIXME: This should be temporary until we have a __pragma + // solution, to avoid some errors flagged in VC++ headers. + DefineBuiltinMacro(Buf, "_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=0"); + } } if (LangOpts.Optimize) @@ -365,8 +374,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf); DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf); DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf); - // FIXME: TargetInfo hookize __WINT_TYPE__. - DefineBuiltinMacro(Buf, "__WINT_TYPE__=int"); + DefineType("__WINT_TYPE__", TI.getWIntType(), Buf); DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat()); DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat()); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index e61668d..9c6059b 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -27,6 +28,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -335,8 +337,6 @@ void PCHValidator::ReadCounter(unsigned Value) { PP.setCounterValue(Value); } - - //===----------------------------------------------------------------------===// // PCH reader implementation //===----------------------------------------------------------------------===// @@ -345,7 +345,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot) : Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), - SemaObj(0), PP(&PP), Context(Context), Consumer(0), + SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -362,7 +362,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags, const char *isysroot) : SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), - SemaObj(0), PP(0), Context(0), Consumer(0), + SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -383,7 +383,7 @@ Expr *PCHReader::ReadDeclExpr() { } Expr *PCHReader::ReadTypeExpr() { - return dyn_cast_or_null<Expr>(ReadStmt(Stream)); + return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor)); } @@ -411,7 +411,7 @@ public: unsigned R = 5381; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + R = llvm::HashString(II->getName(), R); return R; } @@ -521,7 +521,7 @@ public: } static unsigned ComputeHash(const internal_key_type& a) { - return BernsteinHash(a.first, a.second); + return llvm::HashString(llvm::StringRef(a.first, a.second)); } // This hopefully will just get inlined and removed by the optimizer. @@ -731,7 +731,7 @@ class VISIBILITY_HIDDEN PCHStatLookupTrait { typedef PCHStatData data_type; static unsigned ComputeHash(const char *path) { - return BernsteinHash(path); + return llvm::HashString(path); } static internal_key_type GetInternalKey(const char *path) { return path; } @@ -794,7 +794,7 @@ public: // If we don't get a hit in the PCH file just forward to 'stat'. if (I == Cache->end()) { ++NumStatMisses; - return ::stat(path, buf); + return StatSysCallCache::stat(path, buf); } ++NumStatHits; @@ -1158,15 +1158,7 @@ PCHReader::ReadPCHBlock() { if (Code == llvm::bitc::ENTER_SUBBLOCK) { switch (Stream.ReadSubBlockID()) { - case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded) - default: // Skip unknown content. - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - break; - - case pch::DECLS_BLOCK_ID: + case pch::DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode // cursor to it, enter the block and read the abbrevs in that block. @@ -1174,7 +1166,7 @@ PCHReader::ReadPCHBlock() { DeclsCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor. // Read the abbrevs. - ReadBlockAbbrevs(DeclsCursor, pch::DECLS_BLOCK_ID)) { + ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { Error("malformed block record in PCH file"); return Failure; } @@ -1352,13 +1344,16 @@ PCHReader::ReadPCHBlock() { } break; - case pch::STAT_CACHE: - FileMgr.setStatCache( - new PCHStatCache((const unsigned char *)BlobStart + Record[0], - (const unsigned char *)BlobStart, - NumStatHits, NumStatMisses)); + case pch::STAT_CACHE: { + PCHStatCache *MyStatCache = + new PCHStatCache((const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + NumStatHits, NumStatMisses); + FileMgr.addStatCache(MyStatCache); + StatCache = MyStatCache; break; - + } + case pch::EXT_VECTOR_DECLS: if (!ExtVectorDecls.empty()) { Error("duplicate EXT_VECTOR_DECLS record in PCH file"); @@ -1466,7 +1461,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. - FileMgr.setStatCache(0); + if (StatCache) + FileMgr.removeStatCache((PCHStatCache*)StatCache); return IgnorePCH; } @@ -1509,7 +1505,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { IdentifierInfo *II = Identifiers[I]; // Look in the on-disk hash table for an entry for PCHIdentifierLookupTrait Info(*this, II); - std::pair<const char*, unsigned> Key(II->getName(), II->getLength()); + std::pair<const char*, unsigned> Key(II->getNameStart(), II->getLength()); PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); if (Pos == IdTable->end()) continue; @@ -1593,6 +1589,11 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { if (unsigned ObjCClassRedef = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) + Context->setBlockDescriptorType(GetType(String)); + if (unsigned String + = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) + Context->setBlockDescriptorExtendedType(GetType(String)); } /// \brief Retrieve the name of the original source file name @@ -1770,15 +1771,15 @@ void PCHReader::ReadComments(std::vector<SourceRange> &Comments) { QualType PCHReader::ReadTypeRecord(uint64_t Offset) { // Keep track of where we are in the stream, then jump back there // after reading this type. - SavedStreamPosition SavedPosition(Stream); + SavedStreamPosition SavedPosition(DeclsCursor); // Note that we are loading a type record. LoadingTypeOrDecl Loading(*this); - Stream.JumpToBit(Offset); + DeclsCursor.JumpToBit(Offset); RecordData Record; - unsigned Code = Stream.ReadCode(); - switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) { + unsigned Code = DeclsCursor.ReadCode(); + switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { case pch::TYPE_EXT_QUAL: { assert(Record.size() == 2 && "Incorrect encoding of extended qualifier type"); @@ -1839,30 +1840,6 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { ASM, IndexTypeQuals); } - case pch::TYPE_CONSTANT_ARRAY_WITH_EXPR: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]); - SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]); - unsigned Idx = 5; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayWithExprType(ElementType, - Size, ReadTypeExpr(), - ASM, IndexTypeQuals, - SourceRange(LBLoc, RBLoc)); - } - - case pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - unsigned Idx = 3; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayWithoutExprType(ElementType, Size, - ASM, IndexTypeQuals); - } - case pch::TYPE_INCOMPLETE_ARRAY: { QualType ElementType = GetType(Record[0]); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; @@ -1987,20 +1964,184 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos); } - case pch::TYPE_OBJC_PROTOCOL_LIST: { + case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { unsigned Idx = 0; - QualType OIT = GetType(Record[Idx++]); - unsigned NumProtos = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCProtocolListType(OIT, Protos.data(), NumProtos); + QualType Parm = GetType(Record[Idx++]); + QualType Replacement = GetType(Record[Idx++]); + return + Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + Replacement); } } // Suppress a GCC warning return QualType(); } +namespace { + +class TypeLocReader : public TypeLocVisitor<TypeLocReader> { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + +public: + TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx) + : Reader(Reader), Record(Record), Idx(Idx) { } + + // We want compile-time assurance that we've enumerated all of + // these, so unfortunately we have to declare them first, then + // define them out-of-line. +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitFunctionTypeLoc(FunctionTypeLoc); + void VisitArrayTypeLoc(ArrayTypeLoc); +}; + +} + +void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { + TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (Record[Idx++]) + TL.setSizeExpr(Reader.ReadDeclExpr()); + else + TL.setSizeExpr(0); +} +void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + } +} +void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setHasBaseTypeAsWritten(Record[Idx++]); + TL.setHasProtocolsAsWritten(Record[Idx++]); + if (TL.hasProtocolsAsWritten()) + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record, + unsigned &Idx) { + QualType InfoTy = GetType(Record[Idx++]); + if (InfoTy.isNull()) + return 0; + + DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy); + TypeLocReader TLR(*this, Record, Idx); + for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLR.Visit(TL); + return DInfo; +} QualType PCHReader::GetType(pch::TypeID ID) { unsigned FastQuals = ID & Qualifiers::FastMask; @@ -2374,7 +2515,10 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { // All of the strings in the PCH file are preceded by a 16-bit // length. Extract that 16-bit length to avoid having to execute // strlen(). - const char *StrLenPtr = Str - 2; + // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as + // unsigned integers. This is important to avoid integer overflow when + // we cast them to 'unsigned'. + const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; IdentifiersLoaded[ID - 1] diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b673256..d1cb461 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -18,7 +18,6 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/Expr.h" -#include "clang/AST/TypeLocVisitor.h" using namespace clang; @@ -86,6 +85,7 @@ void PCHDeclReader::VisitDecl(Decl *D) { D->setImplicit(Record[Idx++]); D->setUsed(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); + D->setPCHLevel(Record[Idx++] + 1); } void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { @@ -149,84 +149,11 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); } -namespace { - -class TypeLocReader : public TypeLocVisitor<TypeLocReader> { - PCHReader &Reader; - const PCHReader::RecordData &Record; - unsigned &Idx; - -public: - TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, - unsigned &Idx) - : Reader(Reader), Record(Record), Idx(Idx) { } - -#define ABSTRACT_TYPELOC(CLASS) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS(CLASS TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - } -}; - -} - -void TypeLocReader::VisitQualifiedLoc(QualifiedLoc TyLoc) { - // nothing to do -} -void TypeLocReader::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { - TyLoc.setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTypedefLoc(TypedefLoc TyLoc) { - TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { - TyLoc.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { - TyLoc.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i) - TyLoc.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitPointerLoc(PointerLoc TyLoc) { - TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitBlockPointerLoc(BlockPointerLoc TyLoc) { - TyLoc.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitMemberPointerLoc(MemberPointerLoc TyLoc) { - TyLoc.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitReferenceLoc(ReferenceLoc TyLoc) { - TyLoc.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitFunctionLoc(FunctionLoc TyLoc) { - TyLoc.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i) - TyLoc.setArg(i, cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); -} -void TypeLocReader::VisitArrayLoc(ArrayLoc TyLoc) { - TyLoc.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TyLoc.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - if (Record[Idx++]) - TyLoc.setSizeExpr(Reader.ReadDeclExpr()); -} - void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - QualType InfoTy = Reader.GetType(Record[Idx++]); - if (InfoTy.isNull()) - return; - - DeclaratorInfo *DInfo = Reader.getContext()->CreateDeclaratorInfo(InfoTy); - TypeLocReader TLR(Reader, Record, Idx); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLR.Visit(TL); - DD->setDeclaratorInfo(DInfo); + DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx); + if (DInfo) + DD->setDeclaratorInfo(DInfo); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 64a678e..fb48df3 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclContextInternals.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" @@ -30,6 +31,7 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" @@ -117,23 +119,6 @@ void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { Code = pch::TYPE_CONSTANT_ARRAY; } -void PCHTypeWriter -::VisitConstantArrayWithExprType(const ConstantArrayWithExprType *T) { - VisitArrayType(T); - Writer.AddSourceLocation(T->getLBracketLoc(), Record); - Writer.AddSourceLocation(T->getRBracketLoc(), Record); - Writer.AddAPInt(T->getSize(), Record); - Writer.AddStmt(T->getSizeExpr()); - Code = pch::TYPE_CONSTANT_ARRAY_WITH_EXPR; -} - -void PCHTypeWriter -::VisitConstantArrayWithoutExprType(const ConstantArrayWithoutExprType *T) { - VisitArrayType(T); - Writer.AddAPInt(T->getSize(), Record); - Code = pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR; -} - void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { VisitArrayType(T); Code = pch::TYPE_INCOMPLETE_ARRAY; @@ -225,6 +210,14 @@ void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { } void +PCHTypeWriter::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTypeRef(T->getReplacementType(), Record); + Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void PCHTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { // FIXME: Serialize this type (C++ only) @@ -255,13 +248,150 @@ PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Code = pch::TYPE_OBJC_OBJECT_POINTER; } -void PCHTypeWriter::VisitObjCProtocolListType(const ObjCProtocolListType *T) { - Writer.AddTypeRef(T->getBaseType(), Record); - Record.push_back(T->getNumProtocols()); - for (ObjCProtocolListType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); I != E; ++I) - Writer.AddDeclRef(*I, Record); - Code = pch::TYPE_OBJC_PROTOCOL_LIST; +namespace { + +class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + +public: + TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); + void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); +}; + +} + +void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getCaretLoc(), Record); +} +void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpLoc(), Record); +} +void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); +} +void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { + Writer.AddSourceLocation(TL.getLBracketLoc(), Record); + Writer.AddSourceLocation(TL.getRBracketLoc(), Record); + Record.push_back(TL.getSizeExpr() ? 1 : 0); + if (TL.getSizeExpr()) + Writer.AddStmt(TL.getSizeExpr()); +} +void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddDeclRef(TL.getArg(i), Record); +} +void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); +} +void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Record.push_back(TL.hasBaseTypeAsWritten()); + Record.push_back(TL.hasProtocolsAsWritten()); + if (TL.hasProtocolsAsWritten()) + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } //===----------------------------------------------------------------------===// @@ -411,8 +541,8 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_TOKEN); - // Types block. - BLOCK(TYPES_BLOCK); + // Decls and Types block. + BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); RECORD(TYPE_FIXED_WIDTH_INT); RECORD(TYPE_COMPLEX); @@ -435,12 +565,6 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); RECORD(TYPE_OBJC_OBJECT_POINTER); - RECORD(TYPE_OBJC_PROTOCOL_LIST); - // Statements and Exprs can occur in the Types block. - AddStmtsExprs(Stream, Record); - - // Decls block. - BLOCK(DECLS_BLOCK); RECORD(DECL_ATTR); RECORD(DECL_TRANSLATION_UNIT); RECORD(DECL_TYPEDEF); @@ -470,7 +594,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); RECORD(DECL_CONTEXT_VISIBLE); - // Statements and Exprs can occur in the Decls block. + // Statements and Exprs can occur in the Decls and Types block. AddStmtsExprs(Stream, Record); #undef RECORD #undef BLOCK @@ -662,7 +786,7 @@ public: typedef const data_type& data_type_ref; static unsigned ComputeHash(const char *path) { - return BernsteinHash(path); + return llvm::HashString(path); } std::pair<unsigned,unsigned> @@ -878,10 +1002,10 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, std::vector<uint32_t> SLocEntryOffsets; RecordData PreloadSLocs; SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1); - for (SourceManager::sloc_entry_iterator - SLoc = SourceMgr.sloc_entry_begin() + 1, - SLocEnd = SourceMgr.sloc_entry_end(); - SLoc != SLocEnd; ++SLoc) { + for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) { + // Get this source location entry. + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); + // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); @@ -956,9 +1080,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Compute the token length for this macro expansion. unsigned NextOffset = SourceMgr.getNextOffset(); - SourceManager::sloc_entry_iterator NextSLoc = SLoc; - if (++NextSLoc != SLocEnd) - NextOffset = NextSLoc->getOffset(); + if (I + 1 != N) + NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset(); Record.push_back(NextOffset - SLoc->getOffset() - 1); Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record); } @@ -1019,6 +1142,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. + // FIXME: Make sure that this sees macros defined in included PCH files. for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1152,22 +1276,6 @@ void PCHWriter::WriteType(QualType T) { FlushStmts(); } -/// \brief Write a block containing all of the types. -void PCHWriter::WriteTypesBlock(ASTContext &Context) { - // Enter the types block. - Stream.EnterSubblock(pch::TYPES_BLOCK_ID, 2); - - // Emit all of the types that need to be emitted (so far). - while (!TypesToEmit.empty()) { - QualType T = TypesToEmit.front(); - TypesToEmit.pop(); - WriteType(T); - } - - // Exit the types block - Stream.ExitBlock(); -} - //===----------------------------------------------------------------------===// // Declaration Serialization //===----------------------------------------------------------------------===// @@ -1266,7 +1374,7 @@ public: unsigned R = 5381; for (unsigned I = 0; I != N; ++I) if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + R = llvm::HashString(II->getName(), R); return R; } @@ -1475,13 +1583,13 @@ public: : Writer(Writer), PP(PP) { } static unsigned ComputeHash(const IdentifierInfo* II) { - return clang::BernsteinHash(II->getName()); + return llvm::HashString(II->getName()); } std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, pch::IdentID ID) { - unsigned KeyLen = strlen(II->getName()) + 1; + unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 if (isInterestingIdentifier(II)) { DataLen += 2; // 2 bytes for builtin ID, flags @@ -1506,7 +1614,7 @@ public: // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. Writer.SetIdentifierOffset(II, Out.tell()); - Out.write(II->getName(), KeyLen); + Out.write(II->getNameStart(), KeyLen); } void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, @@ -1810,7 +1918,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // The translation unit is the first declaration we'll emit. DeclIDs[Context.getTranslationUnitDecl()] = 1; - DeclsToEmit.push(Context.getTranslationUnitDecl()); + DeclTypesToEmit.push(Context.getTranslationUnitDecl()); // Make sure that we emit IdentifierInfos (and any attached // declarations) for builtins. @@ -1858,7 +1966,6 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (StatCalls && !isysroot) WriteStatCache(*StatCalls, isysroot); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - WritePreprocessor(PP); WriteComments(Context); // Write the record of special types. Record.clear(); @@ -1875,17 +1982,25 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddTypeRef(Context.getsigjmp_bufType(), Record); AddTypeRef(Context.ObjCIdRedefinitionType, Record); AddTypeRef(Context.ObjCClassRedefinitionType, Record); + AddTypeRef(Context.getRawBlockdescriptorType(), Record); + AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); Stream.EmitRecord(pch::SPECIAL_TYPES, Record); // Keep writing types and declarations until all types and // declarations have been written. - do { - if (!DeclsToEmit.empty()) - WriteDeclsBlock(Context); - if (!TypesToEmit.empty()) - WriteTypesBlock(Context); - } while (!(DeclsToEmit.empty() && TypesToEmit.empty())); - + Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3); + WriteDeclsBlockAbbrevs(); + while (!DeclTypesToEmit.empty()) { + DeclOrType DOT = DeclTypesToEmit.front(); + DeclTypesToEmit.pop(); + if (DOT.isType()) + WriteType(DOT.getType()); + else + WriteDecl(Context, DOT.getDecl()); + } + Stream.ExitBlock(); + + WritePreprocessor(PP); WriteMethodPool(SemaRef); WriteIdentifierTable(PP); @@ -1991,6 +2106,18 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { Record.push_back(SID); } +void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { + if (DInfo == 0) { + AddTypeRef(QualType(), Record); + return; + } + + AddTypeRef(DInfo->getType(), Record); + TypeLocWriter TLW(*this, Record); + for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLW.Visit(TL); +} + void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { if (T.isNull()) { Record.push_back(pch::PREDEF_TYPE_NULL_ID); @@ -2007,7 +2134,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { // Assign it a new ID. This is the only time we enqueue a // qualified type, and it has no CV qualifiers. ID = NextTypeID++; - TypesToEmit.push(T); + DeclTypesToEmit.push(T); } // Encode the type qualifiers in the type reference. @@ -2061,7 +2188,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { // We haven't seen this type before. Assign it a new ID and put it // into the queue of types to emit. ID = NextTypeID++; - TypesToEmit.push(T); + DeclTypesToEmit.push(T); } // Encode the type qualifiers in the type reference. @@ -2079,7 +2206,7 @@ void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { // We haven't seen this declaration before. Give it a new ID and // enqueue it in the list of declarations to emit. ID = DeclIDs.size(); - DeclsToEmit.push(const_cast<Decl *>(D)); + DeclTypesToEmit.push(const_cast<Decl *>(D)); } Record.push_back(ID); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index ef7c5ec..fbd9929 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -14,7 +14,6 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" -#include "clang/AST/TypeLocVisitor.h" #include "llvm/Bitcode/BitstreamWriter.h" #include <cstdio> @@ -88,6 +87,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isImplicit()); Record.push_back(D->isUsed()); Record.push_back(D->getAccess()); + Record.push_back(D->getPCHLevel()); } void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { @@ -149,84 +149,10 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { Writer.AddAPSInt(D->getInitVal(), Record); Code = pch::DECL_ENUM_CONSTANT; } -namespace { - -class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { - PCHWriter &Writer; - PCHWriter::RecordData &Record; - -public: - TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) - : Writer(Writer), Record(Record) { } - -#define ABSTRACT_TYPELOC(CLASS) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS(CLASS TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitTypeLoc(TypeLoc TyLoc) { - assert(0 && "A type loc wrapper was not handled!"); - } -}; - -} - -void TypeLocWriter::VisitQualifiedLoc(QualifiedLoc TyLoc) { - // nothing to do here -} -void TypeLocWriter::VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStartLoc(), Record); -} -void TypeLocWriter::VisitTypedefLoc(TypedefLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getNameLoc(), Record); -} -void TypeLocWriter::VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getNameLoc(), Record); -} -void TypeLocWriter::VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLAngleLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRAngleLoc(), Record); - for (unsigned i = 0, e = TyLoc.getNumProtocols(); i != e; ++i) - Writer.AddSourceLocation(TyLoc.getProtocolLoc(i), Record); -} -void TypeLocWriter::VisitPointerLoc(PointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStarLoc(), Record); -} -void TypeLocWriter::VisitBlockPointerLoc(BlockPointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getCaretLoc(), Record); -} -void TypeLocWriter::VisitMemberPointerLoc(MemberPointerLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getStarLoc(), Record); -} -void TypeLocWriter::VisitReferenceLoc(ReferenceLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getAmpLoc(), Record); -} -void TypeLocWriter::VisitFunctionLoc(FunctionLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLParenLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRParenLoc(), Record); - for (unsigned i = 0, e = TyLoc.getNumArgs(); i != e; ++i) - Writer.AddDeclRef(TyLoc.getArg(i), Record); -} -void TypeLocWriter::VisitArrayLoc(ArrayLoc TyLoc) { - Writer.AddSourceLocation(TyLoc.getLBracketLoc(), Record); - Writer.AddSourceLocation(TyLoc.getRBracketLoc(), Record); - Record.push_back(TyLoc.getSizeExpr() ? 1 : 0); - if (TyLoc.getSizeExpr()) - Writer.AddStmt(TyLoc.getSizeExpr()); -} void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); - DeclaratorInfo *DInfo = D->getDeclaratorInfo(); - if (DInfo == 0) { - Writer.AddTypeRef(QualType(), Record); - return; - } - - Writer.AddTypeRef(DInfo->getTypeLoc().getSourceType(), Record); - TypeLocWriter TLW(Writer, Record); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLW.Visit(TL); + Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record); } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -448,6 +374,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { !D->isImplicit() && !D->isUsed() && D->getAccess() == AS_none && + D->getPCHLevel() == 0 && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? D->getObjCDeclQualifier() == 0) @@ -523,6 +450,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -607,80 +535,64 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context) { } } -/// \brief Write a block containing all of the declarations. -void PCHWriter::WriteDeclsBlock(ASTContext &Context) { - // Enter the declarations block. - Stream.EnterSubblock(pch::DECLS_BLOCK_ID, 3); - - // Output the abbreviations that we will use in this block. - WriteDeclsBlockAbbrevs(); - - // Emit all of the declarations. +void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { RecordData Record; PCHDeclWriter W(*this, Context, Record); - while (!DeclsToEmit.empty()) { - // Pull the next declaration off the queue - Decl *D = DeclsToEmit.front(); - DeclsToEmit.pop(); - - // If this declaration is also a DeclContext, write blocks for the - // declarations that lexically stored inside its context and those - // declarations that are visible from its context. These blocks - // are written before the declaration itself so that we can put - // their offsets into the record for the declaration. - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - DeclContext *DC = dyn_cast<DeclContext>(D); - if (DC) { - LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); - VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); - } - // Determine the ID for this declaration - pch::DeclID &ID = DeclIDs[D]; - if (ID == 0) - ID = DeclIDs.size(); + // If this declaration is also a DeclContext, write blocks for the + // declarations that lexically stored inside its context and those + // declarations that are visible from its context. These blocks + // are written before the declaration itself so that we can put + // their offsets into the record for the declaration. + uint64_t LexicalOffset = 0; + uint64_t VisibleOffset = 0; + DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) { + LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); + VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); + } - unsigned Index = ID - 1; + // Determine the ID for this declaration + pch::DeclID &ID = DeclIDs[D]; + if (ID == 0) + ID = DeclIDs.size(); - // Record the offset for this declaration - if (DeclOffsets.size() == Index) - DeclOffsets.push_back(Stream.GetCurrentBitNo()); - else if (DeclOffsets.size() < Index) { - DeclOffsets.resize(Index+1); - DeclOffsets[Index] = Stream.GetCurrentBitNo(); - } + unsigned Index = ID - 1; - // Build and emit a record for this declaration - Record.clear(); - W.Code = (pch::DeclCode)0; - W.AbbrevToUse = 0; - W.Visit(D); - if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - - if (!W.Code) { - fprintf(stderr, "Cannot serialize declaration of kind %s\n", - D->getDeclKindName()); - assert(false && "Unhandled declaration kind while generating PCH"); - exit(-1); - } - Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); + // Record the offset for this declaration + if (DeclOffsets.size() == Index) + DeclOffsets.push_back(Stream.GetCurrentBitNo()); + else if (DeclOffsets.size() < Index) { + DeclOffsets.resize(Index+1); + DeclOffsets[Index] = Stream.GetCurrentBitNo(); + } - // If the declaration had any attributes, write them now. - if (D->hasAttrs()) - WriteAttributeRecord(D->getAttrs()); + // Build and emit a record for this declaration + Record.clear(); + W.Code = (pch::DeclCode)0; + W.AbbrevToUse = 0; + W.Visit(D); + if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); + + if (!W.Code) { + fprintf(stderr, "Cannot serialize declaration of kind %s\n", + D->getDeclKindName()); + assert(false && "Unhandled declaration kind while generating PCH"); + exit(-1); + } + Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); - // Flush any expressions that were written as part of this declaration. - FlushStmts(); + // If the declaration had any attributes, write them now. + if (D->hasAttrs()) + WriteAttributeRecord(D->getAttrs()); - // Note "external" declarations so that we can add them to a record in the - // PCH file later. - // - // FIXME: This should be renamed, the predicate is much more complicated. - if (isRequiredDecl(D, Context)) - ExternalDefinitions.push_back(ID); - } + // Flush any expressions that were written as part of this declaration. + FlushStmts(); - // Exit the declarations block - Stream.ExitBlock(); + // Note "external" declarations so that we can add them to a record in the + // PCH file later. + // + // FIXME: This should be renamed, the predicate is much more complicated. + if (isRequiredDecl(D, Context)) + ExternalDefinitions.push_back(Index + 1); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 492b31a..f3cb206 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -399,7 +399,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } if (IdentifierInfo *II = Tok.getIdentifierInfo()) { - OS.write(II->getName(), II->getLength()); + OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && Tok.getLiteralData()) { OS.write(Tok.getLiteralData(), Tok.getLength()); @@ -434,7 +434,7 @@ namespace { struct SortMacrosByID { typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const { - return strcmp(LHS.first->getName(), RHS.first->getName()) < 0; + return LHS.first->getName() < RHS.first->getName(); } }; } diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index d92f5c7..b5d59c0 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -128,13 +128,13 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { // comment the line out. if (RawTokens[CurRawTok].is(tok::identifier)) { const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); - if (!strcmp(II->getName(), "warning")) { + if (II->getName() == "warning") { // Comment out #warning. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } else if (!strcmp(II->getName(), "pragma") && + } else if (II->getName() == "pragma" && RawTokens[CurRawTok+1].is(tok::identifier) && - !strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(), - "mark")){ + (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == + "mark")) { // Comment out #pragma mark. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 55ab78e..0ea0a58 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -675,7 +675,7 @@ static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl, S = "((struct "; S += ClassDecl->getIdentifier()->getName(); S += "_IMPL *)self)->"; - S += OID->getNameAsCString(); + S += OID->getName(); return S; } @@ -2265,7 +2265,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { if (clsName) { // class message. // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle // the 'super' idiom within a class method. - if (!strcmp(clsName->getName(), "super")) { + if (clsName->getName() == "super") { MsgSendFlavor = MsgSendSuperFunctionDecl; if (MsgSendStretFlavor) MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; @@ -2289,9 +2289,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + SuperDecl->getIdentifier()->getNameStart(), + SuperDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], ClsExprs.size()); @@ -2343,7 +2343,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), + clsName->getNameStart(), clsName->getLength(), false, argType, SourceLocation())); @@ -2375,9 +2375,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getName(), - SuperDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + SuperDecl->getIdentifier()->getNameStart(), + SuperDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size()); diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 63d9a50..14769c1 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -214,6 +214,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine, // Move the end of the interesting region right until we've // pulled in something else interesting. if (CaretEnd != SourceLength) { + assert(CaretEnd < SourceLength && "Unexpected caret position!"); unsigned NewEnd = CaretEnd; // Skip over any whitespace we see here; we're looking for @@ -320,6 +321,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') ++LineEnd; + // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past + // the source line length as currently being computed. See + // test/Misc/message-length.c. + CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp index 6294d69..c24f3bf 100644 --- a/lib/Index/ASTLocation.cpp +++ b/lib/Index/ASTLocation.cpp @@ -101,7 +101,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { break; case N_Type: { - QualType T = AsTypeLoc().getSourceType(); + QualType T = AsTypeLoc().getType(); OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString(); } } diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h index e18aa57..0ae78fb 100644 --- a/lib/Index/ASTVisitor.h +++ b/lib/Index/ASTVisitor.h @@ -123,14 +123,14 @@ public: BaseTypeLocVisitor::Visit(TL); } - void VisitArrayLoc(ArrayLoc TL) { - BaseTypeLocVisitor::VisitArrayLoc(TL); + void VisitArrayLoc(ArrayTypeLoc TL) { + BaseTypeLocVisitor::VisitArrayTypeLoc(TL); if (TL.getSizeExpr()) Visit(TL.getSizeExpr()); } - void VisitFunctionLoc(FunctionLoc TL) { - BaseTypeLocVisitor::VisitFunctionLoc(TL); + void VisitFunctionTypeLoc(FunctionTypeLoc TL) { + BaseTypeLocVisitor::VisitFunctionTypeLoc(TL); for (unsigned i = 0; i != TL.getNumArgs(); ++i) Visit(TL.getArg(i)); } diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp index 0e48a36..366cf1b 100644 --- a/lib/Index/DeclReferenceMap.cpp +++ b/lib/Index/DeclReferenceMap.cpp @@ -31,8 +31,8 @@ public: void VisitMemberExpr(MemberExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - void VisitTypedefLoc(TypedefLoc TL); - void VisitObjCInterfaceLoc(ObjCInterfaceLoc TL); + void VisitTypedefTypeLoc(TypedefTypeLoc TL); + void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); }; } // anonymous namespace @@ -55,12 +55,12 @@ void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { Map.insert(std::make_pair(Node->getDecl(), ASTLocation(CurrentDecl, Node))); } -void RefMapper::VisitTypedefLoc(TypedefLoc TL) { +void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) { NamedDecl *ND = TL.getTypedefDecl(); Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); } -void RefMapper::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) { +void RefMapper::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { NamedDecl *ND = TL.getIFaceDecl(); Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); } diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp index 77d7a84..03fe9f7 100644 --- a/lib/Index/Entity.cpp +++ b/lib/Index/Entity.cpp @@ -72,7 +72,8 @@ Entity EntityGetter::VisitNamedDecl(NamedDecl *D) { if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) { IdentifierInfo *GlobII = - &ProgImpl.getIdents().get(II->getName(), II->getName() + II->getLength()); + &ProgImpl.getIdents().get(II->getNameStart(), + II->getNameStart() + II->getLength()); GlobName = DeclarationName(GlobII); } else { Selector LocalSel = LocalName.getObjCSelector(); @@ -139,8 +140,9 @@ Decl *EntityImpl::getDecl(ASTContext &AST) { DeclarationName LocalName; if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) { - IdentifierInfo &II = AST.Idents.get(GlobII->getName(), - GlobII->getName() + GlobII->getLength()); + IdentifierInfo &II = + AST.Idents.get(GlobII->getNameStart(), + GlobII->getNameStart() + GlobII->getLength()); LocalName = DeclarationName(&II); } else { Selector GlobSel = Name.getObjCSelector(); diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp index f3ec41d..2b2ca6d 100644 --- a/lib/Index/GlobalSelector.cpp +++ b/lib/Index/GlobalSelector.cpp @@ -29,8 +29,9 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const { for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); i != e; ++i) { IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); - IdentifierInfo *II = &AST.Idents.get(GlobII->getName(), - GlobII->getName() + GlobII->getLength()); + IdentifierInfo *II = + &AST.Idents.get(GlobII->getNameStart(), + GlobII->getNameStart() + GlobII->getLength()); Ids.push_back(II); } @@ -57,8 +58,9 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); i != e; ++i) { IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); - IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(), - II->getName() + II->getLength()); + IdentifierInfo *GlobII = + &ProgImpl.getIdents().get(II->getNameStart(), + II->getNameStart() + II->getLength()); Ids.push_back(GlobII); } diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 229669d..8edd634 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -120,11 +120,12 @@ public: TypeLocResolver(ASTContext &ctx, SourceLocation loc, Decl *pd) : LocResolverBase(ctx, loc), ParentDecl(pd) { } - ASTLocation VisitTypedefLoc(TypedefLoc TL); - ASTLocation VisitFunctionLoc(FunctionLoc TL); - ASTLocation VisitArrayLoc(ArrayLoc TL); - ASTLocation VisitObjCInterfaceLoc(ObjCInterfaceLoc TL); - ASTLocation VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); + ASTLocation VisitBuiltinTypeLoc(BuiltinTypeLoc TL); + ASTLocation VisitTypedefTypeLoc(TypedefTypeLoc TL); + ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL); + ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL); + ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + ASTLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); ASTLocation VisitTypeLoc(TypeLoc TL); }; @@ -349,7 +350,25 @@ ASTLocation DeclLocResolver::VisitDecl(Decl *D) { return ASTLocation(D); } -ASTLocation TypeLocResolver::VisitTypedefLoc(TypedefLoc TL) { +ASTLocation TypeLocResolver::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // Continue the 'id' magic by making the builtin type (which cannot + // actually be spelled) map to the typedef. + BuiltinType *T = TL.getTypePtr(); + if (T->getKind() == BuiltinType::ObjCId) { + TypedefDecl *D = Ctx.getObjCIdType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + // Same thing with 'Class'. + if (T->getKind() == BuiltinType::ObjCClass) { + TypedefDecl *D = Ctx.getObjCClassType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitTypedefTypeLoc(TypedefTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); if (ContainsLocation(TL.getNameLoc())) @@ -357,7 +376,7 @@ ASTLocation TypeLocResolver::VisitTypedefLoc(TypedefLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitFunctionLoc(FunctionLoc TL) { +ASTLocation TypeLocResolver::VisitFunctionTypeLoc(FunctionTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -373,7 +392,7 @@ ASTLocation TypeLocResolver::VisitFunctionLoc(FunctionLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitArrayLoc(ArrayLoc TL) { +ASTLocation TypeLocResolver::VisitArrayTypeLoc(ArrayTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -384,17 +403,11 @@ ASTLocation TypeLocResolver::VisitArrayLoc(ArrayLoc TL) { return ASTLocation(ParentDecl, TL); } -ASTLocation TypeLocResolver::VisitObjCInterfaceLoc(ObjCInterfaceLoc TL) { +ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); if (ContainsLocation(TL.getNameLoc())) return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc()); - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { SourceLocation L = TL.getProtocolLoc(i); @@ -408,6 +421,24 @@ ASTLocation TypeLocResolver::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { return ASTLocation(ParentDecl, TL); } +ASTLocation TypeLocResolver::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + + if (TL.hasProtocolsAsWritten()) { + for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { + SourceLocation L = TL.getProtocolLoc(i); + RangePos RP = CheckRange(L); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return ASTLocation(ParentDecl, TL.getProtocol(i), L); + } + } + + return ASTLocation(ParentDecl, TL); +} + ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { assert(ContainsLocation(TL) && "Should visit only after verifying that loc is in range"); @@ -497,9 +528,12 @@ void LocResolverBase::print(Stmt *Node) { /// \brief Returns the AST node that a source location points to. /// -ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) { +ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, + Decl *RelativeToDecl) { if (Loc.isInvalid()) return ASTLocation(); + if (RelativeToDecl) + return DeclLocResolver(Ctx, Loc).Visit(RelativeToDecl); return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 196a77f..e264efa 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1071,7 +1071,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // we allow macros that expand to nothing after the filename, because this // falls into the category of "#include pp-tokens new-line" specified in // C99 6.10.2p4. - CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getName(), true); + CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getNameStart(), true); // Check that we don't have infinite #include recursion. if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) { diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index 36ace8b..f17a5d9 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -20,8 +20,9 @@ #include "clang/Lex/PTHManager.h" #include "clang/Lex/Token.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/MemoryBuffer.h" #include <sys/stat.h> using namespace clang; @@ -95,14 +96,6 @@ LexNextToken: //===--------------------------------------==// // Process the token. //===--------------------------------------==// -#if 0 - SourceManager& SM = PP->getSourceManager(); - llvm::errs() << SM.getFileEntryForID(FileID)->getName() - << ':' << SM.getLogicalLineNumber(Tok.getLocation()) - << ':' << SM.getLogicalColumnNumber(Tok.getLocation()) - << '\n'; -#endif - if (TKind == tok::eof) { // Save the end-of-file token. EofToken = Tok; @@ -308,7 +301,7 @@ public: typedef std::pair<unsigned char, const char*> internal_key_type; static unsigned ComputeHash(internal_key_type x) { - return BernsteinHash(x.second); + return llvm::HashString(x.second); } static std::pair<unsigned, unsigned> @@ -363,7 +356,7 @@ public: } static unsigned ComputeHash(const internal_key_type& a) { - return BernsteinHash(a.first, a.second); + return llvm::HashString(llvm::StringRef(a.first, a.second)); } // This hopefully will just get inlined and removed by the optimizer. @@ -562,7 +555,7 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { // Store the new IdentifierInfo in the cache. PerIDCache[PersistentID] = II; - assert(II->getName() && II->getName()[0] != '\0'); + assert(II->getNameStart() && II->getNameStart()[0] != '\0'); return II; } @@ -679,7 +672,8 @@ public: CacheTy::iterator I = Cache.find(path); // If we don't get a hit in the PTH file just forward to 'stat'. - if (I == Cache.end()) return ::stat(path, buf); + if (I == Cache.end()) + return StatSysCallCache::stat(path, buf); const PTHStatData& Data = *I; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index bfa090a..7f3afc6 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -122,7 +122,7 @@ Preprocessor::~Preprocessor() { void Preprocessor::setPTHManager(PTHManager* pm) { PTH.reset(pm); - FileMgr.setStatCache(PTH->createStatCache()); + FileMgr.addStatCache(PTH->createStatCache()); } void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { @@ -234,7 +234,7 @@ unsigned Preprocessor::getSpelling(const Token &Tok, // If this token is an identifier, just return the string from the identifier // table, which is very quick. if (const IdentifierInfo *II = Tok.getIdentifierInfo()) { - Buffer = II->getName(); + Buffer = II->getNameStart(); return II->getLength(); } diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp index ade7f85..0795164 100644 --- a/lib/Lex/TokenConcatenation.cpp +++ b/lib/Lex/TokenConcatenation.cpp @@ -95,7 +95,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { static char GetFirstChar(Preprocessor &PP, const Token &Tok) { if (IdentifierInfo *II = Tok.getIdentifierInfo()) { // Avoid spelling identifiers, the most common form of token. - return II->getName()[0]; + return II->getNameStart()[0]; } else if (!Tok.needsCleaning()) { if (Tok.isLiteral() && Tok.getLiteralData()) { return *Tok.getLiteralData(); diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 2ee41bc..224a31c 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -45,18 +45,15 @@ AttributeList::~AttributeList() { } AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - const char *Str = Name->getName(); - unsigned Len = Name->getLength(); + llvm::StringRef AttrName = Name->getName(); // Normalize the attribute name, __foo__ becomes foo. - if (Len > 4 && Str[0] == '_' && Str[1] == '_' && - Str[Len - 2] == '_' && Str[Len - 1] == '_') { - Str += 2; - Len -= 4; - } + if (AttrName.startswith("__") && AttrName.endswith("__")) + AttrName = AttrName.substr(2, AttrName.size() - 4); // FIXME: Hand generating this is neither smart nor efficient. - switch (Len) { + const char *Str = AttrName.data(); + switch (AttrName.size()) { case 4: if (!memcmp(Str, "weak", 4)) return AT_weak; if (!memcmp(Str, "pure", 4)) return AT_pure; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 72e30e3..8be89a8 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -972,13 +972,41 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { return ExprError(); } - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getLocation(), - Tok.getIdentifierInfo(), - SS, - NextToken().is(tok::l_paren)); + if (NextToken().is(tok::less)) { + // class-name: + // ~ simple-template-id + TemplateTy Template + = Actions.ActOnDependentTemplateName(SourceLocation(), + *Tok.getIdentifierInfo(), + Tok.getLocation(), + SS, + ObjectType); + if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS, + SourceLocation(), true)) + return ExprError(); + + assert(Tok.is(tok::annot_typename) && + "AnnotateTemplateIdToken didn't work?"); + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getAnnotationRange(), + Tok.getAnnotationValue(), + SS, + NextToken().is(tok::l_paren)); + } else { + // class-name: + // ~ identifier + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getLocation(), + Tok.getIdentifierInfo(), + SS, + NextToken().is(tok::l_paren)); + } + + // Consume the identifier or template-id token. ConsumeToken(); } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { // We have a reference to a member operator, e.g., t.operator int or diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 325f085..fa65156 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -356,7 +356,8 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { TemplateId->NumArgs); OwningExprResult Result - = Actions.ActOnTemplateIdExpr(TemplateTy::make(TemplateId->Template), + = Actions.ActOnTemplateIdExpr(SS, + TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 6ab23fd..c4e79ca 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -65,9 +66,9 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { if (Tok.is(tok::identifier)) { const IdentifierInfo *FieldName = Tok.getIdentifierInfo(); - std::string NewSyntax("."); - NewSyntax += FieldName->getName(); - NewSyntax += " = "; + llvm::SmallString<256> NewSyntax; + llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName() + << " = "; SourceLocation NameLoc = ConsumeToken(); // Eat the identifier. @@ -77,7 +78,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { Diag(Tok, diag::ext_gnu_old_style_field_designator) << CodeModificationHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), - NewSyntax); + NewSyntax.str()); Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 1d29f31..2e0cd6d 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -428,7 +428,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { return; } - if (II->getName()[0] == 's') { + if (II->getNameStart()[0] == 's') { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); DS.setSetterName(Tok.getIdentifierInfo()); ConsumeToken(); // consume method name @@ -1371,8 +1371,11 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { "parsing Objective-C method"); // parse optional ';' - if (Tok.is(tok::semi)) + if (Tok.is(tok::semi)) { + if (ObjCImpDecl) + Diag(Tok, diag::warn_semicolon_before_method_nody); ConsumeToken(); + } // We should have an opening brace now. if (Tok.isNot(tok::l_brace)) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 907ca80..272be2f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1256,6 +1256,8 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { /// asm-string-literal '(' expression ')' /// '[' identifier ']' asm-string-literal '(' expression ')' /// +// +// FIXME: Avoid unnecessary std::string trashing. bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, llvm::SmallVectorImpl<ExprTy*> &Constraints, llvm::SmallVectorImpl<ExprTy*> &Exprs) { @@ -1281,7 +1283,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, IdentifierInfo *II = Tok.getIdentifierInfo(); ConsumeToken(); - Names.push_back(std::string(II->getName(), II->getLength())); + Names.push_back(II->getName()); MatchRHSPunctuation(tok::r_square, Loc); } else Names.push_back(std::string()); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 2f500a4..bc737e9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -77,7 +77,10 @@ void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const { const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); - OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; + if (Tok.isAnnotation()) + OS << ": at annotation token \n"; + else + OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; } diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp index 30bbcfa..fdb6fc3 100644 --- a/lib/Rewrite/RewriteRope.cpp +++ b/lib/Rewrite/RewriteRope.cpp @@ -154,6 +154,7 @@ namespace { ~RopePieceBTreeLeaf() { if (PrevLeaf || NextLeaf) removeFromLeafInOrder(); + clear(); } bool isFull() const { return NumPieces == 2*WidthFactor; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index ba05a07..fc9c14f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -23,44 +23,134 @@ #include "clang/Basic/TargetInfo.h" using namespace clang; +/// Determines whether we should have an a.k.a. clause when +/// pretty-printing a type. There are three main criteria: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +/// 3) Some types may have already been desugared previously in this diagnostic. +/// if this is the case, doing another "aka" would just be clutter. +/// +static bool ShouldAKA(ASTContext &Context, QualType QT, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + QualType &DesugaredQT) { + QualType InputTy = QT; + + bool AKA = false; + QualifierCollector Qc; + + while (true) { + const Type *Ty = Qc.strip(QT); + + // Don't aka just because we saw an elaborated type... + if (isa<ElaboratedType>(Ty)) { + QT = cast<ElaboratedType>(Ty)->desugar(); + continue; + } + + // ...or a qualified name type... + if (isa<QualifiedNameType>(Ty)) { + QT = cast<QualifiedNameType>(Ty)->desugar(); + continue; + } + + // ...or a substituted template type parameter. + if (isa<SubstTemplateTypeParmType>(Ty)) { + QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); + continue; + } + + // Don't desugar template specializations. + if (isa<TemplateSpecializationType>(Ty)) + break; + + // Don't desugar magic Objective-C types. + if (QualType(Ty,0) == Context.getObjCIdType() || + QualType(Ty,0) == Context.getObjCClassType() || + QualType(Ty,0) == Context.getObjCSelType() || + QualType(Ty,0) == Context.getObjCProtoType()) + break; + + // Don't desugar va_list. + if (QualType(Ty,0) == Context.getBuiltinVaListType()) + break; + + // Otherwise, do a single-step desugar. + QualType Underlying; + bool IsSugar = false; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + case Type::Class: { \ + const Class##Type *CTy = cast<Class##Type>(Ty); \ + if (CTy->isSugared()) { \ + IsSugar = true; \ + Underlying = CTy->desugar(); \ + } \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + + // If it wasn't sugared, we're done. + if (!IsSugar) + break; + + // If the desugared type is a vector type, we don't want to expand + // it, it will turn into an attribute mess. People want their "vec4". + if (isa<VectorType>(Underlying)) + break; + + // Otherwise, we're tearing through something opaque; note that + // we'll eventually need an a.k.a. clause and keep going. + AKA = true; + QT = Underlying; + continue; + } + + // If we never tore through opaque sugar, don't print aka. + if (!AKA) return false; + + // If we did, check to see if we already desugared this type in this + // diagnostic. If so, don't do it again. + for (unsigned i = 0; i != NumPrevArgs; ++i) { + // TODO: Handle ak_declcontext case. + if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + void *Ptr = (void*)PrevArgs[i].second; + QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); + if (PrevTy == InputTy) + return false; + } + } + + DesugaredQT = Qc.apply(QT); + return true; +} + /// \brief Convert the given type to a string suitable for printing as part of /// a diagnostic. /// /// \param Context the context in which the type was allocated /// \param Ty the type to print -static std::string ConvertTypeToDiagnosticString(ASTContext &Context, - QualType Ty) { +static std::string +ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs) { // FIXME: Playing with std::string is really slow. std::string S = Ty.getAsString(Context.PrintingPolicy); - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty.getDesugaredType(); - - if (Ty != DesugaredTy && - // If the desugared type is a vector type, we don't want to expand it, - // it will turn into an attribute mess. People want their "vec4". - !isa<VectorType>(DesugaredTy) && - - // Don't aka just because we saw an elaborated type... - (!isa<ElaboratedType>(Ty) || - cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && - - // ...or a qualified name type... - (!isa<QualifiedNameType>(Ty) || - cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && - - // ...or a non-dependent template specialization. - (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + // Consider producing an a.k.a. clause if removing all the direct + // sugar gives us something "significantly different". + + QualType DesugaredTy; + if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) { S = "'"+S+"' (aka '"; S += DesugaredTy.getAsString(Context.PrintingPolicy); S += "')"; @@ -76,21 +166,27 @@ static std::string ConvertTypeToDiagnosticString(ASTContext &Context, static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl<char> &Output, void *Cookie) { ASTContext &Context = *static_cast<ASTContext*>(Cookie); std::string S; bool NeedQuotes = true; - if (Kind == Diagnostic::ak_qualtype) { + + switch (Kind) { + default: assert(0 && "unknown ArgumentKind"); + case Diagnostic::ak_qualtype: { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); - S = ConvertTypeToDiagnosticString(Context, Ty); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); NeedQuotes = false; - } else if (Kind == Diagnostic::ak_declarationname) { - + break; + } + case Diagnostic::ak_declarationname: { DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); S = N.getAsString(); @@ -101,7 +197,9 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - } else if (Kind == Diagnostic::ak_nameddecl) { + break; + } + case Diagnostic::ak_nameddecl: { bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) Qualified = true; @@ -110,30 +208,30 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, "Invalid modifier for NamedDecl* argument"); Qualified = false; } - reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S, - Context.PrintingPolicy, - Qualified); - } else if (Kind == Diagnostic::ak_nestednamespec) { + reinterpret_cast<NamedDecl*>(Val)-> + getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); + break; + } + case Diagnostic::ak_nestednamespec: { llvm::raw_string_ostream OS(S); - reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS, - Context.PrintingPolicy); + reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, + Context.PrintingPolicy); NeedQuotes = false; - } else { - assert(Kind == Diagnostic::ak_declcontext); + break; + } + case Diagnostic::ak_declcontext: { DeclContext *DC = reinterpret_cast<DeclContext *> (Val); - NeedQuotes = false; - if (!DC) { - assert(false && "Should never have a null declaration context"); - S = "unknown context"; - } else if (DC->isTranslationUnit()) { + assert(DC && "Should never have a null declaration context"); + + if (DC->isTranslationUnit()) { // FIXME: Get these strings from some localized place if (Context.getLangOptions().CPlusPlus) S = "the global namespace"; else S = "the global scope"; } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { - S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type)); - NeedQuotes = false; + S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs); } else { // FIXME: Get these strings from some localized place NamedDecl *ND = cast<NamedDecl>(DC); @@ -147,8 +245,10 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, S += "'"; ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); S += "'"; - NeedQuotes = false; } + NeedQuotes = false; + break; + } } if (NeedQuotes) @@ -361,9 +461,8 @@ void Sema::ActOnEndOfTranslationUnit() { // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); - QualType T - = Context.getConstantArrayWithoutExprType(ArrayT->getElementType(), - One, ArrayType::Normal, 0); + QualType T = Context.getConstantArrayType(ArrayT->getElementType(), + One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 80f3663..6dd081b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -448,7 +448,7 @@ public: // QualType adjustParameterType(QualType T); QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &IsInvalid, QualType &SourceTy); + bool &IsInvalid); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); @@ -908,6 +908,7 @@ public: bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, @@ -929,7 +930,7 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); - void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); void AddOverloadedCallCandidates(NamedDecl *Callee, DeclarationName &UnqualifiedName, @@ -2108,6 +2109,15 @@ public: bool HasTrailingLParen); virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *Type, + const CXXScopeSpec &SS, + bool HasTrailingLParen); + + virtual OwningExprResult ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -2343,6 +2353,10 @@ public: FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); + bool isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, + SourceLocation NameLoc, QualType &ThisType, + QualType &MemberType); + //===--------------------------------------------------------------------===// // C++ Derived Classes // @@ -2515,14 +2529,17 @@ public: DeclSpec::TST TagSpec, SourceLocation TagLoc); - OwningExprResult BuildTemplateIdExpr(TemplateName Template, + OwningExprResult BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - virtual OwningExprResult ActOnTemplateIdExpr(TemplateTy Template, + virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, @@ -3143,6 +3160,10 @@ public: void PerformPendingImplicitInstantiations(); + DeclaratorInfo *SubstType(DeclaratorInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); @@ -3197,11 +3218,13 @@ public: void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, @@ -3404,8 +3427,7 @@ public: /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. - void ImpCastExprToType(Expr *&Expr, QualType Type, - CastExpr::CastKind Kind = CastExpr::CK_Unknown, + void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind, bool isLvalue = false); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts @@ -3550,6 +3572,10 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, const char *Flavor); + + bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, + const ImplicitConversionSequence& ICS, + const char *Flavor); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -3659,14 +3685,16 @@ public: // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid - bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastExpr::CastKind &Kind); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns true if the cast is invalid - bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + bool CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *&CastExpr, + CastExpr::CastKind &Kind); /// CXXCheckCStyleCast - Check constraints of a C-style or function-style /// cast under C++ semantics. @@ -3727,22 +3755,6 @@ public: QualType FieldTy, const Expr *BitWidth, bool *ZeroWidth = 0); - /// adjustFunctionParamType - Converts the type of a function parameter to a - // type that can be passed as an argument type to - /// ASTContext::getFunctionType. - /// - /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is - /// deleted. Such cv-qualifiers affect only the definition of the parameter - /// within the body of the function; they do not affect the function type. - QualType adjustFunctionParamType(QualType T) const { - if (!Context.getLangOptions().CPlusPlus) - return T; - return - T->isDependentType() ? T.getUnqualifiedType() - : T.getDesugaredType().getUnqualifiedType(); - - } - /// \name Code completion //@{ void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 69d1f92..bf39604 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -175,7 +175,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by /// the cast checkers. Both arguments must denote pointer (possibly to member) /// types. -bool +static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // Casting away constness is defined in C++ 5.2.11p8 with reference to // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since @@ -605,6 +605,11 @@ TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg) { + // We can only work with complete types. But don't complain if it doesn't work + if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) || + Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0))) + return TC_NotApplicable; + // Downcast can only happen in class hierarchies, so we need classes. if (!DestType->isRecordType() || !SrcType->isRecordType()) { return TC_NotApplicable; @@ -943,6 +948,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, } // A valid member pointer cast. + Kind = CastExpr::CK_BitCast; return TC_Success; } @@ -1044,6 +1050,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // Not casting away constness, so the only remaining check is for compatible // pointer categories. + Kind = CastExpr::CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { @@ -1085,8 +1092,10 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - if (CastTy->isVoidType()) + if (CastTy->isVoidType()) { + Kind = CastExpr::CK_ToVoid; return false; + } // If the type is dependent, we won't do any other semantic analysis now. if (CastTy->isDependentType() || CastExpr->isTypeDependent()) @@ -1109,6 +1118,9 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, msg); + if (tcr == TC_Success) + Kind = CastExpr::CK_NoOp; + if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 92bf83f..589b0c6 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -381,8 +381,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // If the first type needs to be converted (e.g. void** -> int*), do it now. if (BuiltinFT->getArgType(0) != FirstArg->getType()) { - ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_Unknown, - /*isLvalue=*/false); + ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_BitCast); TheCall->setArg(0, FirstArg); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3981b8d..3811513 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -235,8 +235,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Filter out names reserved for the implementation (C99 7.1.3, // C++ [lib.global.names]). Users don't need to see those. + // + // FIXME: Add predicate for this. if (Id->getLength() >= 2) { - const char *Name = Id->getName(); + const char *Name = Id->getNameStart(); if (Name[0] == '_' && (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) return; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 606b33f..b83181b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -218,7 +218,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { Diag(SS->getRange().getBegin(), diag::err_typename_missing) - << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() + << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() << SourceRange(SS->getRange().getBegin(), IILoc) << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(), "typename "); @@ -1059,6 +1059,8 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { /// NeverFallThrough iff we never fall off the end of the statement. We assume /// that functions not marked noreturn will return. Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { + // FIXME: Eventually share this CFG object when we have other warnings based + // of the CFG. This can be done using AnalysisContext. llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context)); // FIXME: They should never return 0, fix that, delete this code. @@ -1527,14 +1529,19 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } + // Mock up a declarator. + Declarator Dc(DS, Declarator::TypeNameContext); + DeclaratorInfo *DInfo = 0; + GetTypeForDeclarator(Dc, S, &DInfo); + assert(DInfo && "couldn't build declarator info for anonymous struct/union"); + // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - // FIXME: Type source info. - /*DInfo=*/0, + DInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); if (getLangOptions().CPlusPlus) @@ -1561,8 +1568,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - // FIXME: Type source info. - /*DInfo=*/0, + DInfo, SC); } Anon->setImplicit(); @@ -1903,16 +1909,9 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, llvm::APSInt &Res = EvalResult.Val.getInt(); if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) { - Expr* ArySizeExpr = VLATy->getSizeExpr(); - // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA, - // so as to transfer ownership to the ConstantArrayWithExpr. - // Alternatively, we could "clone" it (how?). - // Since we don't know how to do things above, we just use the - // very same Expr*. - return Context.getConstantArrayWithExprType(VLATy->getElementType(), - Res, ArySizeExpr, - ArrayType::Normal, 0, - VLATy->getBracketsRange()); + // TODO: preserve the size expression in declarator info + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); } SizeIsNegative = true; @@ -3331,7 +3330,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { << Init->getSourceRange(); VDecl->setInvalidDecl(); } else if (!VDecl->getType()->isDependentType()) - ImpCastExprToType(Init, VDecl->getType()); + ImpCastExprToType(Init, VDecl->getType(), CastExpr::CK_IntegralCast); } } } else if (VDecl->isFileVarDecl()) { @@ -3534,10 +3533,37 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, // Block scope. C99 6.7p7: If an identifier for an object is declared with // no linkage (C99 6.2.2p6), the type for the object shall be complete... if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) { - if (!IDecl->isInvalidDecl() && - RequireCompleteType(IDecl->getLocation(), T, - diag::err_typecheck_decl_incomplete_type)) - IDecl->setInvalidDecl(); + if (T->isDependentType()) { + // If T is dependent, we should not require a complete type. + // (RequireCompleteType shouldn't be called with dependent types.) + // But we still can at least check if we've got an array of unspecified + // size without an initializer. + if (!IDecl->isInvalidDecl() && T->isIncompleteArrayType() && + !IDecl->getInit()) { + Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type) + << T; + IDecl->setInvalidDecl(); + } + } else if (!IDecl->isInvalidDecl()) { + // If T is an incomplete array type with an initializer list that is + // dependent on something, its size has not been fixed. We could attempt + // to fix the size for such arrays, but we would still have to check + // here for initializers containing a C++0x vararg expansion, e.g. + // template <typename... Args> void f(Args... args) { + // int vals[] = { args }; + // } + const IncompleteArrayType *IAT = T->getAs<IncompleteArrayType>(); + Expr *Init = IDecl->getInit(); + if (IAT && Init && + (Init->isTypeDependent() || Init->isValueDependent())) { + // Check that the member type of the array is complete, at least. + if (RequireCompleteType(IDecl->getLocation(), IAT->getElementType(), + diag::err_typecheck_decl_incomplete_type)) + IDecl->setInvalidDecl(); + } else if (RequireCompleteType(IDecl->getLocation(), T, + diag::err_typecheck_decl_incomplete_type)) + IDecl->setInvalidDecl(); + } } // File scope. C99 6.9.2p2: A declaration of an identifier for an // object that has file scope without an initializer, and without a @@ -3707,12 +3733,13 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) { --i; if (FTI.ArgInfo[i].Param == 0) { - std::string Code = " int "; - Code += FTI.ArgInfo[i].Ident->getName(); - Code += ";\n"; + llvm::SmallString<256> Code; + llvm::raw_svector_ostream(Code) << " int " + << FTI.ArgInfo[i].Ident->getName() + << ";\n"; Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) << FTI.ArgInfo[i].Ident - << CodeModificationHint::CreateInsertion(LocAfterDecls, Code); + << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str()); // Implicitly declare the argument as type 'int' for lack of a better // type. @@ -3975,9 +4002,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, } // Extension in C99. Legal in C90, but warn about it. - static const unsigned int BuiltinLen = strlen("__builtin_"); - if (II.getLength() > BuiltinLen && - std::equal(II.getName(), II.getName() + BuiltinLen, "__builtin_")) + if (II.getName().startswith("__builtin_")) Diag(Loc, diag::warn_builtin_unknown) << &II; else if (getLangOptions().C99) Diag(Loc, diag::ext_implicit_function_decl) << &II; @@ -5587,7 +5612,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Adjust the Expr initializer and type. if (ECD->getInitExpr()) ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, - CastExpr::CK_Unknown, + CastExpr::CK_IntegralCast, ECD->getInitExpr(), /*isLvalue=*/false)); if (getLangOptions().CPlusPlus) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 50ebb49..341d49e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1202,6 +1202,35 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue())); } +enum FormatAttrKind { + CFStringFormat, + NSStringFormat, + StrftimeFormat, + SupportedFormat, + InvalidFormat +}; + +/// getFormatAttrKind - Map from format attribute names to supported format +/// types. +static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { + // Check for formats that get handled specially. + if (Format == "NSString") + return NSStringFormat; + if (Format == "CFString") + return CFStringFormat; + if (Format == "strftime") + return StrftimeFormat; + + // Otherwise, check for supported formats. + if (Format == "scanf" || Format == "printf" || Format == "printf0" || + Format == "strfmon" || Format == "cmn_err" || Format == "strftime" || + Format == "NSString" || Format == "CFString" || Format == "vcmn_err" || + Format == "zcmn_err") + return SupportedFormat; + + return InvalidFormat; +} + /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1226,38 +1255,15 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned NumArgs = getFunctionOrMethodNumArgs(d); unsigned FirstIdx = 1; - const char *Format = Attr.getParameterName()->getName(); - unsigned FormatLen = Attr.getParameterName()->getLength(); + llvm::StringRef Format = Attr.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. - if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && - Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { - Format += 2; - FormatLen -= 4; - } - - bool Supported = false; - bool is_NSString = false; - bool is_strftime = false; - bool is_CFString = false; - - switch (FormatLen) { - default: break; - case 5: Supported = !memcmp(Format, "scanf", 5); break; - case 6: Supported = !memcmp(Format, "printf", 6); break; - case 7: Supported = !memcmp(Format, "printf0", 7) || - !memcmp(Format, "strfmon", 7) || - !memcmp(Format, "cmn_err", 7); break; - case 8: - Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || - (is_NSString = !memcmp(Format, "NSString", 8)) || - !memcmp(Format, "vcmn_err", 8) || - !memcmp(Format, "zcmn_err", 8) || - (is_CFString = !memcmp(Format, "CFString", 8)); - break; - } + if (Format.startswith("__") && Format.endswith("__")) + Format = Format.substr(2, Format.size() - 4); - if (!Supported) { + // Check for supported formats. + FormatAttrKind Kind = getFormatAttrKind(Format); + if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "format" << Attr.getParameterName()->getName(); return; @@ -1296,13 +1302,13 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); - if (is_CFString) { + if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { S.Diag(Attr.getLoc(), diag::err_format_attribute_not) << "a CFString" << IdxExpr->getSourceRange(); return; } - } else if (is_NSString) { + } else if (Kind == NSStringFormat) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { @@ -1340,7 +1346,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // strftime requires FirstArg to be 0 because it doesn't read from any // variable the input is just the current time + the format string. - if (is_strftime) { + if (Kind == StrftimeFormat) { if (FirstArg != 0) { S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) << FirstArgExpr->getSourceRange(); @@ -1353,8 +1359,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen), - Idx.getZExtValue(), FirstArg.getZExtValue())); + d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(), + FirstArg.getZExtValue())); } static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, @@ -1496,20 +1502,17 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name); return; } - const char *Str = Name->getName(); - unsigned Len = Name->getLength(); + + llvm::StringRef Str = Attr.getParameterName()->getName(); // Normalize the attribute name, __foo__ becomes foo. - if (Len > 4 && Str[0] == '_' && Str[1] == '_' && - Str[Len - 2] == '_' && Str[Len - 1] == '_') { - Str += 2; - Len -= 4; - } + if (Str.startswith("__") && Str.endswith("__")) + Str = Str.substr(2, Str.size() - 4); unsigned DestWidth = 0; bool IntegerMode = true; bool ComplexMode = false; - switch (Len) { + switch (Str.size()) { case 2: switch (Str[0]) { case 'Q': DestWidth = 8; break; @@ -1531,13 +1534,13 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { case 4: // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. - if (!memcmp(Str, "word", 4)) + if (Str == "word") DestWidth = S.Context.Target.getPointerWidth(0); - if (!memcmp(Str, "byte", 4)) + else if (Str == "byte") DestWidth = S.Context.Target.getCharWidth(); break; case 7: - if (!memcmp(Str, "pointer", 7)) + if (Str == "pointer") DestWidth = S.Context.Target.getPointerWidth(0); break; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 419c8a1..6d1f4ea 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1658,12 +1658,10 @@ namespace { // Traverse the record, looking for methods. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { // If the method is pure virtual, add it to the methods vector. - if (MD->isPure()) { + if (MD->isPure()) Methods.push_back(MD); - continue; - } - // Otherwise, record all the overridden methods in our set. + // Record all the overridden methods in our set. for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { // Keep track of the overridden methods. @@ -3571,7 +3569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (DiagnoseUseOfDecl(Fn, DeclLoc)) return true; - FixOverloadedFunctionReference(Init, Fn); + Init = FixOverloadedFunctionReference(Init, Fn); } T2 = Fn->getType(); @@ -3660,7 +3658,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // applicable conversion functions (13.3.1.6) and choosing // the best one through overload resolution (13.3)), if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !RequireCompleteType(SourceLocation(), T2, 0)) { + !RequireCompleteType(DeclLoc, T2, 0)) { CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); @@ -4283,8 +4281,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. bool invalid = false; - QualType SourceTy; - QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy); + QualType T = ConvertDeclSpecToType(DS, Loc, invalid); if (invalid) return DeclPtrTy(); // This is definitely an error in C++98. It's probably meant to diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a946500..ae45429 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -241,12 +241,12 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { // other types are unchanged by the integer promotions. QualType PTy = Context.isPromotableBitField(Expr); if (!PTy.isNull()) { - ImpCastExprToType(Expr, PTy); + ImpCastExprToType(Expr, PTy, CastExpr::CK_IntegralCast); return Expr; } if (Ty->isPromotableIntegerType()) { QualType PT = Context.getPromotedIntegerType(Ty); - ImpCastExprToType(Expr, PT); + ImpCastExprToType(Expr, PT, CastExpr::CK_IntegralCast); return Expr; } @@ -264,7 +264,8 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { // If this is a 'float' (CVR qualified or typedef) promote to double. if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) if (BT->getKind() == BuiltinType::Float) - return ImpCastExprToType(Expr, Context.DoubleTy); + return ImpCastExprToType(Expr, Context.DoubleTy, + CastExpr::CK_FloatingCast); UsualUnaryConversions(Expr); } @@ -330,8 +331,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); if (!isCompAssign) - ImpCastExprToType(lhsExpr, destType); - ImpCastExprToType(rhsExpr, destType); + ImpCastExprToType(lhsExpr, destType, CastExpr::CK_Unknown); + ImpCastExprToType(rhsExpr, destType, CastExpr::CK_Unknown); return destType; } @@ -940,95 +941,31 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // We may have found a field within an anonymous union or struct // (C++ [class.union]). + // FIXME: This needs to happen post-isImplicitMemberReference? if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { - if (!MD->isStatic()) { - // C++ [class.mfct.nonstatic]p2: - // [...] if name lookup (3.4.1) resolves the name in the - // id-expression to a nonstatic nontype member of class X or of - // a base class of X, the id-expression is transformed into a - // class member access expression (5.2.5) using (*this) (9.3.2) - // as the postfix-expression to the left of the '.' operator. - DeclContext *Ctx = 0; - QualType MemberType; - if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { - Ctx = FD->getDeclContext(); - MemberType = FD->getType(); - - if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>()) - MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) - MemberType - = Context.getQualifiedType(MemberType, - Qualifiers::fromCVRMask(MD->getTypeQualifiers())); - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (!Method->isStatic()) { - Ctx = Method->getParent(); - MemberType = Method->getType(); - } - } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(D)) { - if (CXXMethodDecl *Method - = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) { - if (!Method->isStatic()) { - Ctx = Method->getParent(); - MemberType = Context.OverloadTy; - } - } - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(D)) { - // FIXME: We need an abstraction for iterating over one or more function - // templates or functions. This code is far too repetitive! - for (OverloadedFunctionDecl::function_iterator - Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - CXXMethodDecl *DMethod = 0; - if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(*Func)) - DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); - else - DMethod = dyn_cast<CXXMethodDecl>(*Func); - - if (DMethod && !DMethod->isStatic()) { - Ctx = DMethod->getDeclContext(); - MemberType = Context.OverloadTy; - break; - } - } - } - - if (Ctx && Ctx->isRecord()) { - QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx)); - QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(CtxType) - == Context.getCanonicalType(ThisType)) || - IsDerivedFrom(ThisType, CtxType)) { - // Build the implicit member access expression. - Expr *This = new (Context) CXXThisExpr(SourceLocation(), - MD->getThisType(Context)); - MarkDeclarationReferenced(Loc, D); - if (PerformObjectMemberConversion(This, D)) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && (!SS || !SS->isSet())) - ShouldCheckUse = false; - } + // Cope with an implicit member access in a C++ non-static member function. + QualType ThisType, MemberType; + if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) { + Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + MarkDeclarationReferenced(Loc, D); + if (PerformObjectMemberConversion(This, D)) + return ExprError(); - if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) - return ExprError(); - return Owned(BuildMemberExpr(Context, This, true, SS, D, - Loc, MemberType)); - } - } + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && (!SS || !SS->isSet())) + ShouldCheckUse = false; } + + if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) + return ExprError(); + return Owned(BuildMemberExpr(Context, This, true, SS, D, + Loc, MemberType)); } if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { @@ -1813,7 +1750,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // force the promotion here. Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << LHSExp->getSourceRange(); - ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy)); + ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), + CastExpr::CK_ArrayToPointerDecay); LHSTy = LHSExp->getType(); BaseExpr = LHSExp; @@ -1823,7 +1761,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // Same as previous, except for 123[f().a] case Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << RHSExp->getSourceRange(); - ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy)); + ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), + CastExpr::CK_ArrayToPointerDecay); RHSTy = RHSExp->getType(); BaseExpr = RHSExp; @@ -1877,10 +1816,15 @@ QualType Sema:: CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, const IdentifierInfo *CompName, SourceLocation CompLoc) { + // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, + // see FIXME there. + // + // FIXME: This logic can be greatly simplified by splitting it along + // halving/not halving and reworking the component checking. const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); // The vector accessor can't exceed the number of elements. - const char *compStr = CompName->getName(); + const char *compStr = CompName->getNameStart(); // This flag determines whether or not the component is one of the four // special names that indicate a subset of exactly half the elements are @@ -1917,7 +1861,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // Ensure no component accessor exceeds the width of the vector type it // operates on. if (!HalvingSwizzle) { - compStr = CompName->getName(); + compStr = CompName->getNameStart(); if (HexSwizzle) compStr++; @@ -2042,7 +1986,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // is a reference to 'isa'. if (BaseType != Context.ObjCIdRedefinitionType) { BaseType = Context.ObjCIdRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType); + ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } } assert(!BaseType.isNull() && "no type for member expression"); @@ -2100,7 +2044,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (BaseType->isObjCClassType() && BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType); + ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr @@ -2184,6 +2128,12 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // If the member name was a qualified-id, look into the // nested-name-specifier. DC = computeDeclContext(*SS, false); + + if (!isa<TypeDecl>(DC)) { + Diag(MemberLoc, diag::err_qualified_member_nonclass) + << DC << SS->getRange(); + return ExprError(); + } // FIXME: If DC is not computable, we should build a // CXXUnresolvedMemberExpr. @@ -3142,6 +3092,40 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } +static CastExpr::CastKind getScalarCastKind(ASTContext &Context, + QualType SrcTy, QualType DestTy) { + if (Context.getCanonicalType(SrcTy).getUnqualifiedType() == + Context.getCanonicalType(DestTy).getUnqualifiedType()) + return CastExpr::CK_NoOp; + + if (SrcTy->hasPointerRepresentation()) { + if (DestTy->hasPointerRepresentation()) + return CastExpr::CK_BitCast; + if (DestTy->isIntegerType()) + return CastExpr::CK_PointerToIntegral; + } + + if (SrcTy->isIntegerType()) { + if (DestTy->isIntegerType()) + return CastExpr::CK_IntegralCast; + if (DestTy->hasPointerRepresentation()) + return CastExpr::CK_IntegralToPointer; + if (DestTy->isRealFloatingType()) + return CastExpr::CK_IntegralToFloating; + } + + if (SrcTy->isRealFloatingType()) { + if (DestTy->isRealFloatingType()) + return CastExpr::CK_FloatingCast; + if (DestTy->isIntegerType()) + return CastExpr::CK_FloatingToIntegral; + } + + // FIXME: Assert here. + // assert(false && "Unhandled cast combination!"); + return CastExpr::CK_Unknown; +} + /// CheckCastTypes - Check type constraints for casting between types. bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, CastExpr::CastKind& Kind, @@ -3157,7 +3141,11 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, // type needs to be scalar. if (castType->isVoidType()) { // Cast to void allows any expr type. - } else if (!castType->isScalarType() && !castType->isVectorType()) { + Kind = CastExpr::CK_ToVoid; + return false; + } + + if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.getCanonicalType(castType).getUnqualifiedType() == Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && (castType->isStructureType() || castType->isUnionType())) { @@ -3166,7 +3154,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) << castType << castExpr->getSourceRange(); Kind = CastExpr::CK_NoOp; - } else if (castType->isUnionType()) { + return false; + } + + if (castType->isUnionType()) { // GCC cast to union extension RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator Field, FieldEnd; @@ -3183,28 +3174,36 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) << castExpr->getType() << castExpr->getSourceRange(); Kind = CastExpr::CK_ToUnion; - } else { - // Reject any other conversions to non-scalar types. - return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) - << castType << castExpr->getSourceRange(); + return false; } - } else if (!castExpr->getType()->isScalarType() && - !castExpr->getType()->isVectorType()) { + + // Reject any other conversions to non-scalar types. + return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) + << castType << castExpr->getSourceRange(); + } + + if (!castExpr->getType()->isScalarType() && + !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(), diag::err_typecheck_expect_scalar_operand) << castExpr->getType() << castExpr->getSourceRange(); - } else if (castType->isExtVectorType()) { - if (CheckExtVectorCast(TyR, castType, castExpr->getType())) - return true; - } else if (castType->isVectorType()) { - if (CheckVectorCast(TyR, castType, castExpr->getType())) - return true; - } else if (castExpr->getType()->isVectorType()) { - if (CheckVectorCast(TyR, castExpr->getType(), castType)) - return true; - } else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) { + } + + if (castType->isExtVectorType()) + return CheckExtVectorCast(TyR, castType, castExpr, Kind); + + if (castType->isVectorType()) + return CheckVectorCast(TyR, castType, castExpr->getType(), Kind); + if (castExpr->getType()->isVectorType()) + return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); + + if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - } else if (!castType->isArithmeticType()) { + + if (isa<ObjCSelectorExpr>(castExpr)) + return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + + if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType() && castExprType->isArithmeticType()) return Diag(castExpr->getLocStart(), @@ -3216,12 +3215,13 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, diag::err_cast_pointer_to_non_pointer_int) << castType << castExpr->getSourceRange(); } - if (isa<ObjCSelectorExpr>(castExpr)) - return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + + Kind = getScalarCastKind(Context, castExpr->getType(), castType); return false; } -bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { +bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastExpr::CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); if (Ty->isVectorType() || Ty->isIntegerType()) { @@ -3236,18 +3236,23 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { diag::err_invalid_conversion_between_vector_and_scalar) << VectorTy << Ty << R; + Kind = CastExpr::CK_BitCast; return false; } -bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { +bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, + CastExpr::CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); - + + QualType SrcTy = CastExpr->getType(); + // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; + Kind = CastExpr::CK_BitCast; return false; } @@ -3258,6 +3263,12 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) { return Diag(R.getBegin(), diag::err_invalid_conversion_between_vector_and_scalar) << DestTy << SrcTy << R; + + QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); + ImpCastExprToType(CastExpr, DestElemTy, + getScalarCastKind(Context, SrcTy, DestElemTy)); + + Kind = CastExpr::CK_VectorSplat; return false; } @@ -3414,20 +3425,21 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!RHSTy->isVoidType()) Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void) << LHS->getSourceRange(); - ImpCastExprToType(LHS, Context.VoidTy); - ImpCastExprToType(RHS, Context.VoidTy); + ImpCastExprToType(LHS, Context.VoidTy, CastExpr::CK_ToVoid); + ImpCastExprToType(RHS, Context.VoidTy, CastExpr::CK_ToVoid); return Context.VoidTy; } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer. + // promote the null to a pointer. + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_Unknown); return LHSTy; } if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer. + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } // Handle things like Class and struct objc_class*. Here we case the result @@ -3435,23 +3447,23 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } if (RHSTy->isObjCClassType() && (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy); + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } if (RHSTy->isObjCIdType() && (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy); + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); return RHSTy; } // Handle block pointer types. @@ -3459,8 +3471,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, destType); - ImpCastExprToType(RHS, destType); + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) @@ -3484,13 +3496,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The block pointer types are compatible. - ImpCastExprToType(LHS, LHSTy); - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } // Check constraints for Objective-C object pointers types. @@ -3536,13 +3548,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType); - ImpCastExprToType(RHS, compositeType); + ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); return compositeType; } // Check Objective-C object pointer types and 'void *' @@ -3552,8 +3564,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { @@ -3562,8 +3576,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(RHS, destType); // add qualifiers if necessary - ImpCastExprToType(LHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); return destType; } // Check constraints for C object pointers types (C99 6.5.15p3,6). @@ -3578,16 +3594,20 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(LHS, destType); // add qualifiers if necessary - ImpCastExprToType(RHS, destType); // promote to void* + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); return destType; } @@ -3603,8 +3623,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy); - ImpCastExprToType(RHS, incompatTy); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); return incompatTy; } // The pointer types are compatible. @@ -3614,8 +3634,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type. // FIXME: Need to calculate the composite type. // FIXME: Need to add qualifiers - ImpCastExprToType(LHS, LHSTy); - ImpCastExprToType(RHS, LHSTy); + ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } @@ -3623,13 +3643,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(LHS, RHSTy); // promote the integer to a pointer. + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_IntegralToPointer); return RHSTy; } if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(RHS, LHSTy); // promote the integer to a pointer. + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_IntegralToPointer); return LHSTy; } @@ -3728,16 +3748,16 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // Check if the pointee types are compatible ignoring the sign. // We explicitly check for char so that we catch "char" vs // "unsigned char" on systems where "char" is unsigned. - if (lhptee->isCharType()) { + if (lhptee->isCharType()) lhptee = Context.UnsignedCharTy; - } else if (lhptee->isSignedIntegerType()) { + else if (lhptee->isSignedIntegerType()) lhptee = Context.getCorrespondingUnsignedType(lhptee); - } - if (rhptee->isCharType()) { + + if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; - } else if (rhptee->isSignedIntegerType()) { + else if (rhptee->isSignedIntegerType()) rhptee = Context.getCorrespondingUnsignedType(rhptee); - } + if (lhptee == rhptee) { // Types are compatible ignoring the sign. Qualifier incompatibility // takes priority over sign incompatibility because the sign @@ -4003,14 +4023,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { // 2) null pointer constant if (FromType->isPointerType()) if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { - ImpCastExprToType(rExpr, it->getType()); + ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_BitCast); InitField = *it; break; } if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, it->getType()); + ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer); InitField = *it; break; } @@ -4054,7 +4074,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { lhsType->isBlockPointerType()) && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, lhsType); + ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown); return Compatible; } @@ -4077,7 +4097,8 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. if (result != Incompatible && rExpr->getType() != lhsType) - ImpCastExprToType(rExpr, lhsType.getNonReferenceType()); + ImpCastExprToType(rExpr, lhsType.getNonReferenceType(), + CastExpr::CK_Unknown); return result; } @@ -4128,7 +4149,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, QualType EltTy = LV->getElementType(); if (EltTy->isIntegralType() && rhsType->isIntegralType()) { if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType); + ImpCastExprToType(rex, lhsType, CastExpr::CK_IntegralCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -4136,7 +4157,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, if (EltTy->isRealFloatingType() && rhsType->isScalarType() && rhsType->isRealFloatingType()) { if (Context.getFloatingTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType); + ImpCastExprToType(rex, lhsType, CastExpr::CK_FloatingCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -4416,7 +4437,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, LHSTy = Context.getPromotedIntegerType(LHSTy); } if (!isCompAssign) - ImpCastExprToType(lex, LHSTy); + ImpCastExprToType(lex, LHSTy, CastExpr::CK_IntegralCast); UsualUnaryConversions(rex); @@ -4567,8 +4588,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return QualType(); } - ImpCastExprToType(lex, T); - ImpCastExprToType(rex, T); + ImpCastExprToType(lex, T, CastExpr::CK_BitCast); + ImpCastExprToType(rex, T, CastExpr::CK_BitCast); return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 @@ -4593,7 +4614,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } if (LCanPointeeTy != RCanPointeeTy) - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } @@ -4633,8 +4654,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return QualType(); } - ImpCastExprToType(lex, T); - ImpCastExprToType(rex, T); + ImpCastExprToType(lex, T, CastExpr::CK_BitCast); + ImpCastExprToType(rex, T, CastExpr::CK_BitCast); return ResultTy; } @@ -4653,7 +4674,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } // Allow block pointers to be compared with null pointer constants. @@ -4668,7 +4689,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the pointer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } @@ -4686,14 +4707,14 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { if (!Context.areComparableObjCPointerTypes(lType, rType)) Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType); + ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); return ResultTy; } } @@ -4711,7 +4732,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType); // promote the integer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); return ResultTy; } if (lType->isIntegerType() && rType->isAnyPointerType()) { @@ -4728,18 +4749,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, DiagID) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(lex, rType); // promote the integer to pointer + ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); return ResultTy; } // Handle block pointers. if (!isRelational && RHSIsNull && lType->isBlockPointerType() && rType->isIntegerType()) { - ImpCastExprToType(rex, lType); // promote the integer to pointer + ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); return ResultTy; } if (!isRelational && LHSIsNull && lType->isIntegerType() && rType->isBlockPointerType()) { - ImpCastExprToType(lex, rType); // promote the integer to pointer + ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); return ResultTy; } return InvalidOperands(Loc, lex, rex); @@ -4812,9 +4833,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] UsualUnaryConversions(lex); UsualUnaryConversions(rex); - if (lex->getType()->isScalarType() && rex->getType()->isScalarType()) - return Context.IntTy; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) + return InvalidOperands(Loc, lex, rex); + + if (Context.getLangOptions().CPlusPlus) { + // C++ [expr.log.and]p2 + // C++ [expr.log.or]p2 + return Context.BoolTy; + } + + return Context.IntTy; } /// IsReadonlyProperty - Verify that otherwise a valid l-value expression diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5f111c8..d4d031f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -411,13 +411,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - ImpCastExprToType(ArraySize, Context.getSizeType()); + ImpCastExprToType(ArraySize, Context.getSizeType(), + CastExpr::CK_IntegralCast); } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -448,7 +450,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, Expr **ConsArgs = (Expr**)ConstructorArgs.get(); const RecordType *RT; unsigned NumConsArgs = ConstructorArgs.size(); - if (AllocType->isDependentType()) { + + if (AllocType->isDependentType() || + Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { @@ -491,7 +495,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) - + PlacementArgs.release(); ConstructorArgs.release(); ArraySizeE.release(); @@ -1043,6 +1047,40 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS, Flavor); } +/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST +/// for the derived to base conversion of the expression 'From'. All +/// necessary information is passed in ICS. +bool +Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, + const ImplicitConversionSequence& ICS, + const char *Flavor) { + QualType BaseType = + QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); + // Must do additional defined to base conversion. + QualType DerivedType = + QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr); + + From = new (Context) ImplicitCastExpr( + DerivedType.getNonReferenceType(), + CastKind, + From, + DerivedType->isLValueReferenceType()); + From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(), + CastExpr::CK_DerivedToBase, From, + BaseType->isLValueReferenceType()); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + OwningExprResult FromResult = + BuildCXXConstructExpr( + ICS.UserDefined.After.CopyConstructor->getLocation(), + BaseType, + ICS.UserDefined.After.CopyConstructor, + MultiExprArg(*this, (void **)&From, 1)); + if (FromResult.isInvalid()) + return true; + From = FromResult.takeAs<Expr>(); + return false; +} + /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns true if there was an error, false @@ -1095,13 +1133,19 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CastArg.isInvalid()) return true; + + if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && + ICS.UserDefined.After.CopyConstructor) { + From = CastArg.takeAs<Expr>(); + return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); + } From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), - CastKind, CastArg.takeAs<Expr>(), + CastKind, CastArg.takeAs<Expr>(), ToType->isLValueReferenceType()); return false; - } - + } + case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); return false; @@ -1182,8 +1226,14 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - FixOverloadedFunctionReference(From, Fn); + From = FixOverloadedFunctionReference(From, Fn); FromType = From->getType(); + + // If there's already an address-of operator in the expression, we have + // the right type already, and the code below would just introduce an + // invalid additional pointer level. + if (FromType->isPointerType() || FromType->isMemberFunctionPointerType()) + break; } FromType = Context.getPointerType(FromType); ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); @@ -1205,17 +1255,33 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Integral_Promotion: - case ICK_Floating_Promotion: - case ICK_Complex_Promotion: case ICK_Integral_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); + break; + + case ICK_Floating_Promotion: case ICK_Floating_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_FloatingCast); + break; + + case ICK_Complex_Promotion: case ICK_Complex_Conversion: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + case ICK_Floating_Integral: + if (ToType->isFloatingType()) + ImpCastExprToType(From, ToType, CastExpr::CK_IntegralToFloating); + else + ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral); + break; + case ICK_Complex_Real: + ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + break; + case ICK_Compatible_Conversion: - // FIXME: Go deeper to get the unqualified type! - FromType = ToType.getUnqualifiedType(); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, ToType, CastExpr::CK_NoOp); break; case ICK_Pointer_Conversion: { @@ -1245,8 +1311,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } case ICK_Boolean_Conversion: - FromType = Context.BoolTy; - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown); break; default: @@ -1263,7 +1328,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_Unknown, + CastExpr::CK_NoOp, ToType->isLValueReferenceType()); break; @@ -1465,7 +1530,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, SourceLocation Loc) { Expr *Args[2] = { LHS, RHS }; OverloadCandidateSet CandidateSet; - Self.AddBuiltinOperatorCandidates(OO_Conditional, Args, 2, CandidateSet); + Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { @@ -1691,12 +1756,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>(); if (LMemPtr && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LTy); + ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer); return LTy; } if (RMemPtr && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RTy); + ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer); return RTy; } if (LMemPtr && RMemPtr) { @@ -1787,11 +1852,17 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // one operand is a null pointer constant, the composite pointer type is // the type of the other operand. if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(E1, T2); + if (T2->isMemberPointerType()) + ImpCastExprToType(E1, T2, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(E1, T2, CastExpr::CK_IntegralToPointer); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(E2, T1); + if (T1->isMemberPointerType()) + ImpCastExprToType(E2, T1, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(E2, T1, CastExpr::CK_IntegralToPointer); return T1; } @@ -2051,6 +2122,8 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, ClassName); else { TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); + + // FIXME: If Base is dependent, we might not be able to resolve it here. if (!BaseTy) { Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) << ClassName; @@ -2060,25 +2133,41 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, BaseType = GetTypeFromParser(BaseTy); } - CanQualType CanBaseType = Context.getCanonicalType(BaseType); - DeclarationName DtorName = - Context.DeclarationNames.getCXXDestructorName(CanBaseType); + return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind, + SourceRange(ClassNameLoc), + BaseType.getAsOpaquePtr(), + SS, HasTrailingLParen); +} +Sema::OwningExprResult +Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *T, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + QualType Type = QualType::getFromOpaquePtr(T); + CanQualType CanType = Context.getCanonicalType(Type); + DeclarationName DtorName = + Context.DeclarationNames.getCXXDestructorName(CanType); + OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - DtorName, DeclPtrTy(), &SS); + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + TypeRange.getBegin(), DtorName, DeclPtrTy(), + &SS); if (Result.isInvalid() || HasTrailingLParen) return move(Result); - + // The only way a reference to a destructor can be used is to // immediately call them. Since the next token is not a '(', produce a // diagnostic and build the call now. Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd()); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd()); Diag(E->getLocStart(), diag::err_dtor_expr_without_call) << isa<CXXPseudoDestructorExpr>(E) << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } @@ -2154,9 +2243,14 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, MultiExprArg(*this, (void **)&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - - return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs)); + + OwningExprResult Result = + BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + if (Result.isInvalid()) + return ExprError(); + + return MaybeBindToTemporary(Result.takeAs<Expr>()); } case CastExpr::CK_UserDefinedConversion: { @@ -2168,7 +2262,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, // Create an implicit call expr that calls it. CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); - return Owned(CE); + return MaybeBindToTemporary(CE); } } } @@ -2182,3 +2276,84 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { return Owned(FullExpr); } + +/// \brief Determine whether a reference to the given declaration in the +/// current context is an implicit member access +/// (C++ [class.mfct.non-static]p2). +/// +/// FIXME: Should Objective-C also use this approach? +/// +/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the +/// name of the declaration referenced. +/// +/// \param D the declaration being referenced from the current scope. +/// +/// \param NameLoc the location of the name in the source. +/// +/// \param ThisType if the reference to this declaration is an implicit member +/// access, will be set to the type of the "this" pointer to be used when +/// building that implicit member access. +/// +/// \param MemberType if the reference to this declaration is an implicit +/// member access, will be set to the type of the member being referenced +/// (for use at the type of the resulting member access expression). +/// +/// \returns true if this is an implicit member reference (in which case +/// \p ThisType and \p MemberType will be set), or false if it is not an +/// implicit member reference. +bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, + SourceLocation NameLoc, QualType &ThisType, + QualType &MemberType) { + // If this isn't a C++ method, then it isn't an implicit member reference. + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); + if (!MD || MD->isStatic()) + return false; + + // C++ [class.mfct.nonstatic]p2: + // [...] if name lookup (3.4.1) resolves the name in the + // id-expression to a nonstatic nontype member of class X or of + // a base class of X, the id-expression is transformed into a + // class member access expression (5.2.5) using (*this) (9.3.2) + // as the postfix-expression to the left of the '.' operator. + DeclContext *Ctx = 0; + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Ctx = FD->getDeclContext(); + MemberType = FD->getType(); + + if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>()) + MemberType = RefType->getPointeeType(); + else if (!FD->isMutable()) + MemberType + = Context.getQualifiedType(MemberType, + Qualifiers::fromCVRMask(MD->getTypeQualifiers())); + } else { + for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) { + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl); + FunctionTemplateDecl *FunTmpl = 0; + if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl))) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + + if (Method && !Method->isStatic()) { + Ctx = Method->getParent(); + if (isa<CXXMethodDecl>(D) && !FunTmpl) + MemberType = Method->getType(); + else + MemberType = Context.OverloadTy; + break; + } + } + } + + if (!Ctx || !Ctx->isRecord()) + return false; + + // Determine whether the declaration(s) we found are actually in a base + // class. If not, this isn't an implicit member reference. + ThisType = MD->getThisType(Context); + QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx)); + QualType ClassType + = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent())); + return Context.hasSameType(CtxType, ClassType) || + IsDerivedFrom(ClassType, CtxType); +} + diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d7e4e4a..b78c10b 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -636,7 +636,11 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(lbrac, diag::warn_bad_receiver_type) << RExpr->getType() << RExpr->getSourceRange(); - ImpCastExprToType(RExpr, Context.getObjCIdType()); + if (ReceiverCType->isPointerType()) + ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast); + else + ImpCastExprToType(RExpr, Context.getObjCIdType(), + CastExpr::CK_IntegralToPointer); } else { // Reject other random receiver types (e.g. structs). Diag(lbrac, diag::err_bad_receiver_type) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 27f0896..4746a25 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -109,9 +109,9 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { llvm::APSInt ConstVal(32); ConstVal = StrLength; // Return a new array type (C99 6.7.8p22). - DeclT = S.Context.getConstantArrayWithoutExprType(IAT->getElementType(), - ConstVal, - ArrayType::Normal, 0); + DeclT = S.Context.getConstantArrayType(IAT->getElementType(), + ConstVal, + ArrayType::Normal, 0); return; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 99e7b08..ebcf3ad 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1934,14 +1934,43 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, return ImplicitConversionSequence::Worse; } } - - - // FIXME: conversion of A::* to B::* is better than conversion of - // A::* to C::*, - - // FIXME: conversion of B::* to C::* is better than conversion of - // A::* to C::*, and - + + // Ranking of member-pointer types. + if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && + FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && + ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) { + const MemberPointerType * FromMemPointer1 = + FromType1->getAs<MemberPointerType>(); + const MemberPointerType * ToMemPointer1 = + ToType1->getAs<MemberPointerType>(); + const MemberPointerType * FromMemPointer2 = + FromType2->getAs<MemberPointerType>(); + const MemberPointerType * ToMemPointer2 = + ToType2->getAs<MemberPointerType>(); + const Type *FromPointeeType1 = FromMemPointer1->getClass(); + const Type *ToPointeeType1 = ToMemPointer1->getClass(); + const Type *FromPointeeType2 = FromMemPointer2->getClass(); + const Type *ToPointeeType2 = ToMemPointer2->getClass(); + QualType FromPointee1 = QualType(FromPointeeType1, 0).getUnqualifiedType(); + QualType ToPointee1 = QualType(ToPointeeType1, 0).getUnqualifiedType(); + QualType FromPointee2 = QualType(FromPointeeType2, 0).getUnqualifiedType(); + QualType ToPointee2 = QualType(ToPointeeType2, 0).getUnqualifiedType(); + // conversion of A::* to B::* is better than conversion of A::* to C::*, + if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { + if (IsDerivedFrom(ToPointee1, ToPointee2)) + return ImplicitConversionSequence::Worse; + else if (IsDerivedFrom(ToPointee2, ToPointee1)) + return ImplicitConversionSequence::Better; + } + // conversion of B::* to C::* is better than conversion of A::* to C::* + if (ToPointee1 == ToPointee2 && FromPointee1 != FromPointee2) { + if (IsDerivedFrom(FromPointee1, FromPointee2)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromPointee2, FromPointee1)) + return ImplicitConversionSequence::Worse; + } + } + if (SCS1.CopyConstructor && SCS2.CopyConstructor && SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, @@ -2539,6 +2568,18 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.Viable = false; return; } + + // We won't go through a user-define type conversion function to convert a + // derived to base as such conversions are given Conversion Rank. They only + // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] + QualType FromCanon + = Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); + if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { + Candidate.Viable = false; + return; + } + // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to @@ -2551,7 +2592,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, DeclRefExpr ConversionRef(Conversion, Conversion->getType(), SourceLocation()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), - CastExpr::CK_Unknown, + CastExpr::CK_FunctionToPointerDecay, &ConversionRef, false); // Note that it is safe to allocate CallExpr on the stack here because @@ -2723,7 +2764,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, ArgumentDependentLookup(OpName, Args, NumArgs, Functions); AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); - AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); } /// \brief Add overload candidates for overloaded operators that are @@ -2873,7 +2914,8 @@ class BuiltinCandidateTypeSet { /// Context - The AST context in which we will build the type sets. ASTContext &Context; - bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty); + bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty, + const Qualifiers &VisibleQuals); bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty); public: @@ -2883,8 +2925,11 @@ public: BuiltinCandidateTypeSet(Sema &SemaRef) : SemaRef(SemaRef), Context(SemaRef.Context) { } - void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, - bool AllowExplicitConversions); + void AddTypesConvertedFrom(QualType Ty, + SourceLocation Loc, + bool AllowUserConversions, + bool AllowExplicitConversions, + const Qualifiers &VisibleTypeConversionsQuals); /// pointer_begin - First pointer type found; iterator pointer_begin() { return PointerTypes.begin(); } @@ -2915,7 +2960,8 @@ public: /// /// FIXME: what to do about extended qualifiers? bool -BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { +BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, + const Qualifiers &VisibleQuals) { // Insert this type. if (!PointerTypes.insert(Ty)) @@ -2926,11 +2972,16 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { QualType PointeeTy = PointerTy->getPointeeType(); unsigned BaseCVR = PointeeTy.getCVRQualifiers(); - + bool hasVolatile = VisibleQuals.hasVolatile(); + bool hasRestrict = VisibleQuals.hasRestrict(); + // Iterate through all strict supersets of BaseCVR. for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { if ((CVR | BaseCVR) != CVR) continue; - + // Skip over Volatile/Restrict if no Volatile/Restrict found anywhere + // in the types. + if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue; + if ((CVR & Qualifiers::Restrict) && !hasRestrict) continue; QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); PointerTypes.insert(Context.getPointerType(QPointeeTy)); } @@ -2983,8 +3034,10 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( /// type. void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, + SourceLocation Loc, bool AllowUserConversions, - bool AllowExplicitConversions) { + bool AllowExplicitConversions, + const Qualifiers &VisibleQuals) { // Only deal with canonical types. Ty = Context.getCanonicalType(Ty); @@ -3001,33 +3054,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // Insert our type, and its more-qualified variants, into the set // of types. - if (!AddPointerWithMoreQualifiedTypeVariants(Ty)) + if (!AddPointerWithMoreQualifiedTypeVariants(Ty, VisibleQuals)) return; - - // Add 'cv void*' to our set of types. - if (!Ty->isVoidType()) { - QualType QualVoid - = Context.getCVRQualifiedType(Context.VoidTy, - PointeeTy.getCVRQualifiers()); - AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); - } - - // If this is a pointer to a class type, add pointers to its bases - // (with the same level of cv-qualification as the original - // derived class, of course). - if (const RecordType *PointeeRec = PointeeTy->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl()); - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - QualType BaseTy = Context.getCanonicalType(Base->getType()); - BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(), - PointeeTy.getCVRQualifiers()); - - // Add the pointer type, recursively, so that we get all of - // the indirect base classes, too. - AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false); - } - } } else if (Ty->isMemberPointerType()) { // Member pointers are far easier, since the pointee can't be converted. if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) @@ -3036,7 +3064,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, EnumerationTypes.insert(Ty); } else if (AllowUserConversions) { if (const RecordType *TyRec = Ty->getAs<RecordType>()) { - if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) { + if (SemaRef.RequireCompleteType(Loc, Ty, 0)) { // No conversion functions in incomplete types. return; } @@ -3056,8 +3084,10 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (ConvTemplate) continue; - if (AllowExplicitConversions || !Conv->isExplicit()) - AddTypesConvertedFrom(Conv->getConversionType(), false, false); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); + } } } } @@ -3089,6 +3119,58 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, } } +/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers +/// , if any, found in visible type conversion functions found in ArgExpr's +/// type. +static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { + Qualifiers VRQuals; + const RecordType *TyRec; + if (const MemberPointerType *RHSMPType = + ArgExpr->getType()->getAs<MemberPointerType>()) + TyRec = cast<RecordType>(RHSMPType->getClass()); + else + TyRec = ArgExpr->getType()->getAs<RecordType>(); + if (!TyRec) { + // Just to be safe, assume the worst case. + VRQuals.addVolatile(); + VRQuals.addRestrict(); + return VRQuals; + } + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + OverloadedFunctionDecl *Conversions = + ClassDecl->getVisibleConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*Func)) { + QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); + if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>()) + CanTy = ResTypeRef->getPointeeType(); + // Need to go down the pointer/mempointer chain and add qualifiers + // as see them. + bool done = false; + while (!done) { + if (const PointerType *ResTypePtr = CanTy->getAs<PointerType>()) + CanTy = ResTypePtr->getPointeeType(); + else if (const MemberPointerType *ResTypeMPtr = + CanTy->getAs<MemberPointerType>()) + CanTy = ResTypeMPtr->getPointeeType(); + else + done = true; + if (CanTy.isVolatileQualified()) + VRQuals.addVolatile(); + if (CanTy.isRestrictQualified()) + VRQuals.addRestrict(); + if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) + return VRQuals; + } + } + } + return VRQuals; +} + /// AddBuiltinOperatorCandidates - Add the appropriate built-in /// operator overloads to the candidate set (C++ [over.built]), based /// on the operator @p Op and the arguments given. For example, if the @@ -3096,6 +3178,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, /// operator+(int, int)" to cover integer addition. void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { // The set of "promoted arithmetic types", which are the arithmetic @@ -3119,10 +3202,25 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy, Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy }; - + assert(ArithmeticTypes[FirstPromotedIntegralType] == Context.IntTy && + "Invalid first promoted integral type"); + assert(ArithmeticTypes[LastPromotedIntegralType - 1] + == Context.UnsignedLongLongTy && + "Invalid last promoted integral type"); + assert(ArithmeticTypes[FirstPromotedArithmeticType] == Context.IntTy && + "Invalid first promoted arithmetic type"); + assert(ArithmeticTypes[LastPromotedArithmeticType - 1] + == Context.LongDoubleTy && + "Invalid last promoted arithmetic type"); + // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates // that make use of these types. + Qualifiers VisibleTypeConversionsQuals; + VisibleTypeConversionsQuals.addConst(); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); + BuiltinCandidateTypeSet CandidateTypes(*this); if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || @@ -3132,10 +3230,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) { for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), + OpLoc, true, (Op == OO_Exclaim || Op == OO_AmpAmp || - Op == OO_PipePipe)); + Op == OO_PipePipe), + VisibleTypeConversionsQuals); } bool isComparison = false; @@ -3202,14 +3302,17 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); - - // Volatile version - ParamTypes[0] - = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); - if (NumArgs == 1) - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); - else - AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + // heuristic to reduce number of builtin candidates in the set. + // Add volatile version only if there are conversions to a volatile type. + if (VisibleTypeConversionsQuals.hasVolatile()) { + // Volatile version + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + } } // C++ [over.built]p5: @@ -3238,7 +3341,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, else AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { // With volatile ParamTypes[0] = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); @@ -3550,7 +3654,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); - if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { // volatile version ParamTypes[0] = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); @@ -3586,10 +3691,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /*IsAssigmentOperator=*/Op == OO_Equal); // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, - /*IsAssigmentOperator=*/Op == OO_Equal); + if (VisibleTypeConversionsQuals.hasVolatile()) { + ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } } } break; @@ -3621,12 +3728,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); - - // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left]; - ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); - ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + if (VisibleTypeConversionsQuals.hasVolatile()) { + // Add this built-in operator as a candidate (VQ is 'volatile'). + ParamTypes[0] = ArithmeticTypes[Left]; + ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + } } } break; @@ -3708,6 +3816,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0); if (!isa<RecordType>(C1)) continue; + // heuristic to reduce number of builtin candidates in the set. + // Add volatile/restrict version only if there are conversions to a + // volatile/restrict type. + if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) + continue; } for (BuiltinCandidateTypeSet::iterator MemPtr = CandidateTypes.member_pointer_begin(), @@ -3721,6 +3836,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType ParamTypes[2] = { *Ptr, *MemPtr }; // build CV12 T& QualType T = mptr->getPointeeType(); + if (!VisibleTypeConversionsQuals.hasVolatile() && + T.isVolatileQualified()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && + T.isRestrictQualified()) + continue; T = Q1.apply(T); QualType ResultTy = Context.getLValueReferenceType(T); AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); @@ -4061,13 +4182,20 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } else if (OnlyViable) { assert(Cand->Conversions.size() <= 2 && "builtin-binary-operator-not-binary"); - if (Cand->Conversions.size() == 1) - Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) - << Opc << Cand->BuiltinTypes.ParamTypes[0]; - else - Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) - << Opc << Cand->BuiltinTypes.ParamTypes[0] - << Cand->BuiltinTypes.ParamTypes[1]; + std::string TypeStr("operator"); + TypeStr += Opc; + TypeStr += "("; + TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); + if (Cand->Conversions.size() == 1) { + TypeStr += ")"; + Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr; + } + else { + TypeStr += ", "; + TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); + TypeStr += ")"; + Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr; + } } else if (!Cand->Viable && !Reported) { // Non-viability might be due to ambiguous user-defined conversions, @@ -4150,6 +4278,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, OvlExpr = UnOp->getSubExpr()->IgnoreParens(); } + bool HasExplicitTemplateArgs = false; + const TemplateArgument *ExplicitTemplateArgs = 0; + unsigned NumExplicitTemplateArgs = 0; + // Try to dig out the overloaded function. FunctionTemplateDecl *FunctionTemplate = 0; if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) { @@ -4159,9 +4291,17 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl()); // FIXME: Explicit template arguments + } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) { + TemplateName Name = TIRE->getTemplateName(); + Ovl = Name.getAsOverloadedFunctionDecl(); + FunctionTemplate = + dyn_cast_or_null<FunctionTemplateDecl>(Name.getAsTemplateDecl()); + + HasExplicitTemplateArgs = true; + ExplicitTemplateArgs = TIRE->getTemplateArgs(); + NumExplicitTemplateArgs = TIRE->getNumTemplateArgs(); } - // FIXME: TemplateIdRefExpr? - + // If there's no overloaded function declaration or function template, // we're done. if (!Ovl && !FunctionTemplate) @@ -4206,8 +4346,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false, - /*FIXME:*/0, /*FIXME:*/0, + = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, FunctionType, Specialization, Info)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; @@ -4240,8 +4381,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // If there were 0 or 1 matches, we're done. if (Matches.empty()) return 0; - else if (Matches.size() == 1) - return *Matches.begin(); + else if (Matches.size() == 1) { + FunctionDecl *Result = *Matches.begin(); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; + } // C++ [over.over]p4: // If more than one function is selected, [...] @@ -4257,14 +4401,17 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // two-pass algorithm (similar to the one used to identify the // best viable function in an overload set) that identifies the // best function template (if it exists). - llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(), + llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(), Matches.end()); - return getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), - TPOC_Other, From->getLocStart(), - PDiag(), - PDiag(diag::err_addr_ovl_ambiguous) - << TemplateMatches[0]->getDeclName(), - PDiag(diag::err_ovl_template_candidate)); + FunctionDecl *Result = + getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), + TPOC_Other, From->getLocStart(), + PDiag(), + PDiag(diag::err_addr_ovl_ambiguous) + << TemplateMatches[0]->getDeclName(), + PDiag(diag::err_ovl_template_candidate)); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; } // [...] any function template specializations in the set are @@ -4276,8 +4423,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // [...] After such eliminations, if any, there shall remain exactly one // selected function. - if (RemainingMatches.size() == 1) - return RemainingMatches.front(); + if (RemainingMatches.size() == 1) { + FunctionDecl *Result = RemainingMatches.front(); + MarkDeclarationReferenced(From->getLocStart(), Result); + return Result; + } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). @@ -4511,7 +4661,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -4671,7 +4821,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -4925,6 +5075,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); + if (RequireCompleteType(LParenLoc, Object->getType(), + PartialDiagnostic(diag::err_incomplete_object_call) + << Object->getSourceRange())) + return true; + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -4942,33 +5097,30 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) { - // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - - // Skip over templated conversion functions; they aren't - // surrogates. - if (ConvTemplate) - continue; + // Skip over templated conversion functions; they aren't + // surrogates. + if (ConvTemplate) + continue; - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) - ConvType = ConvPtrType->getPointeeType(); + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); - if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); - } + if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); } // Perform overload resolution. @@ -5205,11 +5357,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// a C++ overloaded function (possibly with some parentheses and /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to -/// refer (possibly indirectly) to Fn. -void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { +/// refer (possibly indirectly) to Fn. Returns the new expr. +Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { - FixOverloadedFunctionReference(PE->getSubExpr(), Fn); - E->setType(PE->getSubExpr()->getType()); + Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + NewExpr->setType(PE->getSubExpr()->getType()); + return NewExpr; } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); @@ -5228,11 +5381,16 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); E->setType(Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr())); - return; + return E; } + // FIXME: TemplateIdRefExpr referring to a member function template + // specialization! } - FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); - E->setType(Context.getPointerType(UnOp->getSubExpr()->getType())); + Expr *NewExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + UnOp->setSubExpr(NewExpr); + UnOp->setType(Context.getPointerType(NewExpr->getType())); + + return UnOp; } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { assert((isa<OverloadedFunctionDecl>(DR->getDecl()) || isa<FunctionTemplateDecl>(DR->getDecl())) && @@ -5242,9 +5400,24 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { MemExpr->setMemberDecl(Fn); E->setType(Fn->getType()); + } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(E)) { + // FIXME: We should capture the template arguments here. + if (NestedNameSpecifier *Qualifier = TID->getQualifier()) + E = new (Context) QualifiedDeclRefExpr(Fn, Fn->getType(), + TID->getTemplateNameLoc(), + /*FIXME?*/false, /*FIXME?*/false, + TID->getQualifierRange(), + Qualifier); + else + E = new (Context) DeclRefExpr(Fn, Fn->getType(), + TID->getTemplateNameLoc()); + + TID->Destroy(Context); } else { assert(false && "Invalid reference to overloaded function"); } + + return E; } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index e8cd6b0..1453424 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -368,6 +368,21 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs, return false; } +/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of +/// potentially integral-promoted expression @p expr. +static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { + const ImplicitCastExpr *ImplicitCast = + dyn_cast_or_null<ImplicitCastExpr>(expr); + if (ImplicitCast != NULL) { + const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr(); + QualType TypeBeforePromotion = ExprBeforePromotion->getType(); + if (TypeBeforePromotion->isIntegralType()) { + return TypeBeforePromotion; + } + } + return expr->getType(); +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -382,11 +397,30 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, Expr *CondExpr = SS->getCond(); QualType CondType = CondExpr->getType(); - if (!CondExpr->isTypeDependent() && - !CondType->isIntegerType()) { // C99 6.8.4.2p1 - Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) - << CondType << CondExpr->getSourceRange(); - return StmtError(); + // C++ 6.4.2.p2: + // Integral promotions are performed (on the switch condition). + // + // A case value unrepresentable by the original switch condition + // type (before the promotion) doesn't make sense, even when it can + // be represented by the promoted type. Therefore we need to find + // the pre-promotion type of the switch condition. + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExpr); + + if (!CondExpr->isTypeDependent()) { + if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 + Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) + << CondType << CondExpr->getSourceRange(); + return StmtError(); + } + + if (CondTypeBeforePromotion->isBooleanType()) { + // switch(bool_expr) {...} is often a programmer error, e.g. + // switch(n && mask) { ... } // Doh - should be "n & mask". + // One can always use an if statement instead of switch(bool_expr). + Diag(SwitchLoc, diag::warn_bool_switch_condition) + << CondExpr->getSourceRange(); + } } // Get the bitwidth of the switched-on value before promotions. We must @@ -395,8 +429,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue? 0 - : static_cast<unsigned>(Context.getTypeSize(CondType)); - bool CondIsSigned = CondType->isSignedIntegerType(); + : static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion)); + bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType(); // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after @@ -448,7 +482,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Lo, CondType); + ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -504,7 +538,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Hi, CondType); + ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ab0bbe0..0f22320 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1251,7 +1251,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, return ElabType.getAsOpaquePtr(); } -Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, +Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, @@ -1261,16 +1263,36 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, // template arguments that we have against the template name, if the template // name refers to a single template. That's not a terribly common case, // though. - return Owned(TemplateIdRefExpr::Create(Context, - /*FIXME: New type?*/Context.OverloadTy, - /*FIXME: Necessary?*/0, - /*FIXME: Necessary?*/SourceRange(), + + // Cope with an implicit member access in a C++ non-static member function. + NamedDecl *D = Template.getAsTemplateDecl(); + if (!D) + D = Template.getAsOverloadedFunctionDecl(); + + CXXScopeSpec SS; + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + QualType ThisType, MemberType; + if (D && isImplicitMemberReference(&SS, D, TemplateNameLoc, + ThisType, MemberType)) { + Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + return Owned(MemberExpr::Create(Context, This, true, + Qualifier, QualifierRange, + D, TemplateNameLoc, true, + LAngleLoc, TemplateArgs, + NumTemplateArgs, RAngleLoc, + Context.OverloadTy)); + } + + return Owned(TemplateIdRefExpr::Create(Context, Context.OverloadTy, + Qualifier, QualifierRange, Template, TemplateNameLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc)); } -Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, +Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, @@ -1283,7 +1305,9 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(TemplateTy TemplateD, translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); TemplateArgsIn.release(); - return BuildTemplateIdExpr(Template, TemplateNameLoc, LAngleLoc, + return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), + SS.getRange(), + Template, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc); } @@ -1706,7 +1730,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, bool Invalid = false; // See through any implicit casts we added to fix the type. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); // C++0x allows nullptr, and there's no further checking to be done for that. @@ -1808,7 +1832,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { bool Invalid = false; // See through any implicit casts we added to fix the type. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) Arg = Cast->getSubExpr(); // C++0x allows nullptr, and there's no further checking to be done for that. @@ -1936,7 +1960,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_IntegralCast); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -2025,20 +2049,23 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || ParamType->isMemberPointerType())) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + if (ParamType->isMemberPointerType()) + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); + else + ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(ArgType); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); } else if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; - FixOverloadedFunctionReference(Arg, Fn); + Arg = FixOverloadedFunctionReference(Arg, Fn); ArgType = Arg->getType(); if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(Arg->getType()); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); } } @@ -2083,15 +2110,15 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (ArgType->isNullPtrType()) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); } else if (ArgType->isArrayType()) { ArgType = Context.getArrayDecayedType(ArgType); - ImpCastExprToType(Arg, ArgType); + ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay); } if (IsQualificationConversion(ArgType, ParamType)) { ArgType = ParamType; - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); } if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { @@ -2162,9 +2189,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. } else if (ArgType->isNullPtrType()) { - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); } else if (IsQualificationConversion(ArgType, ParamType)) { - ImpCastExprToType(Arg, ParamType); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -3038,6 +3065,173 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, return DeclPtrTy(); } +/// \brief Diagnose cases where we have an explicit template specialization +/// before/after an explicit template instantiation, producing diagnostics +/// for those cases where they are required and determining whether the +/// new specialization/instantiation will have any effect. +/// +/// \param S the semantic analysis object. +/// +/// \param NewLoc the location of the new explicit specialization or +/// instantiation. +/// +/// \param NewTSK the kind of the new explicit specialization or instantiation. +/// +/// \param PrevDecl the previous declaration of the entity. +/// +/// \param PrevTSK the kind of the old explicit specialization or instantiatin. +/// +/// \param PrevPointOfInstantiation if valid, indicates where the previus +/// declaration was instantiated (either implicitly or explicitly). +/// +/// \param SuppressNew will be set to true to indicate that the new +/// specialization or instantiation has no effect and should be ignored. +/// +/// \returns true if there was an error that should prevent the introduction of +/// the new declaration into the AST, false otherwise. +static bool +CheckSpecializationInstantiationRedecl(Sema &S, + SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew) { + SuppressNew = false; + + switch (NewTSK) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + assert(false && "Don't check implicit instantiations here"); + return false; + + case TSK_ExplicitSpecialization: + switch (PrevTSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // Okay, we're just specializing something that is either already + // explicitly specialized or has merely been mentioned without any + // instantiation. + return false; + + case TSK_ImplicitInstantiation: + if (PrevPointOfInstantiation.isInvalid()) { + // The declaration itself has not actually been instantiated, so it is + // still okay to specialize it. + return false; + } + // Fall through + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + assert((PrevTSK == TSK_ImplicitInstantiation || + PrevPointOfInstantiation.isValid()) && + "Explicit instantiation without point of instantiation?"); + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template + // is explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an + // implicit instantiation to take place, in every translation unit in + // which such a use occurs; no diagnostic is required. + S.Diag(NewLoc, diag::err_specialization_after_instantiation) + << PrevDecl; + S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) + << (PrevTSK != TSK_ImplicitInstantiation); + + return true; + } + break; + + case TSK_ExplicitInstantiationDeclaration: + switch (PrevTSK) { + case TSK_ExplicitInstantiationDeclaration: + // This explicit instantiation declaration is redundant (that's okay). + SuppressNew = true; + return false; + + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We're explicitly instantiating something that may have already been + // implicitly instantiated; that's fine. + return false; + + case TSK_ExplicitSpecialization: + // C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit instantiation + // of a template appears after a declaration of an explicit + // specialization for that template, the explicit instantiation has no + // effect. + return false; + + case TSK_ExplicitInstantiationDefinition: + // C++0x [temp.explicit]p10: + // If an entity is the subject of both an explicit instantiation + // declaration and an explicit instantiation definition in the same + // translation unit, the definition shall follow the declaration. + S.Diag(NewLoc, + diag::err_explicit_instantiation_declaration_after_definition); + S.Diag(PrevPointOfInstantiation, + diag::note_explicit_instantiation_definition_here); + assert(PrevPointOfInstantiation.isValid() && + "Explicit instantiation without point of instantiation?"); + SuppressNew = true; + return false; + } + break; + + case TSK_ExplicitInstantiationDefinition: + switch (PrevTSK) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We're explicitly instantiating something that may have already been + // implicitly instantiated; that's fine. + return false; + + case TSK_ExplicitSpecialization: + // C++ DR 259, C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit + // instantiation of a template appears after a declaration of + // an explicit specialization for that template, the explicit + // instantiation has no effect. + // + // In C++98/03 mode, we only give an extension warning here, because it + // is not not harmful to try to explicitly instantiate something that + // has been explicitly specialized. + if (!S.getLangOptions().CPlusPlus0x) { + S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) + << PrevDecl; + S.Diag(PrevDecl->getLocation(), + diag::note_previous_template_specialization); + } + SuppressNew = true; + return false; + + case TSK_ExplicitInstantiationDeclaration: + // We're explicity instantiating a definition for something for which we + // were previously asked to suppress instantiations. That's fine. + return false; + + case TSK_ExplicitInstantiationDefinition: + // C++0x [temp.spec]p5: + // For a given template and a given set of template-arguments, + // - an explicit instantiation definition shall appear at most once + // in a program, + S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate) + << PrevDecl; + S.Diag(PrevPointOfInstantiation, + diag::note_previous_explicit_instantiation); + SuppressNew = true; + return false; + } + break; + } + + assert(false && "Missing specialization/instantiation case?"); + + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -3463,54 +3657,18 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplateSpecializationDecl *Specialization = 0; - bool SpecializationRequiresInstantiation = true; if (PrevDecl) { - if (PrevDecl->getSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { - // This particular specialization has already been declared or - // instantiated. We cannot explicitly instantiate it. - Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate) - << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), - diag::note_previous_explicit_instantiation); + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK, + PrevDecl, + PrevDecl->getSpecializationKind(), + PrevDecl->getPointOfInstantiation(), + SuppressNew)) return DeclPtrTy::make(PrevDecl); - } - - if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { - // C++ DR 259, C++0x [temp.explicit]p4: - // For a given set of template parameters, if an explicit - // instantiation of a template appears after a declaration of - // an explicit specialization for that template, the explicit - // instantiation has no effect. - if (!getLangOptions().CPlusPlus0x) { - Diag(TemplateNameLoc, - diag::ext_explicit_instantiation_after_specialization) - << Context.getTypeDeclType(PrevDecl); - Diag(PrevDecl->getLocation(), - diag::note_previous_template_specialization); - } - // Create a new class template specialization declaration node - // for this explicit specialization. This node is only used to - // record the existence of this explicit instantiation for - // accurate reproduction of the source code; we don't actually - // use it for anything, since it is semantically irrelevant. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, - ClassTemplate->getDeclContext(), - TemplateNameLoc, - ClassTemplate, - Converted, 0); - Specialization->setLexicalDeclContext(CurContext); - CurContext->addDecl(Specialization); + if (SuppressNew) return DeclPtrTy::make(PrevDecl); - } - - // If we have already (implicitly) instantiated this - // specialization, there is less work to do. - if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation) - SpecializationRequiresInstantiation = false; - + if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation || PrevDecl->getSpecializationKind() == TSK_Undeclared) { // Since the only prior class template specialization with these @@ -3521,7 +3679,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; } - } + } if (!Specialization) { // Create a new class template specialization declaration node for @@ -3574,11 +3732,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, // // This check comes when we actually try to perform the // instantiation. - if (SpecializationRequiresInstantiation) + ClassTemplateSpecializationDecl *Def + = cast_or_null<ClassTemplateSpecializationDecl>( + Specialization->getDefinition(Context)); + if (!Def) InstantiateClassTemplateSpecialization(Specialization, TSK); else // Instantiate the members of this class template specialization. - InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization, - TSK); + InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); return DeclPtrTy::make(Specialization); } @@ -3649,17 +3809,46 @@ Sema::ActOnExplicitInstantiation(Scope *S, // // This is C++ DR 275. CheckExplicitInstantiationScope(*this, Record, NameLoc, true); - - if (!Record->getDefinition(Context)) { - // If the class has a definition, instantiate it (and all of its - // members, recursively). - Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); - if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, - getTemplateInstantiationArgs(Record), - TSK)) + + // Verify that it is okay to explicitly instantiate here. + CXXRecordDecl *PrevDecl + = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration()); + if (!PrevDecl && Record->getDefinition(Context)) + PrevDecl = Record; + if (PrevDecl) { + MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); + bool SuppressNew = false; + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, + PrevDecl, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew)) + return true; + if (SuppressNew) + return TagD; + } + + CXXRecordDecl *RecordDef + = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + if (!RecordDef) { + // C++ [temp.explicit]p3: + // A definition of a member class of a class template shall be in scope + // at the point of an explicit instantiation of the member class. + CXXRecordDecl *Def + = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + if (!Def) { + Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) + << 0 << Record->getDeclName() << Record->getDeclContext(); + Diag(Pattern->getLocation(), diag::note_forward_declaration) + << Pattern; + return true; + } else if (InstantiateClass(NameLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) return true; } else // Instantiate all of the members of the class. - InstantiateClassMembers(TemplateLoc, Record, + InstantiateClassMembers(NameLoc, RecordDef, getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of @@ -3775,11 +3964,24 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Check the scope of this explicit instantiation. CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); + // Verify that it is okay to explicitly instantiate here. + MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); + assert(MSInfo && "Missing static data member specialization info?"); + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + Prev, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew)) + return true; + if (SuppressNew) + return DeclPtrTy(); + // Instantiate static data member. - // FIXME: Check for prior specializations and such. - Prev->setTemplateSpecializationKind(TSK); + Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false); + InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false, + /*DefinitionRequired=*/true); // FIXME: Create an ExplicitInstantiation node? return DeclPtrTy(); @@ -3850,8 +4052,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!Specialization) return true; - switch (Specialization->getTemplateSpecializationKind()) { - case TSK_Undeclared: + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) << Specialization @@ -3859,35 +4060,33 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TSK_ExplicitSpecialization); Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here); return true; + } + + FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration(); + if (!PrevDecl && Specialization->isThisDeclarationADefinition()) + PrevDecl = Specialization; - case TSK_ExplicitSpecialization: - // C++ [temp.explicit]p4: - // For a given set of template parameters, if an explicit instantiation - // of a template appears after a declaration of an explicit - // specialization for that template, the explicit instantiation has no - // effect. - break; - - case TSK_ExplicitInstantiationDefinition: - // FIXME: Check that we aren't trying to perform an explicit instantiation - // declaration now. - // Fall through - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - // Instantiate the function, if this is an explicit instantiation - // definition. - if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, - false); - - Specialization->setTemplateSpecializationKind(TSK); - break; + if (PrevDecl) { + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + PrevDecl, + PrevDecl->getTemplateSpecializationKind(), + PrevDecl->getPointOfInstantiation(), + SuppressNew)) + return true; + + // FIXME: We may still want to build some representation of this + // explicit specialization. + if (SuppressNew) + return DeclPtrTy(); } - - // Check the scope of this explicit instantiation. - FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, + false, /*DefinitionRequired=*/true); + + Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + // C++0x [temp.explicit]p2: // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of @@ -3895,6 +4094,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. + FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) @@ -4089,12 +4289,27 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). - QualType TransformTypenameType(const TypenameType *T); + QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL); + QualType TransformTypenameType(TypenameType *T); }; } QualType -CurrentInstantiationRebuilder::TransformTypenameType(const TypenameType *T) { +CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, + TypenameTypeLoc TL) { + QualType Result = TransformTypenameType(TL.getTypePtr()); + if (Result.isNull()) + return QualType(); + + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + +QualType +CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { + NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), /*FIXME:*/SourceRange(getBaseLocation())); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b981389..2a44f83 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -221,7 +221,7 @@ DeduceTemplateArguments(ASTContext &Context, QualType Arg, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(Arg->isCanonical() && "Argument type must be canonical"); + assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. // FIXME: This is untested code; it can be tested when we implement @@ -313,7 +313,7 @@ DeduceTemplateArguments(ASTContext &Context, /// that corresponds to T. Otherwise, returns T. static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, Qualifiers &Quals) { - assert(T->isCanonical() && "Only operates on canonical types"); + assert(T.isCanonical() && "Only operates on canonical types"); if (!isa<ArrayType>(T)) { Quals = T.getQualifiers(); return T.getUnqualifiedType(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 24b8370..53d1580 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -400,6 +400,10 @@ namespace { /// instantiating it. Decl *TransformDefinition(Decl *D); + /// \bried Transform the first qualifier within a scope by instantiating the + /// declaration. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc); + /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, @@ -416,7 +420,8 @@ namespace { /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. - QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T); + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL); }; } @@ -457,6 +462,31 @@ Decl *TemplateInstantiator::TransformDefinition(Decl *D) { return Inst; } +NamedDecl * +TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, + SourceLocation Loc) { + // If the first part of the nested-name-specifier was a template type + // parameter, instantiate that type parameter down to a tag type. + if (TemplateTypeParmDecl *TTPD = dyn_cast_or_null<TemplateTypeParmDecl>(D)) { + const TemplateTypeParmType *TTP + = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD)); + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); + if (T.isNull()) + return cast_or_null<NamedDecl>(TransformDecl(D)); + + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); + + // The resulting type is not a tag; complain. + getSema().Diag(Loc, diag::err_nested_name_spec_non_tag) << T; + return 0; + } + } + + return cast_or_null<NamedDecl>(TransformDecl(D)); +} + VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, @@ -596,8 +626,9 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { } QualType -TemplateInstantiator::TransformTemplateTypeParmType( - const TemplateTypeParmType *T) { +TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL) { + TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding // template argument. @@ -606,25 +637,42 @@ TemplateInstantiator::TransformTemplateTypeParmType( // because we are performing instantiation from explicitly-specified // template arguments in a function template class, but there were some // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) - return QualType(T, 0); + if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) { + TemplateTypeParmTypeLoc NewTL + = TLB.push<TemplateTypeParmTypeLoc>(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - return TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + QualType Replacement + = TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + + // TODO: only do this uniquing once, at the start of instantiation. + QualType Result + = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); + SubstTemplateTypeParmTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } // The template type parameter comes from an inner template (e.g., // the template parameter list of a member template inside the // template we are instantiating). Create a new template type // parameter with the template "level" reduced by one. - return getSema().Context.getTemplateTypeParmType( - T->getDepth() - TemplateArgs.getNumLevels(), - T->getIndex(), - T->isParameterPack(), - T->getName()); + QualType Result + = getSema().Context.getTemplateTypeParmType(T->getDepth() + - TemplateArgs.getNumLevels(), + T->getIndex(), + T->isParameterPack(), + T->getName()); + TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } /// \brief Perform substitution on the type T with a given set of template @@ -654,6 +702,22 @@ TemplateInstantiator::TransformTemplateTypeParmType( /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. +DeclaratorInfo *Sema::SubstType(DeclaratorInfo *T, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (!T->getType()->isDependentType()) + return T; + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + return Instantiator.TransformType(T); +} + +/// Deprecated form of the above. QualType Sema::SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity) { @@ -769,6 +833,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, } Pattern = PatternDef; + // \brief Record the point of instantiation. + if (MemberSpecializationInfo *MSInfo + = Instantiation->getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst) return true; @@ -1007,7 +1078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, TSK_ExplicitSpecialization) continue; - Function->setTemplateSpecializationKind(TSK); + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); } if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) @@ -1018,7 +1089,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) continue; - Var->setTemplateSpecializationKind(TSK); + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 060cc55..be4adbc 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -123,16 +123,17 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Do substitution on the type of the declaration - QualType T = SemaRef.SubstType(D->getType(), TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName()); - if (T.isNull()) + DeclaratorInfo *DI = SemaRef.SubstType(D->getDeclaratorInfo(), + TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (!DI) return 0; // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), - T, D->getDeclaratorInfo(), + DI->getType(), DI, D->getStorageClass()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); @@ -203,11 +204,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; - QualType T = D->getType(); - if (T->isDependentType()) { - T = SemaRef.SubstType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); - if (!T.isNull() && T->isFunctionType()) { + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI->getType()->isDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { + DI = D->getDeclaratorInfo(); + Invalid = true; + } else if (DI->getType()->isFunctionType()) { // C++ [temp.arg.type]p3: // If a declaration acquires a function type through a type // dependent on a template-parameter and this causes a @@ -215,8 +219,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { // function declarator to have function type, the program is // ill-formed. SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) - << T; - T = QualType(); + << DI->getType(); Invalid = true; } } @@ -237,8 +240,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { BitWidth = InstantiatedBitWidth.takeAs<Expr>(); } - FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T, - D->getDeclaratorInfo(), + FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), + DI->getType(), DI, cast<RecordDecl>(Owner), D->getLocation(), D->isMutable(), @@ -1044,9 +1047,14 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where the body of the function is required. Complain if +/// there is no such body. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Function->isInvalidDecl()) return; @@ -1075,8 +1083,24 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); - if (!Pattern) + if (!Pattern) { + if (DefinitionRequired) { + if (Function->getPrimaryTemplate()) + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_func_template) + << Function->getPrimaryTemplate(); + else + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 1 << Function->getDeclName() << Function->getDeclContext(); + + if (PatternDecl) + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); + } + return; + } // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations @@ -1161,10 +1185,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where an out-of-line definition of the member variable +/// is required. Complain if there is no such definition. void Sema::InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Var->isInvalidDecl()) return; @@ -1187,6 +1216,13 @@ void Sema::InstantiateStaticDataMemberDefinition( // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. + if (DefinitionRequired) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 2 << Var->getDeclName() << Var->getDeclContext(); + Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + } + return; } @@ -1225,7 +1261,10 @@ void Sema::InstantiateStaticDataMemberDefinition( if (Var) { Var->setPreviousDeclaration(OldVar); - Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind()); + MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation()); DeclGroupRef DG(Var); Consumer.HandleTopLevelDecl(DG); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9603ca8..49f7119 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/AST/Expr.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" @@ -51,16 +52,14 @@ QualType Sema::adjustParameterType(QualType T) { /// object. /// \param DS the declaration specifiers /// \param DeclLoc The location of the declarator identifier or invalid if none. -/// \param SourceTy QualType representing the type as written in source form. /// \returns The type described by the declaration specifiers. This function /// never returns null. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &isInvalid, QualType &SourceTy) { + bool &isInvalid) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; - SourceTy = Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: @@ -105,9 +104,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - SourceTy = Context.getObjCProtocolListType(QualType(), - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); @@ -225,9 +221,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - SourceTy = Context.getObjCProtocolListType(Result, - (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); if (const ObjCInterfaceType * Interface = Result->getAs<ObjCInterfaceType>()) { // It would be nice if protocol qualifiers were only stored with the @@ -384,8 +377,6 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getQualifiedType(Result, Quals); } - if (SourceTy.isNull()) - SourceTy = Result; return Result; } @@ -449,36 +440,32 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, /// /// \returns A suitable reference type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, - SourceLocation Loc, DeclarationName Entity) { +QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, + unsigned CVR, SourceLocation Loc, + DeclarationName Entity) { Qualifiers Quals = Qualifiers::fromCVRMask(CVR); - if (LValueRef) { - if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) { - // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a - // reference to a type T, and attempt to create the type "lvalue - // reference to cv TD" creates the type "lvalue reference to T". - // We use the qualifiers (restrict or none) of the original reference, - // not the new ones. This is consistent with GCC. - QualType LVRT = Context.getLValueReferenceType(R->getPointeeType()); - return Context.getQualifiedType(LVRT, T.getQualifiers()); - } - } - if (T->isReferenceType()) { - // C++ [dcl.ref]p4: There shall be no references to references. - // - // According to C++ DR 106, references to references are only - // diagnosed when they are written directly (e.g., "int & &"), - // but not when they happen via a typedef: - // - // typedef int& intref; - // typedef intref& intref2; - // - // Parser::ParseDeclaratorInternal diagnoses the case where - // references are written directly; here, we handle the - // collapsing of references-to-references as described in C++ - // DR 106 and amended by C++ DR 540. - return T; - } + + bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>(); + + // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a + // reference to a type T, and attempt to create the type "lvalue + // reference to cv TD" creates the type "lvalue reference to T". + // We use the qualifiers (restrict or none) of the original reference, + // not the new ones. This is consistent with GCC. + + // C++ [dcl.ref]p4: There shall be no references to references. + // + // According to C++ DR 106, references to references are only + // diagnosed when they are written directly (e.g., "int & &"), + // but not when they happen via a typedef: + // + // typedef int& intref; + // typedef intref& intref2; + // + // Parser::ParseDeclaratorInternal diagnoses the case where + // references are written directly; here, we handle the + // collapsing of references-to-references as described in C++ + // DR 106 and amended by C++ DR 540. // C++ [dcl.ref]p1: // A declarator that specifies the type "reference to cv void" @@ -510,7 +497,8 @@ QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, // Handle restrict on references. if (LValueRef) - return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals); + return Context.getQualifiedType( + Context.getLValueReferenceType(T, SpelledAsLValue), Quals); return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals); } @@ -610,8 +598,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, << ArraySize->getSourceRange(); } } - T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize, - ASM, Quals, Brackets); + T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { @@ -717,7 +704,7 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } - ParamTypes[Idx] = adjustFunctionParamType(ParamType); + ParamTypes[Idx] = ParamType; } if (Invalid) @@ -856,9 +843,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - // The QualType referring to the type as written in source code. We can't use - // T because it can change due to semantic analysis. - QualType SourceTy; switch (D.getKind()) { case Declarator::DK_Abstract: @@ -872,7 +856,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.DependentTy; } else { bool isInvalid = false; - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy); + T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); if (isInvalid) D.setInvalidType(true); else if (OwnedDecl && DS.isTypeSpecOwned()) @@ -891,9 +875,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } - if (SourceTy.isNull()) - SourceTy = T; - if (T == Context.UndeducedAutoTy) { int Error = -1; @@ -942,8 +923,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); - bool ShouldBuildInfo = DInfo != 0; - // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -952,17 +931,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: - if (ShouldBuildInfo) { - if (SourceTy->isFunctionType()) - SourceTy - = Context.getQualifiedType(Context.getBlockPointerType(SourceTy), - Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals)); - else - // If not function type Context::getBlockPointerType asserts, - // so just give up. - ShouldBuildInfo = false; - } - // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); @@ -971,10 +939,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Name); break; case DeclaratorChunk::Pointer: - //FIXME: Use ObjCObjectPointer for info when appropriate. - if (ShouldBuildInfo) - SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy), - Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals)); // Verify that we're not building a pointer to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -995,14 +959,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Qualifiers Quals; if (DeclType.Ref.HasRestrict) Quals.addRestrict(); - if (ShouldBuildInfo) { - if (DeclType.Ref.LValueRef) - SourceTy = Context.getLValueReferenceType(SourceTy); - else - SourceTy = Context.getRValueReferenceType(SourceTy); - SourceTy = Context.getQualifiedType(SourceTy, Quals); - } - // Verify that we're not building a reference to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -1015,11 +971,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } case DeclaratorChunk::Array: { - if (ShouldBuildInfo) - // We just need to get an array type, the exact type doesn't matter. - SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal, - DeclType.Arr.TypeQuals); - // Verify that we're not building an array of pointers to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -1051,24 +1002,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } case DeclaratorChunk::Function: { - if (ShouldBuildInfo) { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - llvm::SmallVector<QualType, 16> ArgTys; - - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); - if (Param) { - QualType ArgTy = adjustFunctionParamType(Param->getType()); - - ArgTys.push_back(ArgTy); - } - } - SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(), - ArgTys.size(), - FTI.isVariadic, - FTI.TypeQuals); - } - // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). @@ -1137,6 +1070,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } else if (FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + D.setInvalidType(true); } else { // Otherwise, we have a function with an argument list that is // potentially variadic. @@ -1185,7 +1119,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - ArgTys.push_back(adjustFunctionParamType(ArgTy)); + ArgTys.push_back(ArgTy); } llvm::SmallVector<QualType, 4> Exceptions; @@ -1234,13 +1168,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, D.setInvalidType(true); } - if (ShouldBuildInfo) { - QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy; - SourceTy = Context.getQualifiedType( - Context.getMemberPointerType(SourceTy, cls.getTypePtr()), - Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals)); - } - if (!ClsType.isNull()) T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals, DeclType.Loc, D.getIdentifier()); @@ -1293,106 +1220,162 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); - if (ShouldBuildInfo) - *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip); + if (DInfo) { + if (D.isInvalidType()) + *DInfo = 0; + else + *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip); + } return T; } -static void FillTypeSpecLoc(TypeLoc TSL, const DeclSpec &DS) { - if (TSL.isNull()) return; +namespace { + class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { + const DeclSpec &DS; - if (TypedefLoc *TL = dyn_cast<TypedefLoc>(&TSL)) { - TL->setNameLoc(DS.getTypeSpecTypeLoc()); + public: + TypeSpecLocFiller(const DeclSpec &DS) : DS(DS) {} - } else if (ObjCInterfaceLoc *TL = dyn_cast<ObjCInterfaceLoc>(&TSL)) { - TL->setNameLoc(DS.getTypeSpecTypeLoc()); + void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + Visit(TL.getUnqualifiedLoc()); + } + void VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + + if (DS.getProtocolQualifiers()) { + assert(TL.getNumProtocols() > 0); + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); + TL.setLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setRAngleLoc(DS.getSourceRange().getEnd()); + for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) + TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); + } else { + assert(TL.getNumProtocols() == 0); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); + } + } + void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - } else if (ObjCProtocolListLoc *PLL = dyn_cast<ObjCProtocolListLoc>(&TSL)) { - assert(PLL->getNumProtocols() == DS.getNumProtocolQualifiers()); - PLL->setLAngleLoc(DS.getProtocolLAngleLoc()); - PLL->setRAngleLoc(DS.getSourceRange().getEnd()); - for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i) - PLL->setProtocolLoc(i, DS.getProtocolLocs()[i]); - FillTypeSpecLoc(PLL->getBaseTypeLoc(), DS); + TL.setStarLoc(SourceLocation()); - } else { - //FIXME: Other typespecs. - DefaultTypeSpecLoc &DTL = cast<DefaultTypeSpecLoc>(TSL); - DTL.setStartLoc(DS.getSourceRange().getBegin()); - } -} + if (DS.getProtocolQualifiers()) { + assert(TL.getNumProtocols() > 0); + assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); + TL.setHasProtocolsAsWritten(true); + TL.setLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setRAngleLoc(DS.getSourceRange().getEnd()); + for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) + TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); -/// \brief Create and instantiate a DeclaratorInfo with type source information. -/// -/// \param T QualType referring to the type as written in source code. -DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { - DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); - TypeLoc CurrTL = DInfo->getTypeLoc(); + } else { + assert(TL.getNumProtocols() == 0); + TL.setHasProtocolsAsWritten(false); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); + } - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { - assert(!CurrTL.isNull()); - - // Don't bother recording source locations for qualifiers. - CurrTL = CurrTL.getUnqualifiedLoc(); + // This might not have been written with an inner type. + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { + TL.setHasBaseTypeAsWritten(false); + TL.getBaseTypeLoc().initialize(SourceLocation()); + } else { + TL.setHasBaseTypeAsWritten(true); + Visit(TL.getBaseTypeLoc()); + } + } + void VisitTypeLoc(TypeLoc TL) { + // FIXME: add other typespec types and change this to an assert. + TL.initialize(DS.getTypeSpecTypeLoc()); + } + }; - DeclaratorChunk &DeclType = D.getTypeObject(i); - switch (DeclType.Kind) { - default: assert(0 && "Unknown decltype!"); - case DeclaratorChunk::BlockPointer: { - BlockPointerLoc &BPL = cast<BlockPointerLoc>(CurrTL); - BPL.setCaretLoc(DeclType.Loc); - break; + class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> { + const DeclaratorChunk &Chunk; + + public: + DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {} + + void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + llvm::llvm_unreachable("qualified type locs not expected here!"); } - case DeclaratorChunk::Pointer: { - //FIXME: ObjCObject pointers. - PointerLoc &PL = cast<PointerLoc>(CurrTL); - PL.setStarLoc(DeclType.Loc); - break; + + void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::BlockPointer); + TL.setCaretLoc(Chunk.Loc); } - case DeclaratorChunk::Reference: { - ReferenceLoc &RL = cast<ReferenceLoc>(CurrTL); - RL.setAmpLoc(DeclType.Loc); - break; + void VisitPointerTypeLoc(PointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pointer); + TL.setStarLoc(Chunk.Loc); } - case DeclaratorChunk::Array: { - DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; - ArrayLoc &AL = cast<ArrayLoc>(CurrTL); - AL.setLBracketLoc(DeclType.Loc); - AL.setRBracketLoc(DeclType.EndLoc); - AL.setSizeExpr(static_cast<Expr*>(ATI.NumElts)); - //FIXME: Star location for [*]. - break; + void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pointer); + TL.setStarLoc(Chunk.Loc); + TL.setHasBaseTypeAsWritten(true); + TL.setHasProtocolsAsWritten(false); + TL.setLAngleLoc(SourceLocation()); + TL.setRAngleLoc(SourceLocation()); } - case DeclaratorChunk::Function: { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - FunctionLoc &FL = cast<FunctionLoc>(CurrTL); - FL.setLParenLoc(DeclType.Loc); - FL.setRParenLoc(DeclType.EndLoc); - for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) { + void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::MemberPointer); + TL.setStarLoc(Chunk.Loc); + // FIXME: nested name specifier + } + void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Reference); + // 'Amp' is misleading: this might have been originally + /// spelled with AmpAmp. + TL.setAmpLoc(Chunk.Loc); + } + void VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Reference); + assert(!Chunk.Ref.LValueRef); + TL.setAmpAmpLoc(Chunk.Loc); + } + void VisitArrayTypeLoc(ArrayTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Array); + TL.setLBracketLoc(Chunk.Loc); + TL.setRBracketLoc(Chunk.EndLoc); + TL.setSizeExpr(static_cast<Expr*>(Chunk.Arr.NumElts)); + } + void VisitFunctionTypeLoc(FunctionTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Function); + TL.setLParenLoc(Chunk.Loc); + TL.setRParenLoc(Chunk.EndLoc); + + const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; + for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>(); - if (Param) { - assert(tpi < FL.getNumArgs()); - FL.setArg(tpi++, Param); - } + TL.setArg(tpi++, Param); } - break; - //FIXME: Exception specs. - } - case DeclaratorChunk::MemberPointer: { - MemberPointerLoc &MPL = cast<MemberPointerLoc>(CurrTL); - MPL.setStarLoc(DeclType.Loc); - //FIXME: Class location. - break; + // FIXME: exception specs } + void VisitTypeLoc(TypeLoc TL) { + llvm::llvm_unreachable("unsupported TypeLoc kind in declarator!"); } + }; +} + +/// \brief Create and instantiate a DeclaratorInfo with type source information. +/// +/// \param T QualType referring to the type as written in source code. +DeclaratorInfo * +Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { + DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); + UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); - CurrTL = CurrTL.getNextTypeLoc(); + for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } - FillTypeSpecLoc(CurrTL, D.getDeclSpec()); + TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); return DInfo; } @@ -1655,6 +1638,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, PartialDiagnostic> Note) { unsigned diag = PD.getDiagID(); + // FIXME: Add this assertion to make sure we always get instantiation points. + // assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType"); // FIXME: Add this assertion to help us flush out problems with // checking for dependent types and type-dependent expressions. // diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ec5c667..7e0972f 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1,4 +1,4 @@ -//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/ +//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===/ // // The LLVM Compiler Infrastructure // @@ -22,9 +22,11 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/TypeLocBuilder.h" #include "clang/Parse/Ownership.h" #include "clang/Parse/Designator.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> namespace clang { @@ -170,25 +172,30 @@ public: /// \brief Transforms the given type into another type. /// - /// By default, this routine transforms a type by delegating to the - /// appropriate TransformXXXType to build a new type, then applying - /// the qualifiers on \p T to the resulting type with AddTypeQualifiers. - /// Subclasses may override this function (to take over all type - /// transformations), some set of the TransformXXXType functions, or - /// the AddTypeQualifiers function to alter the transformation. + /// By default, this routine transforms a type by creating a + /// DeclaratorInfo for it and delegating to the appropriate + /// function. This is expensive, but we don't mind, because + /// this method is deprecated anyway; all users should be + /// switched to storing DeclaratorInfos. /// /// \returns the transformed type. QualType TransformType(QualType T); - /// \brief Transform the given type by adding the given set of qualifiers - /// and returning the result. + /// \brief Transforms the given type-with-location into a new + /// type-with-location. + /// + /// By default, this routine transforms a type by delegating to the + /// appropriate TransformXXXType to build a new type. Subclasses + /// may override this function (to take over all type + /// transformations) or some set of the TransformXXXType functions + /// to alter the transformation. + DeclaratorInfo *TransformType(DeclaratorInfo *DI); + + /// \brief Transform the given type-with-location into a new + /// type, collecting location information in the given builder + /// as necessary. /// - /// FIXME: By default, this routine adds type qualifiers only to types that - /// can have qualifiers, and silently suppresses those qualifiers that are - /// not permitted (e.g., qualifiers on reference or function types). This - /// is the right thing for template instantiation, but probably not for - /// other clients. - QualType AddTypeQualifiers(QualType T, Qualifiers Qs); + QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); /// \brief Transform the given statement. /// @@ -236,6 +243,19 @@ public: /// Subclasses may override this function to provide alternate behavior. Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); } + /// \brief Transform the given declaration, which was the first part of a + /// nested-name-specifier in a member access expression. + /// + /// This specific declaration transformation only applies to the first + /// identifier in a nested-name-specifier of a member access expression, e.g., + /// the \c T in \c x->T::member + /// + /// By default, invokes TransformDecl() to transform the declaration. + /// Subclasses may override this function to provide alternate behavior. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) { + return cast_or_null<NamedDecl>(getDerived().TransformDecl(D)); + } + /// \brief Transform the given nested-name-specifier. /// /// By default, transforms all of the types and declarations within the @@ -253,7 +273,8 @@ public: /// Identifiers and selectors are returned unmodified. Sublcasses may /// override this function to provide alternate behavior. DeclarationName TransformDeclarationName(DeclarationName Name, - SourceLocation Loc); + SourceLocation Loc, + QualType ObjectType = QualType()); /// \brief Transform the given template name. /// @@ -271,11 +292,15 @@ public: /// override this function to provide alternate behavior. TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); -#define ABSTRACT_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) \ - QualType Transform##CLASS##Type(const CLASS##Type *T); -#include "clang/AST/TypeNodes.def" +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); +#include "clang/AST/TypeLocNodes.def" + QualType + TransformTemplateSpecializationType(const TemplateSpecializationType *T, + QualType ObjectType); + OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ @@ -316,6 +341,9 @@ public: /// type. Subclasses may override this routine to provide different behavior. QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + /// \brief Build a new Objective C object pointer type. + QualType RebuildObjCObjectPointerType(QualType PointeeType); + /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -340,29 +368,6 @@ public: const llvm::APInt &Size, unsigned IndexTypeQuals); - /// \brief Build a new constant array type given the element type, size - /// modifier, (known) size of the array, size expression, and index type - /// qualifiers. - /// - /// By default, performs semantic analysis when building the array type. - /// Subclasses may override this routine to provide different behavior. - QualType RebuildConstantArrayWithExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange); - - /// \brief Build a new constant array type given the element type, size - /// modifier, (known) size of the array, and index type qualifiers. - /// - /// By default, performs semantic analysis when building the array type. - /// Subclasses may override this routine to provide different behavior. - QualType RebuildConstantArrayWithoutExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - unsigned IndexTypeQuals); - /// \brief Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. /// @@ -427,6 +432,9 @@ public: unsigned NumParamTypes, bool Variadic, unsigned Quals); + /// \brief Build a new unprototyped function type. + QualType RebuildFunctionNoProtoType(QualType ResultType); + /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -1429,13 +1437,16 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildTemplateIdExpr(TemplateName Template, + OwningExprResult RebuildTemplateIdExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { - return getSema().BuildTemplateIdExpr(Template, TemplateLoc, + return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange, + Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc); @@ -1757,7 +1768,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, template<typename Derived> DeclarationName TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, + QualType ObjectType) { if (!Name) return Name; @@ -1774,7 +1786,14 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TemporaryBase Rebase(*this, Loc, Name); - QualType T = getDerived().TransformType(Name.getCXXNameType()); + QualType T; + if (!ObjectType.isNull() && + isa<TemplateSpecializationType>(Name.getCXXNameType())) { + TemplateSpecializationType *SpecType + = cast<TemplateSpecializationType>(Name.getCXXNameType()); + T = TransformTemplateSpecializationType(SpecType, ObjectType); + } else + T = getDerived().TransformType(Name.getCXXNameType()); if (T.isNull()) return DeclarationName(); @@ -1837,7 +1856,8 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, return TemplateName(); if (!getDerived().AlwaysRebuild() && - NNS == DTN->getQualifier()) + NNS == DTN->getQualifier() && + ObjectType.isNull()) return Name; return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); @@ -1935,268 +1955,369 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { if (getDerived().AlreadyTransformed(T)) return T; - QualifierCollector Qs; - const Type *Ty = Qs.strip(T); + // Temporary workaround. All of these transformations should + // eventually turn into transformations on TypeLocs. + DeclaratorInfo *DI = getSema().Context.CreateDeclaratorInfo(T); + DI->getTypeLoc().initialize(getDerived().getBaseLocation()); + + DeclaratorInfo *NewDI = getDerived().TransformType(DI); - QualType Result; - switch (Ty->getTypeClass()) { -#define ABSTRACT_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - Result = getDerived().Transform##CLASS##Type( \ - static_cast<const CLASS##Type*>(Ty)); \ - break; -#include "clang/AST/TypeNodes.def" - } - - if (Result.isNull() || T == Result) - return Result; + if (!NewDI) + return QualType(); - return getDerived().AddTypeQualifiers(Result, Qs); + return NewDI->getType(); } template<typename Derived> -QualType -TreeTransform<Derived>::AddTypeQualifiers(QualType T, Qualifiers Quals) { - if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType()) - return SemaRef.Context.getQualifiedType(T, Quals); +DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) { + if (getDerived().AlreadyTransformed(DI->getType())) + return DI; - return T; -} + TypeLocBuilder TLB; -template<typename Derived> -QualType TreeTransform<Derived>::TransformBuiltinType(const BuiltinType *T) { - // Nothing to do - return QualType(T, 0); -} + TypeLoc TL = DI->getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); -template<typename Derived> -QualType TreeTransform<Derived>::TransformFixedWidthIntType( - const FixedWidthIntType *T) { - // FIXME: Implement - return QualType(T, 0); -} + QualType Result = getDerived().TransformType(TLB, TL); + if (Result.isNull()) + return 0; -template<typename Derived> -QualType TreeTransform<Derived>::TransformComplexType(const ComplexType *T) { - // FIXME: Implement - return QualType(T, 0); + return TLB.getDeclaratorInfo(SemaRef.Context, Result); } template<typename Derived> -QualType TreeTransform<Derived>::TransformPointerType(const PointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { + switch (T.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: \ + return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T)); +#include "clang/AST/TypeLocNodes.def" + } - return getDerived().RebuildPointerType(PointeeType); + llvm::llvm_unreachable("unhandled type loc!"); + return QualType(); } +/// FIXME: By default, this routine adds type qualifiers only to types +/// that can have qualifiers, and silently suppresses those qualifiers +/// that are not permitted (e.g., qualifiers on reference or function +/// types). This is the right thing for template instantiation, but +/// probably not for other clients. template<typename Derived> QualType -TreeTransform<Derived>::TransformBlockPointerType(const BlockPointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) +TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, + QualifiedTypeLoc T) { + Qualifiers Quals = T.getType().getQualifiers(); + + QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + if (Result.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); + // Silently suppress qualifiers if the result type can't be qualified. + // FIXME: this is the right thing for template instantiation, but + // probably not for other clients. + if (Result->isFunctionType() || Result->isReferenceType()) + return Result; - return getDerived().RebuildBlockPointerType(PointeeType); + Result = SemaRef.Context.getQualifiedType(Result, Quals); + + TLB.push<QualifiedTypeLoc>(Result); + + // No location information to preserve. + + return Result; +} + +template <class TyLoc> static inline +QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { + TyLoc NewT = TLB.push<TyLoc>(T.getType()); + NewT.setNameLoc(T.getNameLoc()); + return T.getType(); +} + +// Ugly metaprogramming macros because I couldn't be bothered to make +// the equivalent template version work. +#define TransformPointerLikeType(TypeClass) do { \ + QualType PointeeType \ + = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ + if (PointeeType.isNull()) \ + return QualType(); \ + \ + QualType Result = TL.getType(); \ + if (getDerived().AlwaysRebuild() || \ + PointeeType != TL.getPointeeLoc().getType()) { \ + Result = getDerived().Rebuild##TypeClass(PointeeType); \ + if (Result.isNull()) \ + return QualType(); \ + } \ + \ + TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \ + NewT.setSigilLoc(TL.getSigilLoc()); \ + \ + return Result; \ +} while(0) + +// Reference collapsing forces us to transform reference types +// differently from the other pointer-like types. +#define TransformReferenceType(TypeClass) do { \ + QualType PointeeType \ + = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ + if (PointeeType.isNull()) \ + return QualType(); \ + \ + QualType Result = TL.getType(); \ + if (getDerived().AlwaysRebuild() || \ + PointeeType != TL.getPointeeLoc().getType()) { \ + Result = getDerived().Rebuild##TypeClass(PointeeType); \ + if (Result.isNull()) \ + return QualType(); \ + } \ + \ + /* Workaround: rebuild doesn't always change the type */ \ + /* FIXME: avoid losing this location information. */ \ + if (Result == PointeeType) \ + return Result; \ + ReferenceTypeLoc NewTL; \ + if (isa<LValueReferenceType>(Result)) \ + NewTL = TLB.push<LValueReferenceTypeLoc>(Result); \ + else \ + NewTL = TLB.push<RValueReferenceTypeLoc>(Result); \ + NewTL.setSigilLoc(TL.getSigilLoc()); \ + return Result; \ +} while (0) + +template<typename Derived> +QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, + BuiltinTypeLoc T) { + return TransformTypeSpecType(TLB, T); } template<typename Derived> QualType -TreeTransform<Derived>::TransformLValueReferenceType( - const LValueReferenceType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); +TreeTransform<Derived>::TransformFixedWidthIntType(TypeLocBuilder &TLB, + FixedWidthIntTypeLoc T) { + return TransformTypeSpecType(TLB, T); +} - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); +template<typename Derived> +QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, + ComplexTypeLoc T) { + // FIXME: recurse? + return TransformTypeSpecType(TLB, T); +} - return getDerived().RebuildLValueReferenceType(PointeeType); +template<typename Derived> +QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, + PointerTypeLoc TL) { + TransformPointerLikeType(PointerType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformRValueReferenceType( - const RValueReferenceType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType()) - return QualType(T, 0); - - return getDerived().RebuildRValueReferenceType(PointeeType); +TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, + BlockPointerTypeLoc TL) { + TransformPointerLikeType(BlockPointerType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformMemberPointerType(const MemberPointerType *T) { - QualType PointeeType = getDerived().TransformType(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0)); - if (ClassType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - PointeeType == T->getPointeeType() && - ClassType == QualType(T->getClass(), 0)) - return QualType(T, 0); - - return getDerived().RebuildMemberPointerType(PointeeType, ClassType); +TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, + LValueReferenceTypeLoc TL) { + TransformReferenceType(LValueReferenceType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayType(const ConstantArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); - if (ElementType.isNull()) - return QualType(); - - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); - - return getDerived().RebuildConstantArrayType(ElementType, - T->getSizeModifier(), - T->getSize(), - T->getIndexTypeCVRQualifiers()); +TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, + RValueReferenceTypeLoc TL) { + TransformReferenceType(RValueReferenceType); } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayWithExprType( - const ConstantArrayWithExprType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); - if (ElementType.isNull()) - return QualType(); +TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, + MemberPointerTypeLoc TL) { + MemberPointerType *T = TL.getTypePtr(); - // Array bounds are not potentially evaluated contexts - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + // TODO: preserve source information for this. + QualType ClassType + = getDerived().TransformType(QualType(T->getClass(), 0)); + if (ClassType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != T->getPointeeType() || + ClassType != QualType(T->getClass(), 0)) { + Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType); + if (Result.isNull()) + return QualType(); + } - return getDerived().RebuildConstantArrayWithExprType(ElementType, - T->getSizeModifier(), - T->getSize(), - Size.takeAs<Expr>(), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result); + NewTL.setSigilLoc(TL.getSigilLoc()); + + return Result; } template<typename Derived> QualType -TreeTransform<Derived>::TransformConstantArrayWithoutExprType( - const ConstantArrayWithoutExprType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, + ConstantArrayTypeLoc TL) { + ConstantArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); - - return getDerived().RebuildConstantArrayWithoutExprType(ElementType, - T->getSizeModifier(), - T->getSize(), + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildConstantArrayType(ElementType, + T->getSizeModifier(), + T->getSize(), T->getIndexTypeCVRQualifiers()); + if (Result.isNull()) + return QualType(); + } + + ConstantArrayTypeLoc NewTL = TLB.push<ConstantArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + + Expr *Size = TL.getSizeExpr(); + if (Size) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + Size = getDerived().TransformExpr(Size).template takeAs<Expr>(); + } + NewTL.setSizeExpr(Size); + + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformIncompleteArrayType( - const IncompleteArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); + TypeLocBuilder &TLB, + IncompleteArrayTypeLoc TL) { + IncompleteArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildIncompleteArrayType(ElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + if (Result.isNull()) + return QualType(); + } + + IncompleteArrayTypeLoc NewTL = TLB.push<IncompleteArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(0); - return getDerived().RebuildIncompleteArrayType(ElementType, - T->getSizeModifier(), - T->getIndexTypeCVRQualifiers()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformVariableArrayType( - const VariableArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +QualType +TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, + VariableArrayTypeLoc TL) { + VariableArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + Sema::OwningExprResult SizeResult + = getDerived().TransformExpr(T->getSizeExpr()); + if (SizeResult.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); + Expr *Size = static_cast<Expr*>(SizeResult.get()); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType() || + Size != T->getSizeExpr()) { + Result = getDerived().RebuildVariableArrayType(ElementType, + T->getSizeModifier(), + move(SizeResult), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + if (Result.isNull()) + return QualType(); } + else SizeResult.take(); + + VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(Size); - return getDerived().RebuildVariableArrayType(ElementType, - T->getSizeModifier(), - move(Size), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformDependentSizedArrayType( - const DependentSizedArrayType *T) { - QualType ElementType = getDerived().TransformType(T->getElementType()); +QualType +TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, + DependentSizedArrayTypeLoc TL) { + DependentSizedArrayType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); - if (Size.isInvalid()) + Sema::OwningExprResult SizeResult + = getDerived().TransformExpr(T->getSizeExpr()); + if (SizeResult.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); + Expr *Size = static_cast<Expr*>(SizeResult.get()); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType() || + Size != T->getSizeExpr()) { + Result = getDerived().RebuildDependentSizedArrayType(ElementType, + T->getSizeModifier(), + move(SizeResult), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + if (Result.isNull()) + return QualType(); } + else SizeResult.take(); - return getDerived().RebuildDependentSizedArrayType(ElementType, - T->getSizeModifier(), - move(Size), - T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + // We might have any sort of array type now, but fortunately they + // all have the same location layout. + ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(Size); + + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { + TypeLocBuilder &TLB, + DependentSizedExtVectorTypeLoc TL) { + DependentSizedExtVectorType *T = TL.getTypePtr(); + + // FIXME: ext vector locs should be nested QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); @@ -2208,98 +2329,201 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( if (Size.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType() && - Size.get() == T->getSizeExpr()) { - Size.take(); - return QualType(T, 0); - } - - return getDerived().RebuildDependentSizedExtVectorType(ElementType, + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + (ElementType != T->getElementType() && Size.get() != T->getSizeExpr())) { + Result = getDerived().RebuildDependentSizedExtVectorType(ElementType, move(Size), T->getAttributeLoc()); + if (Result.isNull()) + return QualType(); + } + else Size.take(); + + // Result might be dependent or not. + if (isa<DependentSizedExtVectorType>(Result)) { + DependentSizedExtVectorTypeLoc NewTL + = TLB.push<DependentSizedExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } else { + ExtVectorTypeLoc NewTL = TLB.push<ExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformVectorType(const VectorType *T) { +QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, + VectorTypeLoc TL) { + VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildVectorType(ElementType, T->getNumElements()); + if (Result.isNull()) + return QualType(); + } + + VectorTypeLoc NewTL = TLB.push<VectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildVectorType(ElementType, T->getNumElements()); + return Result; } template<typename Derived> -QualType -TreeTransform<Derived>::TransformExtVectorType(const ExtVectorType *T) { +QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, + ExtVectorTypeLoc TL) { + VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - ElementType == T->getElementType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ElementType != T->getElementType()) { + Result = getDerived().RebuildExtVectorType(ElementType, + T->getNumElements(), + /*FIXME*/ SourceLocation()); + if (Result.isNull()) + return QualType(); + } + + ExtVectorTypeLoc NewTL = TLB.push<ExtVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(), - /*FIXME*/SourceLocation()); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformFunctionProtoType( - const FunctionProtoType *T) { - QualType ResultType = getDerived().TransformType(T->getResultType()); +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL) { + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) return QualType(); + // Transform the parameters. llvm::SmallVector<QualType, 4> ParamTypes; - for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), - ParamEnd = T->arg_type_end(); - Param != ParamEnd; ++Param) { - QualType P = getDerived().TransformType(*Param); - if (P.isNull()) - return QualType(); + llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + ParmVarDecl *OldParm = TL.getArg(i); + + QualType NewType; + ParmVarDecl *NewParm; + + if (OldParm) { + DeclaratorInfo *OldDI = OldParm->getDeclaratorInfo(); + assert(OldDI->getType() == T->getArgType(i)); + + DeclaratorInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return QualType(); + + if (NewDI == OldDI) + NewParm = OldParm; + else + NewParm = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); + NewType = NewParm->getType(); + + // Deal with the possibility that we don't have a parameter + // declaration for this parameter. + } else { + NewParm = 0; + + QualType OldType = T->getArgType(i); + NewType = getDerived().TransformType(OldType); + if (NewType.isNull()) + return QualType(); + } - ParamTypes.push_back(P); + ParamTypes.push_back(NewType); + ParamDecls.push_back(NewParm); } - if (!getDerived().AlwaysRebuild() && - ResultType == T->getResultType() && - std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ResultType != T->getResultType() || + !std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) { + Result = getDerived().RebuildFunctionProtoType(ResultType, + ParamTypes.data(), + ParamTypes.size(), + T->isVariadic(), + T->getTypeQuals()); + if (Result.isNull()) + return QualType(); + } + + FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) + NewTL.setArg(i, ParamDecls[i]); - return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(), - ParamTypes.size(), T->isVariadic(), - T->getTypeQuals()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( - const FunctionNoProtoType *T) { - // FIXME: Implement - return QualType(T, 0); + TypeLocBuilder &TLB, + FunctionNoProtoTypeLoc TL) { + FunctionNoProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ResultType != T->getResultType()) + Result = getDerived().RebuildFunctionNoProtoType(ResultType); + + FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypedefType(const TypedefType *T) { +QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, + TypedefTypeLoc TL) { + TypedefType *T = TL.getTypePtr(); TypedefDecl *Typedef = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl())); if (!Typedef) return QualType(); - if (!getDerived().AlwaysRebuild() && - Typedef == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Typedef != T->getDecl()) { + Result = getDerived().RebuildTypedefType(Typedef); + if (Result.isNull()) + return QualType(); + } + + TypedefTypeLoc NewTL = TLB.push<TypedefTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildTypedefType(Typedef); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypeOfExprType( - const TypeOfExprType *T) { +QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, + TypeOfExprTypeLoc TL) { + TypeOfExprType *T = TL.getTypePtr(); + // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2307,30 +2531,50 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType( if (E.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - E.get() == T->getUnderlyingExpr()) { - E.take(); - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + E.get() != T->getUnderlyingExpr()) { + Result = getDerived().RebuildTypeOfExprType(move(E)); + if (Result.isNull()) + return QualType(); } + else E.take(); - return getDerived().RebuildTypeOfExprType(move(E)); + TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypeOfType(const TypeOfType *T) { +QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, + TypeOfTypeLoc TL) { + TypeOfType *T = TL.getTypePtr(); + + // FIXME: should be an inner type, or at least have a DeclaratorInfo. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - Underlying == T->getUnderlyingType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Underlying != T->getUnderlyingType()) { + Result = getDerived().RebuildTypeOfType(Underlying); + if (Result.isNull()) + return QualType(); + } - return getDerived().RebuildTypeOfType(Underlying); + TypeOfTypeLoc NewTL = TLB.push<TypeOfTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) { +QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, + DecltypeTypeLoc TL) { + DecltypeType *T = TL.getTypePtr(); + // decltype expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2338,70 +2582,130 @@ QualType TreeTransform<Derived>::TransformDecltypeType(const DecltypeType *T) { if (E.isInvalid()) return QualType(); - if (!getDerived().AlwaysRebuild() && - E.get() == T->getUnderlyingExpr()) { - E.take(); - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + E.get() != T->getUnderlyingExpr()) { + Result = getDerived().RebuildDecltypeType(move(E)); + if (Result.isNull()) + return QualType(); } + else E.take(); - return getDerived().RebuildDecltypeType(move(E)); + DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformRecordType(const RecordType *T) { +QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, + RecordTypeLoc TL) { + RecordType *T = TL.getTypePtr(); RecordDecl *Record - = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); if (!Record) return QualType(); - if (!getDerived().AlwaysRebuild() && - Record == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Record != T->getDecl()) { + Result = getDerived().RebuildRecordType(Record); + if (Result.isNull()) + return QualType(); + } + + RecordTypeLoc NewTL = TLB.push<RecordTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildRecordType(Record); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformEnumType(const EnumType *T) { +QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, + EnumTypeLoc TL) { + EnumType *T = TL.getTypePtr(); EnumDecl *Enum - = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); if (!Enum) return QualType(); - if (!getDerived().AlwaysRebuild() && - Enum == T->getDecl()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Enum != T->getDecl()) { + Result = getDerived().RebuildEnumType(Enum); + if (Result.isNull()) + return QualType(); + } + + EnumTypeLoc NewTL = TLB.push<EnumTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildEnumType(Enum); + return Result; } template <typename Derived> -QualType TreeTransform<Derived>::TransformElaboratedType( - const ElaboratedType *T) { +QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, + ElaboratedTypeLoc TL) { + ElaboratedType *T = TL.getTypePtr(); + + // FIXME: this should be a nested type. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - Underlying == T->getUnderlyingType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + Underlying != T->getUnderlyingType()) { + Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); + if (Result.isNull()) + return QualType(); + } + + ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildElaboratedType(Underlying, T->getTagKind()); + return Result; } template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( - const TemplateTypeParmType *T) { - // Nothing to do - return QualType(T, 0); + TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); } template<typename Derived> +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); +} + +template<typename Derived> +inline QualType +TreeTransform<Derived>::TransformTemplateSpecializationType( + TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL) { + // TODO: figure out how make this work with an ObjectType. + QualType Result + = TransformTemplateSpecializationType(TL.getTypePtr(), QualType()); + if (Result.isNull()) + return QualType(); + + TemplateSpecializationTypeLoc NewTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( - const TemplateSpecializationType *T) { + const TemplateSpecializationType *T, + QualType ObjectType) { TemplateName Template - = getDerived().TransformTemplateName(T->getTemplateName()); + = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); if (Template.isNull()) return QualType(); @@ -2426,8 +2730,10 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( } template<typename Derived> -QualType TreeTransform<Derived>::TransformQualifiedNameType( - const QualifiedNameType *T) { +QualType +TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, + QualifiedNameTypeLoc TL) { + QualifiedNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange()); @@ -2438,22 +2744,33 @@ QualType TreeTransform<Derived>::TransformQualifiedNameType( if (Named.isNull()) return QualType(); - if (!getDerived().AlwaysRebuild() && - NNS == T->getQualifier() && - Named == T->getNamedType()) - return QualType(T, 0); + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + NNS != T->getQualifier() || + Named != T->getNamedType()) { + Result = getDerived().RebuildQualifiedNameType(NNS, Named); + if (Result.isNull()) + return QualType(); + } + + QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); - return getDerived().RebuildQualifiedNameType(NNS, Named); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) { +QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, + TypenameTypeLoc TL) { + TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange(/*FIXME:*/getDerived().getBaseLocation())); if (!NNS) return QualType(); + QualType Result; + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = getDerived().TransformType(QualType(TemplateId, 0)); @@ -2465,31 +2782,33 @@ QualType TreeTransform<Derived>::TransformTypenameType(const TypenameType *T) { NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - return getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + } else { + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier()); } + if (Result.isNull()) + return QualType(); - return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); -} + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); -template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCInterfaceType( - const ObjCInterfaceType *T) { - // FIXME: Implement - return QualType(T, 0); + return Result; } template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCObjectPointerType( - const ObjCObjectPointerType *T) { - // FIXME: Implement - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, + ObjCInterfaceTypeLoc TL) { + assert(false && "TransformObjCInterfaceType unimplemented"); + return QualType(); } template<typename Derived> -QualType TreeTransform<Derived>::TransformObjCProtocolListType( - const ObjCProtocolListType *T) { - assert(false && "Should not see ObjCProtocolList types"); - return QualType(T, 0); +QualType +TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, + ObjCObjectPointerTypeLoc TL) { + assert(false && "TransformObjCObjectPointerType unimplemented"); + return QualType(); } //===----------------------------------------------------------------------===// @@ -4010,8 +4329,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( UnresolvedDeclRefExpr *E) { NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); if (!NNS) return SemaRef.ExprError(); @@ -4040,6 +4359,14 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { if (Template.isNull()) return SemaRef.ExprError(); + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + } + llvm::SmallVector<TemplateArgument, 4> TransArgs; for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { TemplateArgument TransArg @@ -4056,7 +4383,8 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { // FIXME: It's possible that we'll find out now that the template name // actually refers to a type, in which case the caller is actually dealing // with a functional cast. Give a reasonable error message! - return getDerived().RebuildTemplateIdExpr(Template, E->getTemplateNameLoc(), + return getDerived().RebuildTemplateIdExpr(Qualifier, E->getQualifierRange(), + Template, E->getTemplateNameLoc(), E->getLAngleLoc(), TransArgs.data(), TransArgs.size(), @@ -4235,6 +4563,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + // Start the member reference and compute the object's type. Sema::TypeTy *ObjectType = 0; Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), E->getOperatorLoc(), @@ -4243,12 +4572,12 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); - // FIXME: The first qualifier found might be a template type parameter, - // in which case there is no transformed declaration to refer to (it might - // refer to a built-in type!). + // Transform the first part of the nested-name-specifier that qualifies + // the member name. NamedDecl *FirstQualifierInScope - = cast_or_null<NamedDecl>( - getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); + = getDerived().TransformFirstQualifierInScope( + E->getFirstQualifierFoundInScope(), + E->getQualifierRange().getBegin()); NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { @@ -4261,7 +4590,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( } DeclarationName Name - = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc()); + = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), + QualType::getFromOpaquePtr(ObjectType)); if (!Name) return SemaRef.ExprError(); @@ -4504,6 +4834,14 @@ QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, template<typename Derived> QualType +TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template<typename Derived> +QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, @@ -4549,29 +4887,6 @@ TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, template<typename Derived> QualType -TreeTransform<Derived>::RebuildConstantArrayWithExprType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange) { - return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, - IndexTypeQuals, BracketsRange); -} - -template<typename Derived> -QualType -TreeTransform<Derived>::RebuildConstantArrayWithoutExprType( - QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - unsigned IndexTypeQuals) { - return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, - IndexTypeQuals, SourceRange()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, unsigned IndexTypeQuals) { @@ -4644,6 +4959,11 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) { + return SemaRef.Context.getFunctionNoProtoType(T); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) { return SemaRef.BuildTypeofExprType(E.takeAs<Expr>()); } diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index e849042..b6fff10 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -141,9 +141,11 @@ again: } } +//===----------------------------------------------------------------------===// // Reduced test case from <rdar://problem/7114618>. // Basically a null check is performed on the field value, which is then // assigned to a variable and then checked again. +//===----------------------------------------------------------------------===// struct s_7114618 { int *p; }; void test_rdar_7114618(struct s_7114618 *s) { if (s->p) { @@ -168,9 +170,11 @@ void f() { } } +//===----------------------------------------------------------------------===// // <rdar://problem/7185607> // Bit-fields of a struct should be invalidated when blasting the entire // struct with an integer constant. +//===----------------------------------------------------------------------===// struct test_7185607 { int x : 10; int y : 22; @@ -181,9 +185,11 @@ int rdar_test_7185607() { return s.x; // no-warning } +//===----------------------------------------------------------------------===// // <rdar://problem/7242006> [RegionStore] compound literal assignment with // floats not honored // This test case is mirrored in misc-ps.m, but this case is a negative. +//===----------------------------------------------------------------------===// typedef float CGFloat; typedef struct _NSSize { CGFloat width; @@ -195,9 +201,11 @@ CGFloat rdar7242006_negative(CGFloat x) { return y.width; // expected-warning{{garbage}} } +//===----------------------------------------------------------------------===// // <rdar://problem/7249340> - Allow binding of values to symbolic regions. // This test case shows how RegionStore tracks the value bound to 'x' // after the assignment. +//===----------------------------------------------------------------------===// typedef int* ptr_rdar_7249340; void rdar_7249340(ptr_rdar_7249340 x) { *x = 1; @@ -207,11 +215,13 @@ void rdar_7249340(ptr_rdar_7249340 x) { *p = 0xDEADBEEF; // no-warning } +//===----------------------------------------------------------------------===// // <rdar://problem/7249327> - This test case tests both value tracking of // array values and that we handle symbolic values that are casted // between different integer types. Note the assignment 'n = *a++'; here // 'n' is and 'int' and '*a' is 'unsigned'. Previously we got a false positive // at 'x += *b++' (undefined value) because we got a false path. +//===----------------------------------------------------------------------===// int rdar_7249327_aux(void); void rdar_7249327(unsigned int A[2*32]) { @@ -237,8 +247,10 @@ void rdar_7249327(unsigned int A[2*32]) { x += *b++; // no-warning } +//===----------------------------------------------------------------------===// // <rdar://problem/6914474> - Check that 'x' is invalidated because its // address is passed in as a value to a struct. +//===----------------------------------------------------------------------===// struct doodad_6914474 { int *v; }; extern void prod_6914474(struct doodad_6914474 *d); int rdar_6914474(void) { @@ -278,8 +290,11 @@ int test_handle_array_wrapper() { return p->z; // no-warning } +//===----------------------------------------------------------------------===// // <rdar://problem/7261075> [RegionStore] crash when // handling load: '*((unsigned int *)"????")' +//===----------------------------------------------------------------------===// + int rdar_7261075(void) { unsigned int var = 0; if (var == *((unsigned int *)"????")) @@ -287,8 +302,11 @@ int rdar_7261075(void) { return 0; } +//===----------------------------------------------------------------------===// // <rdar://problem/7275774> false path due to limited pointer // arithmetic constraints +//===----------------------------------------------------------------------===// + void rdar_7275774(void *data, unsigned n) { if (!(data || n == 0)) return; @@ -303,3 +321,54 @@ void rdar_7275774(void *data, unsigned n) { } } +//===----------------------------------------------------------------------===// +// <rdar://problem/7312221> +// +// Test that Objective-C instance variables aren't prematurely pruned +// from the analysis state. +//===----------------------------------------------------------------------===// + +struct rdar_7312221_value { int x; }; + +@interface RDar7312221 +{ + struct rdar_7312221_value *y; +} +- (void) doSomething_7312221; +@end + +extern struct rdar_7312221_value *rdar_7312221_helper(); +extern int rdar_7312221_helper_2(id o); +extern void rdar_7312221_helper_3(int z); + +@implementation RDar7312221 +- (void) doSomething_7312221 { + if (y == 0) { + y = rdar_7312221_helper(); + if (y != 0) { + y->x = rdar_7312221_helper_2(self); + // The following use of 'y->x' previously triggered a null dereference, as the value of 'y' + // before 'y = rdar_7312221_helper()' would be used. + rdar_7312221_helper_3(y->x); // no-warning + } + } +} +@end + +struct rdar_7312221_container { + struct rdar_7312221_value *y; +}; + +extern int rdar_7312221_helper_4(struct rdar_7312221_container *s); + +// This test case essentially matches the one in [RDar7312221 doSomething_7312221]. +void doSomething_7312221_with_struct(struct rdar_7312221_container *Self) { + if (Self->y == 0) { + Self->y = rdar_7312221_helper(); + if (Self->y != 0) { + Self->y->x = rdar_7312221_helper_4(Self); + rdar_7312221_helper_3(Self->y->x); // no-warning + } + } +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 10e5823..fcc13a3 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -681,14 +681,40 @@ void *rdar7152418_bar(); return 1; } +//===----------------------------------------------------------------------===// // Test constant-folding of symbolic values, automatically handling type -// conversions of the symbol as necessary. Previously this would crash -// once we started eagerly evaluating symbols whose values were constrained -// to a single value. -void test_constant_symbol(signed char x) { +// conversions of the symbol as necessary. +//===----------------------------------------------------------------------===// + + +// Previously this would crash once we started eagerly evaluating symbols whose +// values were constrained to a single value. +void test_symbol_fold_1(signed char x) { while (1) { if (x == ((signed char) 0)) {} } } +// This previously caused a crash because it triggered an assertion in APSInt. +void test_symbol_fold_2(unsigned int * p, unsigned int n, + const unsigned int * grumpkin, unsigned int dn) { + unsigned int i; + unsigned int tempsub[8]; + unsigned int *solgrumpkin = tempsub + n; + for (i = 0; i < n; i++) + solgrumpkin[i] = (i < dn) ? ~grumpkin[i] : 0xFFFFFFFF; + for (i <<= 5; i < (n << 5); i++) {} +} + +// This previously caused a crash because it triggered an assertion in APSInt. +// 'x' would evaluate to a 8-bit constant (because of the return value of +// test_symbol_fold_3_aux()) which would not get properly promoted to an +// integer. +char test_symbol_fold_3_aux(void); +unsigned test_symbol_fold_3(void) { + unsigned x = test_symbol_fold_3_aux(); + if (x == 54) + return (x << 8) | 0x5; + return 0; +} diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m index bea4047..2ce00b2 100644 --- a/test/Analysis/refcnt_naming.m +++ b/test/Analysis/refcnt_naming.m @@ -15,7 +15,7 @@ typedef signed char BOOL; -(NSObject*)photoCopy; // read as "photo Copy" -(NSObject*)__blebPRCopy; // read as "bleb PRCopy" -(NSObject*)__blebPRcopy; // read as "bleb P Rcopy" --(NSObject*)new_theprefixdoesnotcount; // read as "theprefixdoesnotcount" +-(NSObject*)new_theprefixdoescount; // read as "new theprefixdoescount" -(NSObject*)newestAwesomeStuff; // read as "newest awesome stuff" @end @@ -49,7 +49,7 @@ void testNames(NamingTest* x) { [x photoCopy]; // expected-warning{{leak}} [x __blebPRCopy]; // expected-warning{{leak}} [x __blebPRcopy]; // no-warning - [x new_theprefixdoesnotcount]; // no-warning + [x new_theprefixdoescount]; // expected-warning{{leak}} [x newestAwesomeStuff]; // no-warning } diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m index 7a69683..eacac49 100644 --- a/test/Analysis/retain-release-region-store.m +++ b/test/Analysis/retain-release-region-store.m @@ -1,5 +1,4 @@ // RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s -// XFAIL //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from @@ -43,14 +42,19 @@ typedef mach_port_name_t mach_port_t; typedef signed char BOOL; typedef struct _NSZone NSZone; @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; -@protocol NSObject - (BOOL)isEqual:(id)object; +@protocol NSObject +- (BOOL)isEqual:(id)object; - (id)retain; - (oneway void)release; @end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; -@end @interface NSObject <NSObject> { -} -@end typedef float CGFloat; +@end +@interface NSObject <NSObject> {} ++ (id)allocWithZone:(NSZone *)zone; ++ (id)alloc; +- (void)dealloc; +@end +typedef float CGFloat; typedef double NSTimeInterval; @interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; @end enum { @@ -74,6 +78,13 @@ kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff typedef mach_error_t DAReturn; typedef const struct __DADissenter * DADissenterRef; extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string ); +@interface NSNumber : NSObject +- (id)initWithInt:(int)value; +@end +typedef unsigned long NSUInteger; +@interface NSArray : NSObject +-(id) initWithObjects:(const id *)objects count:(NSUInteger) cnt; +@end //===----------------------------------------------------------------------===// // Test cases. @@ -116,15 +127,14 @@ CFAbsoluteTime f4() { } @end -//===----------------------------------------------------------------------===// -// <rdar://problem/7257223> - False positive due to not invalidating the -// reference count of a tracked region that was itself invalidated. -//===----------------------------------------------------------------------===// +//===------------------------------------------------------------------------------------------===// +// <rdar://problem/7257223> (also <rdar://problem/7283470>) - False positive due to not invalidating +// the reference count of a tracked region that was itself invalidated. +//===------------------------------------------------------------------------------------------===// typedef struct __rdar_7257223 { CFDateRef x; } RDar7257223; void rdar_7257223_aux(RDar7257223 *p); -// THIS CASE CURRENTLY FAILS. CFDateRef rdar7257223_Create(void) { RDar7257223 s; CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); @@ -140,3 +150,58 @@ CFDateRef rdar7257223_Create_2(void) { return s.x; } +void rdar7283470(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; +} + +void rdar7283470_positive(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:2], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:3], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:4], // expected-warning{{leak}} + [[NSNumber alloc] initWithInt:5] // expected-warning{{leak}} + }; +} + +void rdar7283470_2(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + NSArray *s_numbers =[[NSArray alloc] initWithObjects:&numbers[0] count:sizeof(numbers) / sizeof(numbers[0])]; + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; + + [s_numbers release]; +} + +void rdar7283470_2_positive(void) { + NSNumber *numbers[] = { + [[NSNumber alloc] initWithInt:1], // no-warning + [[NSNumber alloc] initWithInt:2], // no-warning + [[NSNumber alloc] initWithInt:3], // no-warning + [[NSNumber alloc] initWithInt:4], // no-warning + [[NSNumber alloc] initWithInt:5] // no-warning + }; + + NSArray *s_numbers =[[NSArray alloc] initWithObjects: &numbers[0] count:sizeof(numbers) / sizeof(numbers[0])]; // expected-warning{{leak}} + + for (unsigned i = 0 ; i < sizeof(numbers) / sizeof(numbers[0]) ; ++i) + [numbers[i] release]; +} + diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index 7076bb2..e620037 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -1098,6 +1098,44 @@ CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height, } //===----------------------------------------------------------------------===// +// <rdar://problem/7265711> allow 'new', 'copy', 'alloc', 'init' prefix to +// start before '_' when determining Cocoa fundamental rule +// +// Previously the retain/release checker just skipped prefixes before the +// first '_' entirely. Now the checker honors the prefix if it results in a +// recognizable naming convention (e.g., 'new', 'init'). +//===----------------------------------------------------------------------===// + +@interface RDar7265711 {} +- (id) new_stuff; +@end + +void rdar7265711_a(RDar7265711 *x) { + id y = [x new_stuff]; // expected-warning{{leak}} +} + +void rdar7265711_b(RDar7265711 *x) { + id y = [x new_stuff]; // no-warning + [y release]; +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7306898> clang thinks [NSCursor dragCopyCursor] returns a +// retained reference +//===----------------------------------------------------------------------===// + +@interface NSCursor : NSObject ++ (NSCursor *)dragCopyCursor; +@end + +void rdar7306898(void) { + // 'dragCopyCursor' does not follow Cocoa's fundamental rule. It is a noun, not an sentence + // implying a 'copy' of something. + NSCursor *c = [NSCursor dragCopyCursor]; // no-warning + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} +} + +//===----------------------------------------------------------------------===// // Tests of ownership attributes. //===----------------------------------------------------------------------===// diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2a7f132..66f05bf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,7 +45,7 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR}/${testdir} - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests in ${testdir}") endforeach() @@ -62,7 +62,7 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests") add_custom_target(clang-c++tests @@ -78,6 +78,6 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests") endif() diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp new file mode 100644 index 0000000..4d0319e --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++98 -pedantic -Werror %s +int a1[] = { 1, 3, 5 }; +void f() { + int a2[] = { 1, 3, 5 }; +} +template <typename T> +void tf() { + T t; + // Element type may be dependent + T a3[] = { 1, 3, 5 }; + // As might be the initializer list, value + int a5[] = { sizeof(T) }; + // or even type. + int a6[] = { t.get() }; +} + +// Allowed by GNU extension +int a4[] = {}; // expected-warning {{zero size arrays}} diff --git a/test/CXX/temp/temp.spec/p5.cpp b/test/CXX/temp/temp.spec/p5.cpp new file mode 100644 index 0000000..d5632e7 --- /dev/null +++ b/test/CXX/temp/temp.spec/p5.cpp @@ -0,0 +1,29 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> inline void f(T) { } +template void f(int); // expected-note{{previous explicit instantiation}} +template void f(int); // expected-error{{duplicate explicit instantiation}} + +template<typename T> +struct X0 { + union Inner { }; + + void f(T) { } + + static T value; +}; + +template<typename T> +T X0<T>::value = 3.14; + +template struct X0<int>; // expected-note{{previous explicit instantiation}} +template struct X0<int>; // expected-error{{duplicate explicit instantiation}} + +template void X0<float>::f(float); // expected-note{{previous explicit instantiation}} +template void X0<float>::f(float); // expected-error{{duplicate explicit instantiation}} + +template union X0<float>::Inner; // expected-note{{previous explicit instantiation}} +template union X0<float>::Inner; // expected-error{{duplicate explicit instantiation}} + +template float X0<float>::value; // expected-note{{previous explicit instantiation}} +template float X0<float>::value; // expected-error{{duplicate explicit instantiation}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp new file mode 100644 index 0000000..d7731f1 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s + +template<typename T> +struct X { + void f() {} +}; + +template inline void X<int>::f(); // expected-error{{'inline'}} + +// FIXME: test constexpr diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp new file mode 100644 index 0000000..3938509 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp @@ -0,0 +1,29 @@ +// RUN: clang-cc -emit-llvm -triple x86_64-apple-darwin10 -o - %s | FileCheck %s +template<typename T> +struct X { + static T member1; + static T member2; + static T member3; +}; + +template<typename T> +T X<T>::member1; + +template<typename T> +T X<T>::member2 = 17; + +// CHECK: @_ZN1XIiE7member1E = global i32 0 +template int X<int>::member1; + +// CHECK: @_ZN1XIiE7member2E = global i32 17 +template int X<int>::member2; + +// For implicit instantiation of +long& get(bool Cond1, bool Cond2) { + // CHECK: @_ZN1XIlE7member1E = weak global i64 0 + // CHECK: @_ZN1XIlE7member2E = weak global i64 17 + // CHECK: @_ZN1XIlE7member3E = external global i64 + return Cond1? X<long>::member1 + : Cond2? X<long>::member2 + : X<long>::member3; +} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp new file mode 100644 index 0000000..896e30e --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp @@ -0,0 +1,89 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct C { }; + +template<typename T> +struct X0 { + T value; // expected-error{{incomplete}} +}; + +// Explicitly instantiate a class template specialization +template struct X0<int>; +template struct X0<void>; // expected-note{{instantiation}} + +// Explicitly instantiate a function template specialization +template<typename T> +void f0(T t) { + ++t; // expected-error{{cannot modify}} +} + +template void f0(int); +template void f0<long>(long); +template void f0<>(unsigned); +template void f0(int C::*); // expected-note{{instantiation}} + +// Explicitly instantiate a member template specialization +template<typename T> +struct X1 { + template<typename U> + struct Inner { + T member1; + U member2; // expected-error{{incomplete}} + }; + + template<typename U> + void f(T& t, U u) { + t = u; // expected-error{{incompatible}} + } +}; + +template struct X1<int>::Inner<float>; +template struct X1<int>::Inner<double>; +template struct X1<int>::Inner<void>; // expected-note{{instantiation}} + +template void X1<int>::f(int&, float); +template void X1<int>::f<long>(int&, long); +template void X1<int>::f<>(int&, double); +template void X1<int>::f<>(int&, int*); // expected-note{{instantiation}} + +// Explicitly instantiate members of a class template +struct Incomplete; // expected-note{{forward declaration}} +struct NonDefaultConstructible { + NonDefaultConstructible(int); +}; + +template<typename T, typename U> +struct X2 { + void f(T &t, U u) { + t = u; // expected-error{{incompatible}} + } + + struct Inner { + T member1; + U member2; // expected-error{{incomplete}} + }; + + static T static_member1; + static U static_member2; +}; + +template<typename T, typename U> +T X2<T, U>::static_member1 = 17; // expected-error{{incompatible type}} + +template<typename T, typename U> +U X2<T, U>::static_member2; // expected-error{{no matching}} + +template void X2<int, float>::f(int &, float); +template void X2<int, float>::f(int &, double); // expected-error{{does not refer}} +template void X2<int, int*>::f(int&, int*); // expected-note{{instantiation}} + +template struct X2<int, float>::Inner; +template struct X2<int, Incomplete>::Inner; // expected-note{{instantiation}} + +template int X2<int, float>::static_member1; +template int* X2<int*, float>::static_member1; // expected-note{{instantiation}} +template + NonDefaultConstructible X2<NonDefaultConstructible, int>::static_member1; + +template + NonDefaultConstructible X2<int, NonDefaultConstructible>::static_member2; // expected-note{{instantiation}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp new file mode 100644 index 0000000..f3d2c95 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp @@ -0,0 +1,43 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Example from the standard +template<class T> class Array { void mf() { } }; + +template class Array<char>; +template void Array<int>::mf(); +template<class T> void sort(Array<T>& v) { /* ... */ } +template void sort(Array<char>&); +namespace N { + template<class T> void f(T&) { } +} +template void N::f<int>(int&); + + +template<typename T> +struct X0 { + struct Inner {}; + void f() { } + static T value; +}; + +template<typename T> +T X0<T>::value = 17; + +typedef X0<int> XInt; + +template struct XInt::Inner; // expected-error{{template-id}} +template void XInt::f(); // expected-error{{template-id}} +template int XInt::value; // expected-error{{template-id}} + +namespace N { + template<typename T> + struct X1 { // expected-note{{explicit instantiation refers here}} + }; + + template<typename T> + void f1(T) {}; // expected-note{{explicit instantiation refers here}} +} +using namespace N; + +template struct X1<int>; // expected-error{{must occur in}} +template void f1(int); // expected-error{{must occur in}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp new file mode 100644 index 0000000..2bd781b --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp @@ -0,0 +1,55 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// A declaration of a function template shall be in scope at the point of the +// explicit instantiation of the function template. +template<typename T> void f0(T) { } +template void f0(int); // okay + +// A definition of the class or class template containing a member function +// template shall be in scope at the point of the explicit instantiation of +// the member function template. +struct X0; // expected-note 2{{forward declaration}} +template<typename> struct X1; // expected-note 2{{declared here}} \ + // expected-note 3{{forward declaration}} + +// FIXME: Repeated diagnostics here! +template void X0::f0<int>(int); // expected-error 2{{incomplete type}} \ + // expected-error{{invalid token after}} +template void X1<int>::f0<int>(int); // expected-error{{implicit instantiation of undefined template}} \ + // expected-error{{incomplete type}} \\ + // expected-error{{invalid token}} + +// A definition of a class template or class member template shall be in scope +// at the point of the explicit instantiation of the class template or class +// member template. +template struct X1<float>; // expected-error{{explicit instantiation of undefined template}} + +template<typename T> +struct X2 { // expected-note 4{{refers here}} + template<typename U> + struct Inner; // expected-note{{declared here}} + + struct InnerClass; // expected-note{{forward declaration}} +}; + +template struct X2<int>::Inner<float>; // expected-error{{explicit instantiation of undefined template}} + +// A definition of a class template shall be in scope at the point of an +// explicit instantiation of a member function or a static data member of the +// class template. +template void X1<int>::f1(int); // expected-error{{incomplete type}} \ + // expected-error{{does not refer}} + +template int X1<int>::member; // expected-error{{incomplete type}} \ + // expected-error{{does not refer}} + +// A definition of a member class of a class template shall be in scope at the +// point of an explicit instantiation of the member class. +template struct X2<float>::InnerClass; // expected-error{{undefined member}} + +// If the declaration of the explicit instantiation names an implicitly-declared +// special member function (Clause 12), the program is ill-formed. +template X2<int>::X2(); // expected-error{{not an instantiation}} +template X2<int>::X2(const X2&); // expected-error{{not an instantiation}} +template X2<int>::~X2(); // expected-error{{not an instantiation}} +template X2<int> &X2<int>::operator=(const X2<int>&); // expected-error{{not an instantiation}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp new file mode 100644 index 0000000..04e511b --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp @@ -0,0 +1,32 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> void f0(T); // expected-note{{here}} +template void f0(int); // expected-error{{explicit instantiation of undefined function template}} + +template<typename T> +struct X0 { + struct Inner; + + void f1(); // expected-note{{here}} + + static T value; // expected-note{{here}} +}; + +template void X0<int>::f1(); // expected-error{{explicit instantiation of undefined member function}} + +template int X0<int>::value; // expected-error{{explicit instantiation of undefined static data member}} + +template<> void f0(long); +template void f0(long); // okay + +template<> void X0<long>::f1(); +template void X0<long>::f1(); + +template<> struct X0<long>::Inner; +template struct X0<long>::Inner; + +template<> long X0<long>::value; +template long X0<long>::value; + +template<> struct X0<double>; +template struct X0<double>; diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c new file mode 100644 index 0000000..eea3fb5 --- /dev/null +++ b/test/CodeGen/2009-10-20-GlobalDebug.c @@ -0,0 +1,4 @@ +// RUN: clang -ccc-host-triple i386-apple-darwin10 -S -g -dA %s -o - | FileCheck %s +int global; +// CHECK: asciz "global" ## DW_AT_MIPS_linkage_name +int main() { return 0;} diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c index ac59b27..359d507 100644 --- a/test/CodeGen/builtins.c +++ b/test/CodeGen/builtins.c @@ -117,7 +117,7 @@ int main() { -char *strcat(char *a, char const *b) {} +void strcat() {} void foo() { __builtin_strcat(0, 0); diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c index beee7ac..85ad988 100644 --- a/test/CodeGen/debug-info.c +++ b/test/CodeGen/debug-info.c @@ -1,10 +1,12 @@ -// RUN: clang-cc -o %t --emit-llvm -g %s +// RUN: clang-cc -o %t --emit-llvm -g %s && +// RUN: FileCheck --input-file=%t %s // PR3023 void convert(void) { struct { typeof(0) f0; } v0; } + // PR2784 struct OPAQUE; typedef struct OPAQUE *PTR; @@ -19,9 +21,11 @@ struct s0 *f0(struct s0 *a0) { return a0->p; } + // PR3134 char xpto[]; + // PR3427 struct foo { int a; @@ -29,9 +33,17 @@ struct foo { }; struct foo bar; + // PR4143 struct foo2 { enum bar *bar; }; struct foo2 foo2; + + +// Radar 7325611 +// CHECK: "barfoo" +typedef int barfoo; +barfoo foo() { +} diff --git a/test/CodeGen/ext-vector-shuffle.c b/test/CodeGen/ext-vector-shuffle.c index f53db94..7655515 100644 --- a/test/CodeGen/ext-vector-shuffle.c +++ b/test/CodeGen/ext-vector-shuffle.c @@ -1,6 +1,6 @@ -// RUN: clang-cc %s -emit-llvm -o - | not grep 'extractelement' && -// RUN: clang-cc %s -emit-llvm -o - | not grep 'insertelement' && -// RUN: clang-cc %s -emit-llvm -o - | grep 'shufflevector' +// RUN: clang-cc %s -x cl -emit-llvm -o - | not grep 'extractelement' && +// RUN: clang-cc %s -x cl -emit-llvm -o - | not grep 'insertelement' && +// RUN: clang-cc %s -x cl -emit-llvm -o - | grep 'shufflevector' typedef __attribute__(( ext_vector_type(2) )) float float2; typedef __attribute__(( ext_vector_type(4) )) float float4; @@ -13,3 +13,5 @@ float4 test2(float4 V) { float2 W = V.ww; return W.xyxy + W.yxyx; } + +float4 test3(float4 V1, float4 V2) { return (float4)(V1.zw, V2.xy); } diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c index 5e48fd4..2945eba 100644 --- a/test/CodeGen/vector.c +++ b/test/CodeGen/vector.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -emit-llvm %s -o - +// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -g -emit-llvm %s -o - typedef short __v4hi __attribute__ ((__vector_size__ (8))); -void f() { +void test1() { __v4hi A = (__v4hi)0LL; } @@ -9,11 +9,34 @@ __v4hi x = {1,2,3}; __v4hi y = {1,2,3,4}; typedef int vty __attribute((vector_size(16))); -int a() { vty b; return b[2LL]; } +int test2() { vty b; return b[2LL]; } // PR4339 typedef float vec4 __attribute__((vector_size(16))); -void vac ( vec4* a, char b, float c ) { +void test3 ( vec4* a, char b, float c ) { (*a)[b] = c; } + + + + +#include <mmintrin.h> + +int test4(int argc, char *argv[]) { + int array[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; + __m64 *p = (__m64 *)array; + + __m64 accum = _mm_setzero_si64(); + + for (int i=0; i<8; ++i) + accum = _mm_add_pi32(p[i], accum); + + __m64 accum2 = _mm_unpackhi_pi32(accum, accum); + accum = _mm_add_pi32(accum, accum2); + + int result = _mm_cvtsi64_si32(accum); + _mm_empty(); + + return result; +} diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp new file mode 100644 index 0000000..1f0c8f3 --- /dev/null +++ b/test/CodeGenCXX/address-of-fntemplate.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s +template <typename T> void f(T) {} +template <typename T> void f() { } + +void test() { + // CHECK: @_Z1fIiEvT_ + void (*p)(int) = &f; + + // CHECK: @_Z1fIiEvv + void (*p2)() = f<int>; +} +// CHECK: define linkonce_odr void @_Z1fIiEvT_ +// CHECK: define linkonce_odr void @_Z1fIiEvv diff --git a/test/CodeGenCXX/call-arg-zero-temp.cpp b/test/CodeGenCXX/call-arg-zero-temp.cpp new file mode 100644 index 0000000..2c44f69 --- /dev/null +++ b/test/CodeGenCXX/call-arg-zero-temp.cpp @@ -0,0 +1,23 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true + + +extern "C" int printf(...); + +struct obj{ int a; float b; double d; }; + +void foo(obj o) { + printf("%d %f %f\n", o.a, o.b, o.d); +} + +int main() { + obj o = obj(); + foo(obj()); +} + +// CHECK-LP64: call __Z3foo3obj + +// CHECK-LP32: call __Z3foo3obj diff --git a/test/CodeGenCXX/casts.cpp b/test/CodeGenCXX/casts.cpp new file mode 100644 index 0000000..045f2d4 --- /dev/null +++ b/test/CodeGenCXX/casts.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc %s -emit-llvm -o %t + +// PR5248 +namespace PR5248 { +struct A { + void copyFrom(const A &src); + void addRef(void); +}; + +void A::copyFrom(const A &src) { + ((A &)src).addRef(); +} +} + diff --git a/test/CodeGenCXX/default-arg-temps.cpp b/test/CodeGenCXX/default-arg-temps.cpp index 2651446..8385aff 100644 --- a/test/CodeGenCXX/default-arg-temps.cpp +++ b/test/CodeGenCXX/default-arg-temps.cpp @@ -15,7 +15,7 @@ public: void g() { // RUN: grep "call void @_ZN1TC1Ev" %t | count 4 && - // RUN: grep "call void @_ZN1TD1Ev" %t | count 4 + // RUN: grep "call void @_ZN1TD1Ev" %t | count 4 && f(); f(); @@ -23,3 +23,10 @@ void g() { X b(a); X c = a; } + + +// RUN: grep memset %t +class obj{ int a; float b; double d; }; +void h() { + obj o = obj(); +} diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp new file mode 100644 index 0000000..0c89019 --- /dev/null +++ b/test/CodeGenCXX/derived-to-base-conv.cpp @@ -0,0 +1,79 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true + +extern "C" int printf(...); +extern "C" void exit(int); + +struct A { + A (const A&) { printf("A::A(const A&)\n"); } + A() {}; +}; + +struct B : public A { + B() {}; +}; + +struct C : public B { + C() {}; +}; + +struct X { + operator B&() {printf("X::operator B&()\n"); return b; } + operator C&() {printf("X::operator C&()\n"); return c; } + X (const X&) { printf("X::X(const X&)\n"); } + X () { printf("X::X()\n"); } + B b; + C c; +}; + +void f(A) { + printf("f(A)\n"); +} + + +void func(X x) +{ + f (x); +} + +int main() +{ + X x; + func(x); +} + +struct Base; + +struct Root { + operator Base&() { exit(1); } +}; + +struct Derived; + +struct Base : Root { + Base(const Base&) { printf("Base::(const Base&)\n"); } + Base() { printf("Base::Base()\n"); } + operator Derived&() { exit(1); } +}; + +struct Derived : Base { +}; + +void foo(Base) {} + +void test(Derived bb) +{ + // CHECK-LP64-NOT: call __ZN4BasecvR7DerivedEv + // CHECK-LP32-NOT: call L__ZN4BasecvR7DerivedEv + foo(bb); +} +// CHECK-LP64: call __ZN1XcvR1BEv +// CHECK-LP64: call __ZN1AC1ERKS_ + +// CHECK-LP32: call L__ZN1XcvR1BEv +// CHECK-LP32: call L__ZN1AC1ERKS_ + + diff --git a/test/CodeGenCXX/expr.cpp b/test/CodeGenCXX/expr.cpp index ae5b0e6..4dc97c4 100644 --- a/test/CodeGenCXX/expr.cpp +++ b/test/CodeGenCXX/expr.cpp @@ -1,5 +1,12 @@ // RUN: clang-cc -emit-llvm -x c++ < %s -void f(int x) { +void test0(int x) { if (x != 0) return; } + + +// PR5211 +void test1() { + char *xpto; + while ( true && xpto[0] ); +} diff --git a/test/CodeGenCXX/mangle-subst.cpp b/test/CodeGenCXX/mangle-subst.cpp index c53a630..46a21b6 100644 --- a/test/CodeGenCXX/mangle-subst.cpp +++ b/test/CodeGenCXX/mangle-subst.cpp @@ -54,3 +54,8 @@ template<typename T> void ft3(S1<T>, S1<char>) { } // CHECK: @_ZN2NS3ft3IiEEvNS_2S1IT_EENS1_IcEE template void ft3<int>(S1<int>, S1<char>); } + +// PR5196 +// CHECK: @_Z1fPKcS0_ +void f(const char*, const char*) {} + diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 13f7de5..a7c2113 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -71,3 +71,19 @@ namespace PR5177 { void bar(B1 b2) { while (b2()) ; } } + +// PR5138 +namespace PR5138 { + struct foo { + virtual void bar(foo *); + }; + + extern "C" { + void baz(foo *); + } + + void (foo::*ptr1)(void *) = (void (foo::*)(void *))&foo::bar; + void (*ptr2)(void *) = (void (*)(void *))&baz; + + void (foo::*ptr3)(void) = (void (foo::*)(void))&foo::bar; +} diff --git a/test/CodeGenCXX/ptr-to-datamember.cpp b/test/CodeGenCXX/ptr-to-datamember.cpp new file mode 100644 index 0000000..eee03c0 --- /dev/null +++ b/test/CodeGenCXX/ptr-to-datamember.cpp @@ -0,0 +1,70 @@ +// RUN: clang-cc -emit-llvm -o - %s + +extern "C" int printf(...); + +struct F { + F() : iF(1), fF(2.0) {} + int iF; + float fF; +}; + +struct V { + double d; + int iV; +}; + +struct B : virtual V{ + double d; + int iB; +}; + +struct B1 : virtual V{ + double d; + int iB1; +}; + +class A : public B, public B1 { +public: + A() : f(1.0), d(2.0), Ai(3) {} + float f; + double d; + int Ai; + F Af; +}; + +void pr(const F& b) { + printf(" %d %f\n", b.iF, b.fF); +} + +void test_aggr_pdata(A& a1) { + F A::* af = &A::Af; + pr(a1.*af); + + (a1.*af).iF = 100; + (a1.*af).fF = 200.00; + printf(" %d %f\n", (a1.*af).iF, (a1.*af).fF); + pr(a1.*af); + + (a1.*af).iF++; + (a1.*af).fF--; + --(a1.*af).fF; + pr(a1.*af); +} + +int main() +{ + A a1; + int A::* pa = &A::Ai; + float A::* pf = &A::f; + double A::* pd = &A::d; + printf("%d %d %d\n", &A::Ai, &A::f, &A::d); + printf("%d\n", &A::B::iB); + printf("%d\n", &A::B1::iB1); + printf("%d\n", &A::f); + printf("%d\n", &A::B::iV); + printf("%d\n", &A::B1::iV); + printf("%d\n", &A::B::V::iV); + printf("%d\n", &A::B1::V::iV); + printf("%d, %f, %f \n", a1.*pa, a1.*pf, a1.*pd); + test_aggr_pdata(a1); +} diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index 32d46b3..8e0e1cb 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -107,3 +107,32 @@ void h() { const C& c = D(); } +namespace T { + struct A { + A(); + ~A(); + }; + + struct B { + B(); + ~B(); + A f(); + }; + + void f() { + // CHECK: call void @_ZN1T1BC1Ev + // CHECK: call void @_ZN1T1B1fEv + // CHECK: call void @_ZN1T1BD1Ev + const A& a = B().f(); + // CHECK: call void @_ZN1T1fEv + f(); + // CHECK: call void @_ZN1T1AD1Ev + } +} + +// PR5227. +namespace PR5227 { +void f(int &a) { + (a = 10) = 20; +} +} diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp new file mode 100644 index 0000000..d622193 --- /dev/null +++ b/test/CodeGenCXX/temporaries.cpp @@ -0,0 +1,117 @@ +// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +struct A { + A(); + ~A(); + void f(); +}; + +void f1() { + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_ZN1AD1Ev + (void)A(); + + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_ZN1AD1Ev + A().f(); +} + +// Function calls +struct B { + B(); + ~B(); +}; + +B g(); + +void f2() { + // CHECK-NOT: call void @_ZN1BC1Ev + // CHECK: call void @_ZN1BD1Ev + (void)g(); +} + +// Member function calls +struct C { + C(); + ~C(); + + C f(); +}; + +void f3() { + // CHECK: call void @_ZN1CC1Ev + // CHECK: call void @_ZN1CD1Ev + // CHECK: call void @_ZN1CD1Ev + C().f(); +} + +// Function call operator +struct D { + D(); + ~D(); + + D operator()(); +}; + +void f4() { + // CHECK call void @_ZN1DC1Ev + // CHECK call void @_ZN1DD1Ev + // CHECK call void @_ZN1DD1Ev + D()(); +} + +// Overloaded operators +struct E { + E(); + ~E(); + E operator+(const E&); + E operator!(); +}; + +void f5() { + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + E() + E(); + + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + !E(); +} + +struct F { + F(); + ~F(); + F& f(); +}; + +void f6() { + // CHECK: call void @_ZN1FC1Ev + // CHECK: call void @_ZN1FD1Ev + F().f(); +} + +struct G { + G(); + G(A); + ~G(); + operator A(); +}; + +void a(const A&); + +void f7() { + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_Z1aRK1A + // CHECK: call void @_ZN1AD1Ev + a(A()); + + // CHECK: call void @_ZN1GC1Ev + // CHECK: call void @_ZN1Gcv1AEv + // CHECK: call void @_Z1aRK1A + // CHECK: call void @_ZN1AD1Ev + // CHECK: call void @_ZN1GD1Ev + a(G()); +} diff --git a/test/Driver/cxx-pth.cpp b/test/Driver/cxx-pth.cpp new file mode 100644 index 0000000..a06a257 --- /dev/null +++ b/test/Driver/cxx-pth.cpp @@ -0,0 +1,12 @@ +// Test forced PTH for CXX support. + +// RUN: clang -x c++-header %s -### 2> %t.log && +// RUN: FileCheck -check-prefix EMIT -input-file %t.log %s && + +// EMIT: "{{.*}}/clang-cc{{.*}}" {{.*}} "-emit-pth" "{{.*}}.cpp.gch" "-x" "c++-header" "{{.*}}.cpp" + +// RUN: touch %t.h.gch && +// RUN: clang -E -include %t.h %s -### 2> %t.log && +// RUN: FileCheck -check-prefix USE -input-file %t.log %s + +// USE: "{{.*}}/clang-cc{{.*}}" {{.*}}"-include-pth" "{{.*}}.h.gch" {{.*}}"-x" "c++" "{{.*}}.cpp" diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c index d81605b..9165a4a 100644 --- a/test/Driver/darwin-ld.c +++ b/test/Driver/darwin-ld.c @@ -33,7 +33,7 @@ // Note that at conception, this exactly matches gcc. // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO 2> %t.log && -// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1/../../../i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1/../../.." "-filelist" "FOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log && +// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../../i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../.." "-filelist" "FOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log && // Don't run dsymutil on a fat build of an executable. // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -arch i386 -arch x86_64 -g %s 2> %t.log && diff --git a/test/Index/c-index-pch.c b/test/Index/c-index-pch.c new file mode 100644 index 0000000..aae4eb3 --- /dev/null +++ b/test/Index/c-index-pch.c @@ -0,0 +1,14 @@ +// RUN: clang-cc -emit-pch -x c -o %t.pch %S/c-index-pch.h && +// RUN: clang-cc -include-pch %t.pch -x c -emit-pch -o %t.ast %s && +// RUN: c-index-test %t.ast all | FileCheck -check-prefix=ALL %s && +// RUN: c-index-test %t.ast local | FileCheck -check-prefix=LOCAL %s +// ALL: FunctionDecl=foo +// ALL: VarDecl=bar +// ALL: FunctionDecl=wibble +// ALL: FunctionDecl=wonka +// LOCAL-NOT: FunctionDecl=foo +// LOCAL-NOT: VarDecl=bar +// LOCAL: FunctionDecl=wibble +// LOCAL: FunctionDecl=wonka +void wibble(int i); +void wonka(float); diff --git a/test/Index/c-index-pch.h b/test/Index/c-index-pch.h new file mode 100644 index 0000000..6dda180 --- /dev/null +++ b/test/Index/c-index-pch.h @@ -0,0 +1,7 @@ +#ifndef C_INDEX_PCH_H +#define C_INDEX_PCH_H + +void foo(int i, float f); +extern int bar; + +#endif // C_INDEX_PCH_H diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c index ac5dab9..9f4d66f 100644 --- a/test/Misc/message-length.c +++ b/test/Misc/message-length.c @@ -1,14 +1,7 @@ -// RUN: clang -fsyntax-only -fmessage-length=72 %s 2> %t && - -// RUN: grep -A4 "FILE:23" %t > %t.msg && -// FIXME: This diagnostic is getting truncated very poorly. -// RUN: grep -e '^ ...// some long comment text and a brace, eh {} ' %t.msg && -// RUN: grep -e '^ \^' %t.msg && -// RUN: clang -fsyntax-only -fmessage-length=1 %s && -// RUN: true +// RUN: clang -fsyntax-only -fmessage-length=72 %s 2>&1 | FileCheck -strict-whitespace %s && +// RUN: clang -fsyntax-only -fmessage-length=1 %s // Hack so we can check things better, force the file name and line. - # 1 "FILE" 1 /* It's tough to verify the results of this test mechanically, since @@ -33,3 +26,7 @@ void a_very_long_line(int *ip, float *FloatPointer) { } #pragma STDC CX_LIMITED_RANGE // some long comment text and a brace, eh {} + + +// CHECK: FILE:23:78 +// CHECK: {{^ ...// some long comment text and a brace, eh {} $}} diff --git a/test/Preprocessor/macro_paste_bcpl_comment.c b/test/Preprocessor/macro_paste_bcpl_comment.c index 8bbee5d..0637a87 100644 --- a/test/Preprocessor/macro_paste_bcpl_comment.c +++ b/test/Preprocessor/macro_paste_bcpl_comment.c @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -Eonly 2>&1 | grep error +// RUN: clang-cc %s -Eonly -fms-extensions=0 2>&1 | grep error #define COMM1 / ## / COMM1 diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c index b83eb94..14011be 100644 --- a/test/Sema/attr-noreturn.c +++ b/test/Sema/attr-noreturn.c @@ -15,14 +15,14 @@ int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires void f3() __attribute__((noreturn)); void f3() { - return; // expected-error {{function 'f3' declared 'noreturn' should not return}} + return; // expected-warning {{function 'f3' declared 'noreturn' should not return}} } -#pragma clang diagnostic warning "-Winvalid-noreturn" +#pragma clang diagnostic error "-Winvalid-noreturn" void f4() __attribute__((noreturn)); void f4() { - return; // expected-warning {{function 'f4' declared 'noreturn' should not return}} + return; // expected-error {{function 'f4' declared 'noreturn' should not return}} } // PR4685 diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c index 69a2320..2bcc0f8 100644 --- a/test/Sema/exprs.c +++ b/test/Sema/exprs.c @@ -103,3 +103,12 @@ void test14() { __m64 mask = (__m64)((__v4hi)a > (__v4hi)a); } + +// PR5242 +typedef unsigned long *test15_t; + +test15_t test15(void) { + return (test15_t)0 + (test15_t)0; // expected-error {{invalid operands to binary expression ('test15_t' (aka 'unsigned long *') and 'test15_t')}} +} + + diff --git a/test/Sema/switch.c b/test/Sema/switch.c index 5999f34..122947e 100644 --- a/test/Sema/switch.c +++ b/test/Sema/switch.c @@ -68,3 +68,10 @@ void test5(int z) { } } +void test6() { + const char ch = 'a'; + switch(ch) { + case 1234: // expected-warning {{overflow converting case value}} + break; + } +} diff --git a/test/Sema/vector-assign.c b/test/Sema/vector-assign.c index 5162e1a..bf9c7f3 100644 --- a/test/Sema/vector-assign.c +++ b/test/Sema/vector-assign.c @@ -5,7 +5,7 @@ typedef signed int v1s __attribute__ ((vector_size (4))); typedef float v2f __attribute__ ((vector_size(8))); typedef signed short v4ss __attribute__ ((vector_size (8))); -void f() { +void test1() { v2s v1; v2u v2; v1s v3; @@ -39,7 +39,15 @@ void f() { } // PR2263 -float f2(__attribute__((vector_size(16))) float a, int b) { +float test2(__attribute__((vector_size(16))) float a, int b) { return a[b]; } +// PR4838 +typedef long long __attribute__((__vector_size__(2 * sizeof(long long)))) +longlongvec; + +void test3a(longlongvec *); +void test3(const unsigned *src) { + test3a(src); // expected-warning {{incompatible pointer types passing 'unsigned int const *', expected 'longlongvec *'}} +} diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c index 6eab324..18104d8 100644 --- a/test/Sema/vector-init.c +++ b/test/Sema/vector-init.c @@ -21,3 +21,10 @@ float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0, __attribute__((vector_size(16))) // expected-error {{unsupported type 'float (void)' for vector_size attribute, please use on typedef}} float f1(void) { } + + + +// PR5265 +typedef float __attribute__((ext_vector_type (3))) float3; +int test2[(sizeof(float3) == sizeof(float4))*2-1]; + diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp index e14304a..42b8d7f 100644 --- a/test/SemaCXX/abstract.cpp +++ b/test/SemaCXX/abstract.cpp @@ -123,3 +123,18 @@ struct K { struct L : public K { void f(); }; + +// PR5222 +namespace PR5222 { + struct A { + virtual A *clone() = 0; + }; + struct B : public A { + virtual B *clone() = 0; + }; + struct C : public B { + virtual C *clone(); + }; + + C c; +} diff --git a/test/SemaCXX/ambiguous-builtin-unary-operator.cpp b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp index 042546a..5affd19 100644 --- a/test/SemaCXX/ambiguous-builtin-unary-operator.cpp +++ b/test/SemaCXX/ambiguous-builtin-unary-operator.cpp @@ -2,17 +2,33 @@ struct A { operator int&(); + operator long*& (); }; struct B { operator long&(); + operator int*& (); }; struct C : B, A { }; void test(C c) { ++c; // expected-error {{use of overloaded operator '++' is ambiguous}}\ - // expected-note 4 {{built-in candidate operator ++ (}} + // expected-note {{built-in candidate operator++(int &)}} \ + // expected-note {{built-in candidate operator++(long &)}} \ + // expected-note {{built-in candidate operator++(long *&)}} \ + // expected-note {{built-in candidate operator++(int *&)}} } +struct A1 { operator volatile int&(); }; + +struct B1 { operator volatile long&(); }; + +struct C1 : B1, A1 { }; + +void test(C1 c) { + ++c; // expected-error {{use of overloaded operator '++' is ambiguous}} \ + // expected-note {{built-in candidate operator++(int volatile &)}} \ + // expected-note {{built-in candidate operator++(long volatile &)}} +} diff --git a/test/SemaCXX/bool.cpp b/test/SemaCXX/bool.cpp index bc44c73..259c09c 100644 --- a/test/SemaCXX/bool.cpp +++ b/test/SemaCXX/bool.cpp @@ -16,3 +16,15 @@ void test(bool b) bool *b1 = (int *)0; // expected-error{{expected 'bool *'}} } + +// static_assert_arg_is_bool(x) compiles only if x is a bool. +template <typename T> +void static_assert_arg_is_bool(T x) { + bool* p = &x; +} + +void test2() { + int n = 2; + static_assert_arg_is_bool(n && 4); + static_assert_arg_is_bool(n || 5); +} diff --git a/test/SemaCXX/builtin-ptrtomember-ambig.cpp b/test/SemaCXX/builtin-ptrtomember-ambig.cpp index 7e20af3..1b52651 100644 --- a/test/SemaCXX/builtin-ptrtomember-ambig.cpp +++ b/test/SemaCXX/builtin-ptrtomember-ambig.cpp @@ -19,6 +19,9 @@ struct C : B { void foo(C c, int A::* pmf) { // FIXME. Why so many built-in candidates? int i = c->*pmf; // expected-error {{use of overloaded operator '->*' is ambiguous}} \ - // expected-note 40 {{built-in candidate operator ->* ('struct A}} + // expected-note {{built-in candidate operator->*(struct A const *, int const struct A::*)}} \ + // expected-note {{built-in candidate operator->*(struct A const *, int struct A::*)}} \ + // expected-note {{built-in candidate operator->*(struct A *, int const struct A::*)}} \ + // expected-note {{built-in candidate operator->*(struct A *, int struct A::*)}} } diff --git a/test/SemaCXX/builtin-ptrtomember-overload.cpp b/test/SemaCXX/builtin-ptrtomember-overload.cpp index 718e981..ed52d47 100644 --- a/test/SemaCXX/builtin-ptrtomember-overload.cpp +++ b/test/SemaCXX/builtin-ptrtomember-overload.cpp @@ -16,3 +16,15 @@ void foo(C c, B b, int A::* pmf) { int i = b->*pmf; } +struct D { + operator const D *(); +}; + +struct DPtr { + operator volatile int D::*(); +}; + +int test(D d, DPtr dptr) { + return d->*dptr; +} + diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp index 9b2a07d..56cc435 100644 --- a/test/SemaCXX/exception-spec.cpp +++ b/test/SemaCXX/exception-spec.cpp @@ -185,3 +185,6 @@ void mfnptr() template <typename T> struct TEx; // expected-note {{template is declared here}} void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}} + +// DR 437, class throws itself. FIXME: See Sema::CheckSpecifiedExceptionType. +//struct DR437 { void f() throw(DR437); }; diff --git a/test/SemaCXX/incomplete-call.cpp b/test/SemaCXX/incomplete-call.cpp index 08bfdef..3ce898a 100644 --- a/test/SemaCXX/incomplete-call.cpp +++ b/test/SemaCXX/incomplete-call.cpp @@ -40,3 +40,10 @@ void g() { (b.*mfp)(); // expected-error {{calling function with incomplete return type 'struct A'}} } + + +struct C; // expected-note{{forward declaration}} + +void test_incomplete_object_call(C& c) { + c(); // expected-error{{incomplete type in call to object of type}} +} diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp index 28b1224..069f526 100644 --- a/test/SemaCXX/member-expr.cpp +++ b/test/SemaCXX/member-expr.cpp @@ -31,3 +31,14 @@ int f0(B *b) { return b->f0->f0; // expected-error{{member reference base type 'struct A *()' is not a structure or union}} \ // expected-note{{perhaps you meant to call this function}} } + +int i; + +namespace C { + int i; +} + +void test2(X *xp) { + xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}} + xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}} +} diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp index 0284b29..13777da 100644 --- a/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/test/SemaCXX/overloaded-builtin-operators.cpp @@ -150,3 +150,28 @@ void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr, void test_assign_restrictions(ShortRef& sr) { sr = (short)0; // expected-error{{no viable overloaded '='}} } + +struct Base { }; +struct Derived1 : Base { }; +struct Derived2 : Base { }; + +template<typename T> +struct ConvertibleToPtrOf { + operator T*(); +}; + +bool test_with_base_ptrs(ConvertibleToPtrOf<Derived1> d1, + ConvertibleToPtrOf<Derived2> d2) { + return d1 == d2; // expected-error{{invalid operands}} +} + +// DR425 +struct A { + template< typename T > operator T() const; +}; + +void test_dr425(A a) { + // FIXME: lots of candidates here! + (void)(1.0f * a); // expected-error{{ambiguous}} \ + // expected-note 81{{candidate}} +} diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 8f71ad5..10b0f5a 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/test/SemaCXX/overloaded-operator.cpp @@ -155,7 +155,7 @@ typedef INTREF Func1(FLOAT, double); typedef float& Func2(int, double); struct ConvertToFunc { - operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(float, double)'}} + operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(FLOAT, double)'}} operator Func2&(); // expected-note{{conversion candidate of type 'float &(&)(int, double)'}} void operator()(); }; diff --git a/test/SemaCXX/ptrtomember-overload-resolution.cpp b/test/SemaCXX/ptrtomember-overload-resolution.cpp new file mode 100644 index 0000000..b3b65ce --- /dev/null +++ b/test/SemaCXX/ptrtomember-overload-resolution.cpp @@ -0,0 +1,44 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x + +// 13.3.3.2 Ranking implicit conversion sequences +// conversion of A::* to B::* is better than conversion of A::* to C::*, +struct A { +int Ai; +}; + +struct B : public A {}; +struct C : public B {}; + +const char * f(int C::*){ return ""; } +int f(int B::*) { return 1; } + +struct D : public C {}; + +const char * g(int B::*){ return ""; } +int g(int D::*) { return 1; } + +void test() +{ + int i = f(&A::Ai); + + const char * str = g(&A::Ai); +} + +// conversion of B::* to C::* is better than conversion of A::* to C::* +typedef void (A::*pmfa)(); +typedef void (B::*pmfb)(); +typedef void (C::*pmfc)(); + +struct X { + operator pmfa(); + operator pmfb(); +}; + + +void g(pmfc); + +void test2(X x) +{ + g(x); +} + diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index 8db8e33..d816c05 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -133,3 +133,14 @@ void t_529_9() (void)static_cast<int A::*>((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}} (void)static_cast<int A::*>((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}} } + +// PR 5261 - static_cast should instantiate template if possible +namespace pr5261 { + struct base {}; + template<typename E> struct derived : public base {}; + template<typename E> struct outer { + base *pb; + ~outer() { (void)static_cast<derived<E>*>(pb); } + }; + outer<int> EntryList; +} diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp new file mode 100644 index 0000000..b22adb7 --- /dev/null +++ b/test/SemaCXX/switch.cpp @@ -0,0 +1,15 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +void test() { + bool x = true; + switch (x) { // expected-warning {{bool}} + case 0: + break; + } + + int n = 3; + switch (n && 1) { // expected-warning {{bool}} + case 1: + break; + } +} diff --git a/test/SemaObjC/objc-string-constant.m b/test/SemaObjC/objc-string-constant.m index 9823922..d27a46a 100644 --- a/test/SemaObjC/objc-string-constant.m +++ b/test/SemaObjC/objc-string-constant.m @@ -29,7 +29,7 @@ @end @implementation Subclass -- (NSString *)token; +- (NSString *)token; // expected-warning {{semicolon before method body is ignored}} { NSMutableString *result = nil; diff --git a/test/SemaObjC/try-catch.m b/test/SemaObjC/try-catch.m index 076eff5..453d80f 100644 --- a/test/SemaObjC/try-catch.m +++ b/test/SemaObjC/try-catch.m @@ -30,7 +30,7 @@ typedef struct _NSZone NSZone; @end @implementation XCRefactoringTransformation -- (NSDictionary *)setUpInfoForTransformKey:(NSString *)transformKey outError:(NSError **)outError; { +- (NSDictionary *)setUpInfoForTransformKey:(NSString *)transformKey outError:(NSError **)outError { @try {} // the exception name is optional (weird) @catch (NSException *) {} diff --git a/test/SemaTemplate/extern-templates.cpp b/test/SemaTemplate/extern-templates.cpp index 28fda1a..44728d1 100644 --- a/test/SemaTemplate/extern-templates.cpp +++ b/test/SemaTemplate/extern-templates.cpp @@ -29,16 +29,14 @@ void test_intptr(X0<int*> xi, X0<int*>::Inner xii) { xii.g(0); } -// FIXME: we would like the notes to point to the explicit instantiation at the -// bottom. -extern template class X0<long*>; // expected-note 2{{instantiation}} +extern template class X0<long*>; void test_longptr(X0<long*> xl, X0<long*>::Inner xli) { xl.f(0); xli.g(0); } -template class X0<long*>; +template class X0<long*>; // expected-note 2{{instantiation}} template<typename T> class X1 { diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp index dee4250..4d8aaa8 100644 --- a/test/SemaTemplate/fun-template-def.cpp +++ b/test/SemaTemplate/fun-template-def.cpp @@ -35,7 +35,7 @@ T f1(T t1, U u1, int i1) dynamic_cast<U>(const_cast<T>(i1))))); new U(i1, t1); - new int(t1, u1); // expected-error {{initializer of a builtin type can only take one argument}} + new int(t1, u1); new (t1, u1) int; delete t1; diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index 146e63c..194593a 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -178,3 +178,18 @@ namespace N10 { template class A<int>; } + +namespace N12 { + // PR5224 + template<typename T> + struct A { typedef int t0; }; + + struct C { + C(int); + + template<typename T> + static C *f0(T a0) {return new C((typename A<T>::t0) 1); } + }; + + void f0(int **a) { C::f0(a); } +} diff --git a/test/SemaTemplate/member-access-expr.cpp b/test/SemaTemplate/member-access-expr.cpp index f4922e8..0a6a6bc 100644 --- a/test/SemaTemplate/member-access-expr.cpp +++ b/test/SemaTemplate/member-access-expr.cpp @@ -74,4 +74,17 @@ void test_destruct(X2 *x2p, int *ip) { destruct(x2p); destruct(ip); destruct_intptr<int>(ip); -}
\ No newline at end of file +} + +// PR5220 +class X3 { +protected: + template <int> float* &f0(); + template <int> const float* &f0() const; + void f1() { + (void)static_cast<float*>(f0<0>()); + } + void f1() const{ + (void)f0<0>(); + } +}; diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index 20437ae..0f9f21f 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -24,7 +24,29 @@ struct XDerived : public X { }; void test_f1(XDerived xd) { - // FIXME: Not quite functional yet. -// int &ir = f1<X>(xd); + int &ir = f1<X>(xd); } +// PR5213 +template <class T> +struct A {}; + +template<class T> +class B +{ + A<T> a_; + +public: + void destroy(); +}; + +template<class T> +void +B<T>::destroy() +{ + a_.~A<T>(); +} + +void do_destroy_B(B<int> b) { + b.destroy(); +} diff --git a/test/SemaTemplate/variadic-class-template-2.cpp b/test/SemaTemplate/variadic-class-template-2.cpp index eadea90..b1ac71b 100644 --- a/test/SemaTemplate/variadic-class-template-2.cpp +++ b/test/SemaTemplate/variadic-class-template-2.cpp @@ -14,6 +14,6 @@ template struct TS2<int, int>; template <typename = int, typename ...> struct TS3 {}; // expected-note{{template parameter is declared here}} template struct TS3<>; // expected-note{{previous explicit instantiation is here}} -template struct TS3<int>; // expected-error{{duplicate explicit instantiation of 'TS3<>'}} +template struct TS3<int>; // expected-error{{duplicate explicit instantiation of 'TS3}} template struct TS3<int, int>; template struct TS3<10>; // expected-error{{template argument for template type parameter must be a type}} diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 9204d18..64dfcfe 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -22,12 +22,27 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/ASTUnit.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +#include "llvm/Support/raw_ostream.h" + #include <cstdio> +#include <vector> + +#ifdef LLVM_ON_WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#else +#include <dlfcn.h> +#endif + using namespace clang; using namespace idx; namespace { - static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) { NamedDecl *D = DRE->getDecl(); @@ -76,6 +91,14 @@ public: } }; #endif + +/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted +/// warnings and errors. +class VISIBILITY_HIDDEN IgnoreDiagnosticsClient : public DiagnosticClient { +public: + virtual ~IgnoreDiagnosticsClient() {} + virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {} +}; // Translation Unit Visitor. class TUVisitor : public DeclVisitor<TUVisitor> { @@ -83,14 +106,24 @@ class TUVisitor : public DeclVisitor<TUVisitor> { CXTranslationUnitIterator Callback; CXClientData CData; + // MaxPCHLevel - the maximum PCH level of declarations that we will pass on + // to the visitor. Declarations with a PCH level greater than this value will + // be suppressed. + unsigned MaxPCHLevel; + void Call(enum CXCursorKind CK, NamedDecl *ND) { + // Filter any declarations that have a PCH level greater than what we allow. + if (ND->getPCHLevel() > MaxPCHLevel) + return; + CXCursor C = { CK, ND, 0 }; Callback(TUnit, C, CData); } public: TUVisitor(CXTranslationUnit CTU, - CXTranslationUnitIterator cback, CXClientData D) : - TUnit(CTU), Callback(cback), CData(D) {} + CXTranslationUnitIterator cback, CXClientData D, + unsigned MaxPCHLevel) : + TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} void VisitTranslationUnitDecl(TranslationUnitDecl *D) { VisitDeclContext(dyn_cast<DeclContext>(D)); @@ -149,16 +182,27 @@ class CDeclVisitor : public DeclVisitor<CDeclVisitor> { CXDeclIterator Callback; CXClientData CData; + // MaxPCHLevel - the maximum PCH level of declarations that we will pass on + // to the visitor. Declarations with a PCH level greater than this value will + // be suppressed. + unsigned MaxPCHLevel; + void Call(enum CXCursorKind CK, NamedDecl *ND) { // Disable the callback when the context is equal to the visiting decl. if (CDecl == ND && !clang_isReference(CK)) return; + + // Filter any declarations that have a PCH level greater than what we allow. + if (ND->getPCHLevel() > MaxPCHLevel) + return; + CXCursor C = { CK, ND, 0 }; Callback(CDecl, C, CData); } public: - CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) : - CDecl(C), Callback(cback), CData(D) {} + CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D, + unsigned MaxPCHLevel) : + CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { // Issue callbacks for the containing class. @@ -237,20 +281,87 @@ public: } }; +class CIndexer : public Indexer { +public: + explicit CIndexer(Program *prog) : Indexer(*prog), + OnlyLocalDecls(false), + DisplayDiagnostics(false) {} + + virtual ~CIndexer() { delete &getProgram(); } + + /// \brief Whether we only want to see "local" declarations (that did not + /// come from a previous precompiled header). If false, we want to see all + /// declarations. + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } + + void setDisplayDiagnostics(bool Display = true) { + DisplayDiagnostics = Display; + } + bool getDisplayDiagnostics() const { return DisplayDiagnostics; } + + /// \brief Get the path of the clang binary. + const llvm::sys::Path& getClangPath(); +private: + bool OnlyLocalDecls; + bool DisplayDiagnostics; + + llvm::sys::Path ClangPath; +}; + +const llvm::sys::Path& CIndexer::getClangPath() { + // Did we already compute the path? + if (!ClangPath.empty()) + return ClangPath; + + // Find the location where this library lives (libCIndex.dylib). +#ifdef LLVM_ON_WIN32 + MEMORY_BASIC_INFORMATION mbi; + char path[MAX_PATH]; + VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi, + sizeof(mbi)); + GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); + + llvm::sys::Path CIndexPath(path); +#else + // This silly cast below avoids a C++ warning. + Dl_info info; + if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) + assert(0 && "Call to dladdr() failed"); + + llvm::sys::Path CIndexPath(info.dli_fname); +#endif + + // We now have the CIndex directory, locate clang relative to it. + CIndexPath.eraseComponent(); + CIndexPath.eraseComponent(); + CIndexPath.appendComponent("bin"); + CIndexPath.appendComponent("clang"); + + // Cache our result. + ClangPath = CIndexPath; + return ClangPath; +} + } extern "C" { -CXIndex clang_createIndex() -{ - // FIXME: Program is leaked. - return new Indexer(*new Program()); +CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics) +{ + CIndexer *CIdxr = new CIndexer(new Program()); + if (excludeDeclarationsFromPCH) + CIdxr->setOnlyLocalDecls(); + if (displayDiagnostics) + CIdxr->setDisplayDiagnostics(); + return CIdxr; } void clang_disposeIndex(CXIndex CIdx) { assert(CIdx && "Passed null CXIndex"); - delete static_cast<Indexer *>(CIdx); + delete static_cast<CIndexer *>(CIdx); } // FIXME: need to pass back error info. @@ -258,12 +369,102 @@ CXTranslationUnit clang_createTranslationUnit( CXIndex CIdx, const char *ast_filename) { assert(CIdx && "Passed null CXIndex"); - Indexer *CXXIdx = static_cast<Indexer *>(CIdx); + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); std::string astName(ast_filename); std::string ErrMsg; - return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(), - CXXIdx->getFileManager(), &ErrMsg); + CXTranslationUnit TU = + ASTUnit::LoadFromPCHFile(astName, &ErrMsg, + CXXIdx->getDisplayDiagnostics() ? + NULL : new IgnoreDiagnosticsClient(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true); + + if (!ErrMsg.empty()) { + (llvm::errs() << "clang_createTranslationUnit: " << ErrMsg + << '\n').flush(); + } + + return TU; +} + +CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, + const char *source_filename, + int num_command_line_args, const char **command_line_args) { + assert(CIdx && "Passed null CXIndex"); + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + + // Build up the arguments for invoking 'clang'. + std::vector<const char *> argv; + + // First add the complete path to the 'clang' executable. + llvm::sys::Path ClangPath = static_cast<CIndexer *>(CIdx)->getClangPath(); + argv.push_back(ClangPath.c_str()); + + // Add the '-emit-ast' option as our execution mode for 'clang'. + argv.push_back("-emit-ast"); + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + if (source_filename) + argv.push_back(source_filename); + + // Generate a temporary name for the AST file. + argv.push_back("-o"); + char astTmpFile[L_tmpnam]; + argv.push_back(tmpnam(astTmpFile)); + + // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. + for (int i = 0; i < num_command_line_args; ++i) + if (const char *arg = command_line_args[i]) { + if (strcmp(arg, "-o") == 0) { + ++i; // Also skip the matching argument. + continue; + } + if (strcmp(arg, "-emit-ast") == 0 || + strcmp(arg, "-c") == 0 || + strcmp(arg, "-fsyntax-only") == 0) { + continue; + } + + // Keep the argument. + argv.push_back(arg); + } + + // Add the null terminator. + argv.push_back(NULL); + +#ifndef LLVM_ON_WIN32 + llvm::sys::Path DevNull("/dev/null"); + std::string ErrMsg; + const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL }; + llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, + /* redirects */ !CXXIdx->getDisplayDiagnostics() ? &Redirects[0] : NULL, + /* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg); + + if (!ErrMsg.empty()) { + llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg + << '\n' << "Arguments: \n"; + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I!=E; ++I) + if (*I) llvm::errs() << ' ' << *I << '\n'; + + (llvm::errs() << '\n').flush(); + } +#else + // FIXME: I don't know what is the equivalent '/dev/null' redirect for + // Windows for this API. + llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0]); +#endif + + // Finally, we create the translation unit from the ast file. + ASTUnit *ATU = static_cast<ASTUnit *>( + clang_createTranslationUnit(CIdx, astTmpFile)); + if (ATU) + ATU->unlinkTemporaryFile(); + return ATU; } void clang_disposeTranslationUnit( @@ -272,7 +473,7 @@ void clang_disposeTranslationUnit( assert(CTUnit && "Passed null CXTranslationUnit"); delete static_cast<ASTUnit *>(CTUnit); } - + const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { assert(CTUnit && "Passed null CXTranslationUnit"); @@ -288,7 +489,8 @@ void clang_loadTranslationUnit(CXTranslationUnit CTUnit, ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); ASTContext &Ctx = CXXUnit->getASTContext(); - TUVisitor DVisit(CTUnit, callback, CData); + TUVisitor DVisit(CTUnit, callback, CData, + CXXUnit->getOnlyLocalDecls()? 1 : Decl::MaxPCHLevel); DVisit.Visit(Ctx.getTranslationUnitDecl()); } @@ -298,7 +500,8 @@ void clang_loadDeclaration(CXDecl Dcl, { assert(Dcl && "Passed null CXDecl"); - CDeclVisitor DVisit(Dcl, callback, CData); + CDeclVisitor DVisit(Dcl, callback, CData, + static_cast<Decl *>(Dcl)->getPCHLevel()); DVisit.Visit(static_cast<Decl *>(Dcl)); } @@ -349,7 +552,7 @@ const char *clang_getDeclSpelling(CXDecl AnonDecl) return OMD->getSelector().getAsString().c_str(); } if (ND->getIdentifier()) - return ND->getIdentifier()->getName(); + return ND->getIdentifier()->getNameStart(); else return ""; } @@ -385,43 +588,38 @@ const char *clang_getCursorSpelling(CXCursor C) if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: - { + case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); assert(OID && "clang_getCursorLine(): Missing interface decl"); - return OID->getSuperClass()->getIdentifier()->getName(); - } - case CXCursor_ObjCClassRef: - { + return OID->getSuperClass()->getIdentifier()->getNameStart(); + } + case CXCursor_ObjCClassRef: { if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) { - return OID->getIdentifier()->getName(); + return OID->getIdentifier()->getNameStart(); } ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); assert(OID && "clang_getCursorLine(): Missing category decl"); - return OID->getClassInterface()->getIdentifier()->getName(); - } - case CXCursor_ObjCProtocolRef: - { + return OID->getClassInterface()->getIdentifier()->getNameStart(); + } + case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); assert(OID && "clang_getCursorLine(): Missing protocol decl"); - return OID->getIdentifier()->getName(); - } - case CXCursor_ObjCSelectorRef: - { + return OID->getIdentifier()->getNameStart(); + } + case CXCursor_ObjCSelectorRef: { ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( static_cast<Stmt *>(C.stmt)); assert(OME && "clang_getCursorLine(): Missing message expr"); return OME->getSelector().getAsString().c_str(); - } + } case CXCursor_VarRef: case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: - { + case CXCursor_EnumConstantRef: { DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( static_cast<Stmt *>(C.stmt)); assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return DRE->getDecl()->getIdentifier()->getName(); - } + return DRE->getDecl()->getIdentifier()->getNameStart(); + } default: return "<not implemented>"; } @@ -497,12 +695,26 @@ static enum CXCursorKind TranslateKind(Decl *D) { // // CXCursor Operations. // +void clang_initCXLookupHint(CXLookupHint *hint) { + memset(hint, 0, sizeof(*hint)); +} + CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, - unsigned line, unsigned column) + unsigned line, unsigned column) { + return clang_getCursorWithHint(CTUnit, source_name, line, column, NULL); +} + +CXCursor clang_getCursorWithHint(CXTranslationUnit CTUnit, + const char *source_name, + unsigned line, unsigned column, + CXLookupHint *hint) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); + // FIXME: Make this better. + CXDecl RelativeToDecl = hint ? hint->decl : NULL; + FileManager &FMgr = CXXUnit->getFileManager(); const FileEntry *File = FMgr.getFile(source_name, source_name+strlen(source_name)); @@ -513,7 +725,8 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, SourceLocation SLoc = CXXUnit->getSourceManager().getLocation(File, line, column); - ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc); + ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc, + static_cast<NamedDecl *>(RelativeToDecl)); Decl *Dcl = ALoc.getParentDecl(); if (ALoc.isNamedRef()) @@ -623,8 +836,7 @@ static SourceLocation getLocationFromCursor(CXCursor C, NamedDecl *ND) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCClassRef: - { + case CXCursor_ObjCClassRef: { if (isa<ObjCInterfaceDecl>(ND)) { // FIXME: This is a hack (storing the parent decl in the stmt slot). NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt); @@ -633,56 +845,49 @@ static SourceLocation getLocationFromCursor(CXCursor C, ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); assert(OID && "clang_getCursorLine(): Missing category decl"); return OID->getClassInterface()->getLocation(); - } - case CXCursor_ObjCSuperClassRef: - { + } + case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); assert(OID && "clang_getCursorLine(): Missing interface decl"); return OID->getSuperClassLoc(); - } - case CXCursor_ObjCProtocolRef: - { + } + case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); assert(OID && "clang_getCursorLine(): Missing protocol decl"); return OID->getLocation(); - } - case CXCursor_ObjCSelectorRef: - { + } + case CXCursor_ObjCSelectorRef: { ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( static_cast<Stmt *>(C.stmt)); assert(OME && "clang_getCursorLine(): Missing message expr"); return OME->getLeftLoc(); /* FIXME: should be a range */ - } + } case CXCursor_VarRef: case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: - { + case CXCursor_EnumConstantRef: { DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( static_cast<Stmt *>(C.stmt)); assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); return DRE->getLocation(); - } + } default: return SourceLocation(); } } else { // We have a declaration or a definition. SourceLocation SLoc; switch (ND->getKind()) { - case Decl::ObjCInterface: - { + case Decl::ObjCInterface: { SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc(); break; - } - case Decl::ObjCProtocol: - { + } + case Decl::ObjCProtocol: { SLoc = ND->getLocation(); /* FIXME: need to get the name location. */ break; - } - default: - { + } + default: { SLoc = ND->getLocation(); break; - } + } } if (SLoc.isInvalid()) return SourceLocation(); @@ -716,7 +921,18 @@ const char *clang_getCursorSource(CXCursor C) SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - return SourceMgr.getBufferName(SLoc); + if (SLoc.isFileID()) + return SourceMgr.getBufferName(SLoc); + + // Retrieve the file in which the macro was instantiated, then provide that + // buffer name. + // FIXME: Do we want to give specific macro-instantiation information? + const llvm::MemoryBuffer *Buffer + = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first); + if (!Buffer) + return 0; + + return Buffer->getBufferIdentifier(); } void clang_getDefinitionSpellingAndExtent(CXCursor C, diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index c1ca0c7..e9d44a0 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -7,6 +7,7 @@ _clang_getCursorFromDecl _clang_getCursorKind _clang_getCursorLine _clang_getCursorSource +_clang_getCursorWithHint _clang_getDeclarationName _clang_getDeclSpelling _clang_getDeclLine @@ -18,7 +19,9 @@ _clang_getURI _clang_loadDeclaration _clang_loadTranslationUnit _clang_createTranslationUnit +_clang_createTranslationUnitFromSourceFile _clang_disposeTranslationUnit +_clang_initCXLookupHint _clang_isDeclaration _clang_isReference _clang_isDefinition diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index 71bbde5..ee77c03 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -22,6 +22,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") ) endif() +if(MSVC) + # windows.h doesn't compile with /Za + get_target_property(NON_ANSI_COMPILE_FLAGS CIndex COMPILE_FLAGS) + string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) + set_target_properties(CIndex PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) +endif(MSVC) + set_target_properties(CIndex PROPERTIES LINKER_LANGUAGE CXX) diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index c514b63..cf2a706 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -53,17 +53,23 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, unsigned curLine = startLine, curColumn = startColumn; CXCursor Ref; - while (startBuf <= endBuf) { + while (startBuf < endBuf) { + CXLookupHint hint; if (*startBuf == '\n') { startBuf++; curLine++; curColumn = 1; } else if (*startBuf != '\t') curColumn++; + + clang_initCXLookupHint(&hint); + hint.decl = Cursor.decl; - Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor), - curLine, curColumn); - if (Ref.kind != CXCursor_FunctionDecl) { + Ref = clang_getCursorWithHint(Unit, clang_getCursorSource(Cursor), + curLine, curColumn, &hint); + if (Ref.kind == CXCursor_NoDeclFound) { + /* Nothing found here; that's fine. */ + } else if (Ref.kind != CXCursor_FunctionDecl) { printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Ref)), curLine, curColumn); PrintCursor(Ref); @@ -85,12 +91,23 @@ int main(int argc, char **argv) { return 0; } { - CXIndex Idx = clang_createIndex(); - CXTranslationUnit TU = clang_createTranslationUnit(Idx, argv[1]); + CXIndex Idx; + CXTranslationUnit TU; enum CXCursorKind K = CXCursor_NotImplemented; + + Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(argv[2], "local") ? 1 : 0, + /* displayDiagnostics */ 1); + + TU = clang_createTranslationUnit(Idx, argv[1]); - if (!strcmp(argv[2], "all")) { + if (!TU) { + fprintf(stderr, "Unable to load translation unit!\n"); + return 1; + } + + if (!strcmp(argv[2], "all") || !strcmp(argv[2], "local")) { clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); + clang_disposeTranslationUnit(TU); return 1; } /* Perform some simple filtering. */ @@ -101,6 +118,7 @@ int main(int argc, char **argv) { else if (!strcmp(argv[2], "typedef")) K = CXCursor_TypedefDecl; clang_loadTranslationUnit(TU, TranslationUnitVisitor, &K); + clang_disposeTranslationUnit(TU); return 1; } } diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 0ad7efb..f77767c 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -1139,9 +1139,6 @@ isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"), // Add the clang headers, which are relative to the clang binary. void AddClangIncludePaths(const char *Argv0, InitHeaderSearch *Init) { - if (nostdclanginc) - return; - llvm::sys::Path MainExecutablePath = llvm::sys::Path::GetMainExecutable(Argv0, (void*)(intptr_t)AddClangIncludePaths); @@ -1243,7 +1240,8 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers, Init.AddDefaultEnvVarPaths(Lang); - AddClangIncludePaths(Argv0, &Init); + if (!nostdclanginc) + AddClangIncludePaths(Argv0, &Init); if (!nostdinc) Init.AddDefaultSystemIncludePaths(Lang, triple); @@ -2190,8 +2188,7 @@ static void ProcessASTInputFile(const std::string &InFile, ProgActions PA, Diagnostic &Diags, FileManager &FileMgr, llvm::LLVMContext& Context) { std::string Error; - llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr, - &Error)); + llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, &Error)); if (!AST) { Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_file) << Error; return; diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp index 103874c..fce48ed 100644 --- a/tools/index-test/index-test.cpp +++ b/tools/index-test/index-test.cpp @@ -225,8 +225,7 @@ int main(int argc, char **argv) { std::string ErrMsg; llvm::OwningPtr<ASTUnit> AST; - AST.reset(ASTUnit::LoadFromPCHFile(InFile, Idxer.getDiagnostics(), - Idxer.getFileManager(), &ErrMsg)); + AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg)); if (!AST) { llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n'; return 1; @@ -244,7 +243,7 @@ int main(int argc, char **argv) { if (!PointAtLocation.empty()) { const std::string &Filename = PointAtLocation[0].FileName; - const FileEntry *File = Idxer.getFileManager().getFile(Filename); + const FileEntry *File = FirstAST->getFileManager().getFile(Filename); if (File == 0) { llvm::errs() << "File '" << Filename << "' does not exist\n"; return 1; @@ -253,7 +252,7 @@ int main(int argc, char **argv) { // Safety check. Using an out-of-date AST file will only lead to crashes // or incorrect results. // FIXME: Check all the source files that make up the AST file. - const FileEntry *ASTFile = Idxer.getFileManager().getFile(FirstFile); + const FileEntry *ASTFile = FirstAST->getFileManager().getFile(FirstFile); if (File->getModificationTime() > ASTFile->getModificationTime()) { llvm::errs() << "[" << FirstFile << "] Error: " << "Pointing at a source file which was modified after creating " diff --git a/www/OpenProjects.html b/www/OpenProjects.html index cdf3121..46d9716 100644 --- a/www/OpenProjects.html +++ b/www/OpenProjects.html @@ -97,6 +97,18 @@ supported.</li> that demonstrates the problem down to something small. There are many ways to do this; ask on cfe-dev for advice.</p> +<li><b>StringRef'ize APIs</b>: A thankless but incredibly useful project is +StringRef'izing (converting to use <tt>llvm::StringRef</tt> instead of <tt>const +char *</tt> or <tt>std::string</tt>) various clang interfaces. This generally +simplifies the code and makes it more efficient.</li> + +<li><b>Universal Driver</b>: Clang is inherently a cross compiler. We would like +to define a new model for cross compilation which provides a great user +experience -- it should be easy to cross compile applications, install support +for new architectures, access different compilers and tools, and be consistent +across different platforms. See the <a href="UniversalDriver.html">Universal +Driver</a> web page for more information.</li> + </div> </body> </html> diff --git a/www/UniversalDriver.html b/www/UniversalDriver.html new file mode 100644 index 0000000..f66151a --- /dev/null +++ b/www/UniversalDriver.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> + <title>Clang - Universal Driver</title> + <link type="text/css" rel="stylesheet" href="menu.css" /> + <link type="text/css" rel="stylesheet" href="content.css" /> +</head> +<body> + +<!--#include virtual="menu.html.incl"--> + +<div id="content"> + +<h1>The Clang Universal Driver Project</h1> + +<p>Clang is inherently a cross compiler, in that it is always capable of +building code for targets which are a different architecture or even operating +system from the one running the compiler. However, actually cross compiling in +practice involves much more than just generating the right assembly code for a +target, it also requires having an appropriate tool chain (assemblers, linkers), +access to header files and libraries for the target, and many other details (for +example, the calling convention or whether software floating point is in +use). Traditionally, compilers and development environments provide little +assistance with this process, so users do not have easy access to the powerful +underlying cross-compilation abilities of clang.</p> + +<p>We would like to solve this problem by defining a new model for how cross +compilation is done, based on the idea of a <i>universal driver</i>. The key +point of this model is that the user would always access the compiler through a +single entry point (e.g., <tt>/usr/bin/cc</tt>) and provide an argument +specifying the <i>configuration</i> they would like to target. Under the hood +this entry point (the universal driver) would have access to all the information +that the driver, compiler, and other tools need to build applications for that +target.</p> + +<p>This is a large and open-ended project. It's eventual success depends not +just on implementing the model, but also on getting buy-in from compiler +developers, operating system distribution vendors and the development community +at large. Our plan is to begin by defining a clear list of the problems we want +to solve and a proposed implementation (from the user perspective).</p> + +<p>This project is in the very early (i.e., thought experiment) stages of +development. Stay tuned for more information, and of course, patches +welcome!</p> + +<p>See also <a href="http://llvm.org/PR4127">PR4127</a>.</p> + +<h2>Existing Solutions and Related Work</h2> + +<ul> + <li>gcc's command line arguments <tt>-V</tt>, <tt>-B</tt>, <tt>-b</tt> are + generic but limited solutions to related problems. Similarly, <tt>-m32</tt> + and <tt>-m64</tt> solve a small subset of the problem for specific + architectures.</li> + + <li>gcc's <a href="http://www.airs.com/ian/configure/configure_8.html">multilibs</a> + solve the part of the problem that relates to finding appropriate libraries + and include files based on particular feature support (soft float, + etc.).</li> + + <li>Apple's "driver driver" supported by gcc and clang solve a subset of the + problem by supporting <tt>-arch</tt>. Apple also provides a tool chain which + supports <a href="http://en.wikipedia.org/wiki/Universal_binary">universal + binaries</a> and object files which may include data for multiple + architectures. See <a href="http://developer.apple.com/mac/library/technotes/tn2005/tn2137.html">TN2137</a> + for an example of how this is used.</li> + + <li>Many operating systems and environments solve the problem by installing + complete development environments (including the IDE, tools, header files, + and libraries) for a single tool chain. This is cumbersome for users and + does not match well with tools which are inherently capable of cross + compiling.</li> + + <li>The Debian <a href="http://wiki.debian.org/ArmEabiPort">ArmEabiPort</a> + wiki page for their work to support the ARM EABI provide an interesting + glimpse into how related issues impact the operating system distribution.</li> + +</ul> + +</div> +</body> +</html> diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl index fa287b1..4184ce6 100644 --- a/www/analyzer/latest_checker.html.incl +++ b/www/analyzer/latest_checker.html.incl @@ -1 +1 @@ -<b><a href="http://checker.minormatter.com/checker-224.tar.bz2">checker-224.tar.bz2</a></b> (built October 6, 2009) +<b><a href="http://checker.minormatter.com/checker-225.tar.bz2">checker-225.tar.bz2</a></b> (built October 21, 2009) diff --git a/www/comparison.html b/www/comparison.html index f0d00bb..2462b89 100644 --- a/www/comparison.html +++ b/www/comparison.html @@ -179,7 +179,8 @@ <ul> <li>PCC dates from the 1970's and has been dormant for most of that time. The clang + llvm communities are very active.</li> - <li>PCC doesn't support Objective-C or C++ and doesn't aim to</li> + <li>PCC doesn't support Objective-C or C++ and doesn't aim to support + C++.</li> <li>PCC's code generation is very limited compared to LLVM. It produces very inefficient code and does not support many important targets.</li> <li>Like Elsa, PCC's does not have an integrated preprocessor, making it diff --git a/www/cxx_status.html b/www/cxx_status.html index 2c1b79e..ecfc8a8 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -24,7 +24,7 @@ <!--*************************************************************************--> <h1>C++ Support in Clang</h1> <!--*************************************************************************--> -<p>Last updated: $Date: 2009-10-13 21:41:44 +0200 (Tue, 13 Oct 2009) $</p> +<p>Last updated: $Date: 2009-10-20 23:10:15 +0200 (Tue, 20 Oct 2009) $</p> <p> This page tracks the status of C++ support in Clang.<br> @@ -1659,9 +1659,8 @@ welcome!</p> <td> 13.3.3 [over.match.best]</td> <td class="na" align="center">N/A</td> <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> + <td class="advanced" align="center"></td> <td class="na" align="center">N/A</td> - <td>Missing support for member pointers</td> </tr> <tr> <td> 13.3.3.1 [over.best.ics]</td> @@ -1789,8 +1788,7 @@ welcome!</p> <td class="advanced" align="center"></td> <td class="medium" align="center"></td> <td class="na" align="center">N/A</td> - <td>Missing support for the ->* operator (p11, p16) and support for - the ternary operator (p24, p25).</td> + <td>Missing support for the ternary operator (p24, p25).</td> </tr> <tr> <td>14 [temp]</td> |